out vec3 finalData;


//------------Why are you here you nupid stigger, go back to BSL where you belong and get tf out of my shader :) --------------------------




// ============================================================
// ADVANCED DISTORTION & ROUNDING SETTINGS
// ============================================================
#define HORIZONTAL_EDGE_STRENGTH  0.15 // Сила искажения по горизонтальным краям [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]
#define VERTICAL_EDGE_STRENGTH    0.15 // Сила искажения по вертикальным краям [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]
#define CORNER_DISTORT_STRENGTH   0.25 // Сила затягивания углов экрана [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]
#define CIRCULAR_DISTORT_STRENGTH 0.10 // Сила центрального кругового искажения (бочка/рыбий глаз) [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]

#define IMAGE_ROUNDING_RADIUS     0.08 // Радиус скругления углов экрана (0.0 - квадрат, 0.5 - круг) [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]
#define IMAGE_VERTICAL_STRENGTH   1.0  // Масштаб маски по вертикали [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]
#define IMAGE_HORIZONTAL_STRENGTH 1.0  // Масштаб маски по горизонтали [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]
#define IMAGE_ROUND_STRENGTH      0.8  // Жесткость краев скругления (1.0 - жесткие, <1.0 - плавный градиент) [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0]
#define LENS_FLARE_STRENGTH 1.0


// ============================================================

#define ENABLE_CAMERA_SHAKE 0 // [0 1] 
// VHS
// ============================================================
#define VHS_STATIC_GLITCH_INTENSITY 0.3 // [0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]
#define VHS_LETTERBOX_ENABLED 1         // Включение рамок [0 1]
#define VHS_LETTERBOX_ORIENTATION 0     // Ориентация рамок: 0 - горизонтальные, 1 - вертикальные [0 1]

// ============================================================
// AXON OVERLAY НАСТРОЙКИ
// ============================================================
#define AXON_OVERLAY 0 // [0 1]
#define AXON_POSITION 1                 // 0 = LEFT TOP | 1 = RIGHT TOP [0 1]
#define AXON_IMG_W 0.05 // [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20]
#define AXON_IMG_H 0.08 // [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20]
#define AXON_IMG_MARGIN 0.02 // [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20]
#define AXON_TEXT_GAP 0.01 // [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20]
#define AXON_CHAR_W 0.01 // [0.0 0.10 0.16 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00]
#define AXON_CHAR_H 0.01 // [0.0 0.10 0.20 0.26 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00]
#define AXON_CHAR_SPACING 1.25 // [0.2 0.5 1.0 1.2 1.25 1.50 1.55 2.0 2.2 2.25 2.50 2.55 3.0]
#define AXON_TEXT_SHADOW 1 // [0 1]
#define AXON_SHADOW_STRENGTH 0.7 // [0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]
#define AXON_SHADOW_OFFSET 0.0015 // [0.0001 0.0002 0.0003 0.0004 0.0005 0.0006 0.000.7 0.0008 0.0009 0.0010 0.0011 0.0012 0.0013 0.0014 0.0015 0.0016 0.0017 0.0018 0.0019 0.0020 0.0021 0.0022 0.0023 0.0024]

// ============================================================
// INTRO ЗАСТАВКА
// ============================================================
#define DC_INTRO 0 // [0 1]
// DC_INTRO_STYLE:
//   1 = colortex21 (PNG)
//   2 = colortex22 (PNG)
//   3 = colortex23 (PNG)
//   4 = colortex24 (PNG)
//   5 = green console (splash style 0)
//   6 = vhs + white (splash style 1)
//   7 = anim console (splash style 2)
//   8 = anim vhs(splash style 3)
#define DC_INTRO_STYLE 1               // [1 2 3 4 5 6 7 8]
#define DC_INTRO_IN   0.6 // [0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]
#define DC_INTRO_HOLD 3.0 // [0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.2 2.4 2.6 2.8 3.0]
#define DC_INTRO_OUT  0.5 // [0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]
#define DC_INTRO_W 0.40 // [0.0 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00]
#define DC_INTRO_H 0.30 // [0.0 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00]

// Шрифт для процедурных стилей 5–8 (те же опции что у SPLASH_FONT_STYLE)
//   0 = SDF гладкий   1 = пиксельный 5x7   2 = терминальный тонкий
//   3 = жирный блочный   4 = курсивный наклонный
#define DC_INTRO_FONT_STYLE 0           // [0 1 2 3 4]

// ============================================================
// BODYCAM MISC
// ============================================================
#define BODYCAMMISC_ENABLED 0
#define DYNAMIC_VIGNETTE 1
#define DYNAMIC_VIGNETTE_STRENGTH 0.3
#define CRT_CURVE 0.05
#define BLOOM_ENABLED 1
#define BLOOM_STRENGTH 0.1
#define DYNAMIC_NOISE 1
#define DYNAMIC_NOISE_STRENGTH 0.02
#define EDGE_DISTORTION_ENABLED 1
#define CUBIC_VIGNETTE_ENABLED 1
#define CUBIC_VIGNETTE_STRENGTH 0.5
#define PS1_STYLE_ENABLED 1
#define PS1_STYLE_INTENSITY 0.5
#define VHS_CHROMATIC_ABERRATION 0.002

// ============================================================
// DIRTY LENS
// ============================================================
#define DIRTY_LENS_INTENSITY 0.8
#define DIRTY_LENS_BLOOM_MIX 0.06
#define DIRTY_LENS_TINT_R 1.0
#define DIRTY_LENS_TINT_G 0.97
#define DIRTY_LENS_TINT_B 0.92
#define PROC_DIRT_LAYERS 5
#define PROC_DIRT_SCALE_BASE 2.0
#define PROC_DIRT_SCALE_MUL 1.35
#define PROC_DIRT_SMOOTH_IN 0.1
#define PROC_DIRT_SMOOTH_OUT 0.3
#define PROC_DIRT_EDGE_BOOST 0.5
#define PROC_DIRT_ASPECT_CORRECT 1
#define RAINCORE_WATER_EXIT_ENABLED 1
#define DYNAMIC_VIGNETTE_SWAY 1
#define DYNAMIC_VIGNETTE_TILT 0.8

#ifndef SHARPNESS_STRENGTH
#define SHARPNESS_STRENGTH 0.5
#endif
#ifndef SCANLINE
#define SCANLINE 1
#endif
#ifndef GRAIN
#define GRAIN 0
#endif
#ifndef GRAIN_STRENGTH
#define GRAIN_STRENGTH 0.05
#endif
#ifndef COLOR_DIST
#define COLOR_DIST 0
#endif
#ifndef COLOR_DIST_STRENGTH
#define COLOR_DIST_STRENGTH 0.02
#endif
#ifndef ENABLE_NVG_IsSneaking
#define ENABLE_NVG_IsSneaking 0
#endif
#ifndef R
#define R 0.0
#endif
#ifndef G
#define G 1.0
#endif
#ifndef B
#define B 0.0
#endif
#ifndef degree_brightness_increase
#define degree_brightness_increase 1.5
#endif
#ifndef FISHEYE_CENTER_STRENGTH
#define FISHEYE_CENTER_STRENGTH 0.5
#endif

// ============================================================
// TAA / DLSS-LIKE
// ============================================================
#define TAA_ENABLED 1
#define TAA_BLEND_FACTOR 0.1
#define TAA_MAX_BLEND 0.95
#define TAA_CLAMP_ENABLED 1
#define TAA_CLAMP_GAMMA 1.0
#define TAA_CLAMP_MARGIN 0.1
#define TAA_VARIANCE_CLIP 1
#define TAA_VARIANCE_GAMMA 1.25
#define TAA_VELOCITY_ENABLED 1
#define TAA_VELOCITY_WEIGHT 1.0
#define TAA_VELOCITY_FALLBACK 1
#define TAA_SHARPENING 1
#define TAA_SHARPNESS 0.4
#define TAA_SHARPNESS_STYLE 1
#define TAA_SAMPLE_CATMULL_ROM 1
#define TAA_NEIGHBOR_SAMPLES 5
#define TAA_LUMA_WEIGHT 1
#define TAA_LUMA_EXPOSURE_CORRECT 1
#define DLSS_LIKE_ENABLED 1
#define DLSS_QUALITY 0
#define DLSS_DISTANCE_START 20.0
#define DLSS_DISTANCE_END 80.0
#define DLSS_SHARPNESS 0.7
#define DLSS_TEMPORAL_STRENGTH 0.85
#define DLSS_EDGE_SHARPEN 0
#define DLSS_EDGE_THRESHOLD 0.05
#define DLSS_DEBUG_DISTANCE 0
#define TAA_JITTER_ENABLED 0
#define TAA_JITTER_STRENGTH 0.5
#define RES_SCALE_PERCENT 200
#define RES_SCALE_UPSAMPLE_SHARP 0.6
#define RES_SCALE_F (float(RES_SCALE_PERCENT) / 100.0)

// ============================================================
// GAMEPLAY EFFECTS
// ============================================================
#define LOW_HEALTH_EFFECT
#define DAMAGE_TAKEN_EFFECT
#define MOTION_AMOUNT 1.0
#define WATER_ON_CAMERA_EFFECT
#define ON_FIRE_DISTORT_EFFECT
#define ON_FIRE_DISTORT_EFFECT_STRENGTH 0.3
 #define DROWNING_EFFECT

// ============================================================
// LENS WATER SYSTEM
// ============================================================
#define LENS_WATER 1

// --- Дождь (капли) ---
#define RAIN_DROP_COUNT_X  0
#define RAIN_DROP_COUNT_Y  0
#define RAIN_DROP_SPEED    0.35
#define RAIN_DROP_REFRACT  0.26
#define RAIN_STATIC_CHANCE 0.0
#define RAIN_TRAIL_REFRACT 0.125
#define DROP_W 0.16
#define DROP_H 10.28
#define DROP_ROUND_TL 0.8
#define DROP_ROUND_TR 0.8
#define DROP_ROUND_BL 0.85
#define DROP_ROUND_BR 0.85
#define DROP_EDGE_FADE 0.35
#define DROP_ANIM_PERIOD 14.0

// --- Вода после выхода из воды ---
#define WATER_EXIT_DURATION  2.5
#define WATER_EXIT_REFRACT   0.08
#define WATER_EXIT_STREAMS   5

// ============================================================
// RAIN STREAKS
// ============================================================
#define RAIN_STREAKS_ENABLED      1       // [0 1]
#define RAIN_STREAKS_COUNT        6       // [1 2 3 4 5 6 8 10 12]
#define RAIN_STREAKS_ZIG_COUNT    8       // [0 1 2 3 4 5 6 8]

// Позиция зиг-потоков по горизонтали: 0.0=лево, 0.5=центр, 1.0=право
#define RAIN_STREAK_ZIG_OFFSET_X  0.95    // [0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0]
// Разброс зиг-потоков вокруг RAIN_STREAK_ZIG_OFFSET_X (в UV единицах)
#define RAIN_STREAK_ZIG_SPREAD    0.18   // [0.05 0.10 0.15 0.18 0.20 0.25 0.30 0.40 0.50]

#define RAIN_STREAK_WIDTH         0.088   // [0.004 0.006 0.008 0.010 0.012 0.016 0.018 0.022 0.028 0.036]
#define RAIN_STREAK_LENGTH        1.10    // [0.2 0.3 0.4 0.5 0.6 0.75 0.80 0.90 1.0]
#define RAIN_STREAK_EDGE_SOFT     1.85    // [0.1 0.2 0.3 0.4 0.5 0.55 0.6 0.7 0.8]
#define RAIN_STREAK_SPEED         0.085   // [0.02 0.04 0.06 0.08 0.085 0.10 0.12 0.15 0.20]
#define RAIN_STREAK_WOBBLE_AMP    0.013   // [0.002 0.004 0.006 0.008 0.010 0.013 0.016 0.020]
#define RAIN_STREAK_WOBBLE_FREQ   1.6     // [0.5 0.8 1.0 1.2 1.5 1.6 1.8 2.0 2.5]
#define RAIN_STREAK_ZIG_AMP       0.025   // [0.006 0.010 0.014 0.018 0.022 0.025 0.030 0.036 0.045]
#define RAIN_STREAK_ZIG_FREQ      4.0     // [1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 6.0 8.0]
#define RAIN_STREAK_ZIG_SMOOTH    0.15    // [0.0 0.1 0.2 0.3 0.35 0.4 0.5 0.6]
#define RAIN_STREAK_REFRACT       0.035   // [0.005 0.008 0.012 0.016 0.020 0.025 0.032 0.035 0.040 0.050]
#define RAIN_STREAK_SPEC          0.45    // [0.1 0.2 0.3 0.4 0.45 0.5 0.6 0.7]
#define RAIN_STREAK_ALPHA         0.75    // [0.2 0.3 0.4 0.5 0.6 0.7 0.75 0.8 0.9 1.0]
#define RAIN_STREAK_BOTTOM_POOL   1       // [0 1]
#define RAIN_STREAK_POOL_STRENGTH 0.04   // [0.01 0.02 0.03 0.04 0.05 0.06 0.08]

// ============================================================

float linearizeDepth(float depth, float near, float far) {
    return (2.0 * near) / (far + near - depth * (far - near));
}

#include "/lib/Head/Common.inc"
#include "/lib/Head/Uniforms.inc"
#include "/lib/Head/Noise.inc"

uniform vec3 viewDir;
uniform vec2 mouseDelta;
uniform vec3 sunPosition;
uniform float sunVisibility;
uniform float moonVisibility;
uniform vec3 lightNight;
uniform float isSneaking;
uniform float sneakSmooth;
#ifndef EYE_SQUINT_SPEED
#define EYE_SQUINT_SPEED 0.15
#endif
#ifndef EYE_SQUINT_MAX
#define EYE_SQUINT_MAX 1.0
#endif
#ifndef EYE_SQUINT_ENABLED
#define EYE_SQUINT_ENABLED 1
#endif
#ifndef EYE_SQUINT_HEIGHT_PIXELS
#define EYE_SQUINT_HEIGHT_PIXELS 40.0
#endif
#ifndef EYE_SQUINT_SOFTNESS
#define EYE_SQUINT_SOFTNESS 8.0
#endif
#ifndef EYE_SQUINT_OFFSET
#define EYE_SQUINT_OFFSET 0.0
#endif
uniform float rainStrength;
uniform int worldTime;
uniform float eyeSquint;
uniform vec3 cameraSpeed;
uniform vec3 previousPosition;
uniform sampler2D colortex20;
uniform sampler2D colortex21;
uniform sampler2D colortex22;
uniform sampler2D colortex23;
uniform sampler2D colortex24;
uniform ivec2 eyeBrightnessSmooth;

uniform float currentPlayerHealth;
uniform float maxPlayerHealth;
uniform float oneHeart;
uniform float threeHeart;
uniform float CriticalDamageTaken;
uniform float MinorDamageTaken;
uniform float exitWater;
uniform float enterWater;
uniform float exitLava;

#ifdef DROWNING_EFFECT
uniform float drowningSmooth;
uniform float currentPlayerAir;
#endif

#ifdef USE_PNG_TEXTURE
uniform sampler2D texture;
#endif

float random(vec2 st) {
    return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453123);
}

// ============================================================
// LENS WATER SYSTEM
// ============================================================

vec2 rand2D(vec2 coord) {
    return vec2(
        fract(sin(dot(coord.xy, vec2(12.9898, 78.233))) * 43758.5453),
        fract(cos(dot(coord.yx, vec2(8.64947, 45.097))) * 43758.5453)
    ) * 2.0 - 1.0;
}

float lwHash(vec2 p) {
    p = fract(p * vec2(443.897, 441.423));
    p += dot(p, p + 19.19);
    return fract(p.x * p.y);
}

float sdRoundedBox(vec2 p, vec2 b, vec4 r) {
    vec2 q = abs(p);
    float rx = (p.x < 0.0)
        ? ((p.y > 0.0) ? r.x : r.z)
        : ((p.y > 0.0) ? r.y : r.w);
    vec2 c = b - rx;
    vec2 d = q - c;
    return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0) - rx;
}

vec3 tearDrop(vec2 localUV, float cx, float cy, float cellAspect) {
    float hw = DROP_W * 0.5;
    float hh = DROP_H * 0.5;
    vec2 p = localUV - vec2(cx, cy);
    p.x *= cellAspect;
    float minR = min(hw * cellAspect, hh);
    vec4 radii = vec4(
        DROP_ROUND_TL * minR, DROP_ROUND_TR * minR,
        DROP_ROUND_BL * minR, DROP_ROUND_BR * minR
    );
    float sdf = sdRoundedBox(p, vec2(hw * cellAspect, hh), radii);
    float fadeWidth = max(DROP_EDGE_FADE * minR * 0.8, 0.002);
    float mask = smoothstep(fadeWidth, -fadeWidth, sdf);
    if (mask < 0.001) return vec3(0.0);
    float eps = 0.004;
    vec2 pex  = p + vec2(eps, 0.0); vec2 pex2 = p - vec2(eps, 0.0);
    vec2 pey  = p + vec2(0.0, eps); vec2 pey2 = p - vec2(0.0, eps);
    vec2 grad = vec2(
        sdRoundedBox(pex,  vec2(hw*cellAspect,hh),radii) - sdRoundedBox(pex2,vec2(hw*cellAspect,hh),radii),
        sdRoundedBox(pey,  vec2(hw*cellAspect,hh),radii) - sdRoundedBox(pey2,vec2(hw*cellAspect,hh),radii)
    ) / (2.0 * eps);
    vec2 normal = -grad * mask * 0.018;
    vec2 specD = p - vec2(-hw * cellAspect * 0.3, hh * 0.5);
    float spec = smoothstep(minR * 0.4, 0.0, length(specD)) * mask;
    return vec3(normal, spec);
}

float trailRefract(vec2 localUV, float cx, float cy, float aspect) {
    float dx = abs((localUV.x - cx) * aspect);
    float dy = localUV.y - cy;
    if (dy < 0.0) return 0.0;
    float width_   = smoothstep(0.022, 0.006, dx);
    float length_  = smoothstep(0.55, 0.04, dy);
    float fade     = smoothstep(0.0, 0.05, dy);
    return width_ * length_ * fade * RAIN_TRAIL_REFRACT;
}

// ============================================================
// RAIN STREAKS
// ============================================================

float rsHash1(float n) {
    return fract(sin(n * 127.1 + 311.7) * 43758.5453);
}

float streakCenterX(float baseX, float phase, float yUV, bool isZig) {
    float wobble = sin(yUV * RAIN_STREAK_WOBBLE_FREQ * 6.28318 + phase + frameTimeCounter * 0.3)
                   * RAIN_STREAK_WOBBLE_AMP;
    if (!isZig) return baseX + wobble;
    float zigRaw = sin(yUV * RAIN_STREAK_ZIG_FREQ * 6.28318 + phase * 2.3);
    float zigSmooth = sign(zigRaw) * pow(abs(zigRaw), 1.0 - RAIN_STREAK_ZIG_SMOOTH * 0.85);
    return baseX + zigSmooth * RAIN_STREAK_ZIG_AMP + wobble * 0.4;
}

vec3 calcWaterStreak(vec2 uv, int idx, bool isZig) {
    float fi = float(idx);

    // Для зиг-потоков — центрируем вокруг RAIN_STREAK_ZIG_OFFSET_X
    // Для прямых — равномерно по всему экрану
    float baseX;
    if (isZig) {
        baseX = RAIN_STREAK_ZIG_OFFSET_X
              + (rsHash1(fi * 13.1 + 7.3) * 2.0 - 1.0) * RAIN_STREAK_ZIG_SPREAD;
        baseX = clamp(baseX, 0.02, 0.98);
    } else {
        baseX = rsHash1(fi * 13.1 + 7.3);
    }

    float phase = rsHash1(fi * 5.7  + 2.1) * 6.28318;
    float speed = RAIN_STREAK_SPEED * (0.6 + rsHash1(fi * 3.3 + 1.7) * 0.8);
    float alpha = 0.55 + rsHash1(fi * 9.1 + 4.4) * 0.45;

    float rawT  = mod(frameTimeCounter * speed + rsHash1(fi * 7.7 + 3.3), 1.0);
    
    // ПОФИКСЕНО: Голова капли теперь движется сверху (1.0) вниз (0.0)
    float headY = 1.0 - rawT;

    float appear = smoothstep(0.0, 0.05, rawT);
    float vanish = smoothstep(0.95, 1.0, rawT);
    float streamAlpha = alpha * appear * (1.0 - vanish)
                      * clamp(rainStrength, 0.0, 1.0) * RAIN_STREAK_ALPHA;

    if (streamAlpha < 0.005) return vec3(0.0);

    // ПОФИКСЕНО: Расстояние от головы до хвоста теперь считается корректно для падения вниз
    float dy = uv.y - headY;
    if (dy < 0.0 || dy > RAIN_STREAK_LENGTH) return vec3(0.0);

    float cx = streakCenterX(baseX, phase, uv.y, isZig);

    float aspect  = viewWidth / viewHeight;
    float dxRaw   = (uv.x - cx) * aspect;
    float halfW   = RAIN_STREAK_WIDTH * aspect;

    float edgeT   = abs(dxRaw) / halfW;
    float edgeMix = RAIN_STREAK_EDGE_SOFT;
    float widthMask = smoothstep(1.0, 1.0 - edgeMix, edgeT)
                    * (1.0 - edgeT * edgeT * (1.0 - edgeMix));
    widthMask = clamp(widthMask, 0.0, 1.0);
    if (widthMask < 0.001) return vec3(0.0);

    float frac       = dy / RAIN_STREAK_LENGTH;
    float lengthMask = pow(1.0 - frac, 1.4) * smoothstep(0.0, 0.03, dy);
    float totalMask  = widthMask * lengthMask * streamAlpha;
    if (totalMask < 0.001) return vec3(0.0);

    float refractX = -dxRaw / max(halfW * halfW / aspect, 0.0001)
                     * RAIN_STREAK_REFRACT * 0.12 * totalMask;
    float headFrac = smoothstep(0.08, 0.0, dy);
    
    // ПОФИКСЕНО: Инвертировано вертикальное преломление, чтобы линза соответствовала падающей капле
    float refractY = headFrac * RAIN_STREAK_REFRACT * totalMask * 1.2;

    float edgeSpec = pow(clamp(1.0 - abs(edgeT - 0.6) * 3.0, 0.0, 1.0), 2.0);
    float headSpec = smoothstep(0.12, 0.0, dy) * widthMask;
    float spec     = (edgeSpec * 0.4 + headSpec * 0.6) * totalMask * RAIN_STREAK_SPEC;

    return vec3(refractX, refractY, spec);
}

vec2 applyBottomPool(vec2 uv) {
    #if RAIN_STREAK_BOTTOM_POOL == 0
        return vec2(0.0);
    #endif

    // ПОФИКСЕНО: Теперь берем чистый uv.y, чтобы эффект работал у НИЖНЕЙ границы экрана (0.0)
    float poolY = uv.y; 
    if (poolY > 0.12) return vec2(0.0);

    // Маска плавно затухает от самого низа (0.0) до высоты 0.12
    float poolMask = smoothstep(0.12, 0.0, poolY) * clamp(rainStrength, 0.0, 1.0);
    
    // Синусоиды для создания эффекта мелкой ряби и волнения воды в лужице
    float ripple = sin(uv.x * 28.0 + frameTimeCounter * 1.2) * 0.4
                 + sin(uv.x * 47.0 - frameTimeCounter * 0.8) * 0.3;
                 
    // ПОФИКСЕНО: Изменен знак преломления по Y, чтобы искажение смотрелось физично для низа экрана
    float refractY = -ripple * RAIN_STREAK_POOL_STRENGTH * poolMask;
    float refractX = cos(uv.x * 19.0 + frameTimeCounter * 0.9) * RAIN_STREAK_POOL_STRENGTH * 0.3 * poolMask;
    
    return vec2(refractX, refractY);
}

vec3 applyRainStreaks(vec2 uv, vec3 color) {
    #if RAIN_STREAKS_ENABLED == 0
        return color;
    #endif
    if (rainStrength < 0.01) return color;

    vec2  totalRefract  = vec2(0.0);
    float totalSpecular = 0.0;

    for (int i = 0; i < RAIN_STREAKS_COUNT; i++) {
        vec3 s = calcWaterStreak(uv, i, false);
        totalRefract  += s.xy;
        totalSpecular += s.z;
    }
    for (int i = 0; i < RAIN_STREAKS_ZIG_COUNT; i++) {
        vec3 s = calcWaterStreak(uv, i + RAIN_STREAKS_COUNT + 50, true);
        totalRefract  += s.xy;
        totalSpecular += s.z;
    }

    totalRefract += applyBottomPool(uv);

    vec2 refractUV      = clamp(uv + totalRefract, 0.0, 1.0);
    vec3 refractedColor = texture2D(colortex3, refractUV).rgb;
    float effectStrength = clamp(length(totalRefract) * 38.0, 0.0, 1.0);
    color = mix(color, refractedColor, effectStrength);
    color += clamp(totalSpecular, 0.0, 0.9) * 0.38 * vec3(0.86, 0.93, 1.0);
    return color;
}

// ============================================================
// applyLensWater
// ============================================================

vec3 applyLensWater(vec2 uv, vec3 color) {
    #if LENS_WATER == 0
        return color;
    #endif

    float t      = frameTimeCounter;
    float aspect = viewWidth / viewHeight;
    vec2  totalRefract  = vec2(0.0);
    float totalSpecular = 0.0;

    if (rainStrength > 0.01) {
        float rs = clamp(rainStrength, 0.0, 1.0);
        int nx = RAIN_DROP_COUNT_X;
        int ny = RAIN_DROP_COUNT_Y;
        float cellW = 1.0 / float(nx);
        float cellH = 1.0 / float(ny);

        for (int row = 0; row < RAIN_DROP_COUNT_Y; row++) {
        for (int col = 0; col < RAIN_DROP_COUNT_X; col++) {
            vec2 idx = vec2(float(col), float(row));
            float r1 = lwHash(idx);
            float r2 = lwHash(idx + vec2(17.3, 5.7));
            float r3 = lwHash(idx + vec2(31.1, 89.3));
            float r4 = lwHash(idx + vec2(53.7, 23.9));
            if (r1 > rs * RAIN_STATIC_CHANCE + 0.12) continue;
            float ox = (r2 - 0.5) * cellW * 0.7;
            float oy = (r3 - 0.5) * cellH * 0.5;
            vec2 origin  = idx * vec2(cellW, cellH) + vec2(ox, oy);
            vec2 localUV = (uv - origin) / vec2(cellW, cellH);
            if (any(lessThan(localUV, vec2(0.0))) ||
                any(greaterThan(localUV, vec2(1.0)))) continue;
            float cx = 0.5 + (r4 - 0.5) * 0.25;
            bool isStatic = r2 > 0.55;
            float cy, dropAlpha;
            if (isStatic) {
                cy = 0.25 + r3 * 0.5;
                dropAlpha = 0.85 + r1 * 0.15;
            } else {
                float speed  = RAIN_DROP_SPEED * (0.5 + r3 * 1.0);
                float period = 8.0 + r2 * 20.0;
                float phase  = r4;
                float rawT   = mod(t * speed + phase * period, period) / period;
                float appear = smoothstep(0.0, 0.08, rawT);
                float vanish = smoothstep(0.92, 1.0, rawT);
                dropAlpha = appear * (1.0 - vanish);
                cy = mix(0.95, 0.05, rawT);
            }
            if (dropAlpha < 0.01) continue;
            vec3 drop   = tearDrop(localUV, cx, cy, aspect * cellW / cellH);
            float trail = trailRefract(localUV, cx, cy, aspect * cellW / cellH);
            totalRefract  += (drop.xy * RAIN_DROP_REFRACT + vec2(0.0, trail)) * dropAlpha * rs;
            totalSpecular += drop.z * dropAlpha * rs;
        }
        }
    }

    if (exitWater > 0.01 && isEyeInWater == 0) {
        float fade = smoothstep(0.0, 0.3, exitWater) * exitWater;
        for (int s = 0; s < WATER_EXIT_STREAMS; s++) {
            float si   = float(s);
            float rX   = lwHash(vec2(si * 3.1, 7.3));
            float rW   = lwHash(vec2(si * 3.1, 13.7));
            float rSp  = lwHash(vec2(si * 3.1, 3.1));
            float rOff = lwHash(vec2(si * 3.1, 43.1));
            float streamX = mix(0.06, 0.94, rX);
            float streamW = mix(0.008, 0.022, rW);
            float speed   = mix(0.12, 0.35, rSp) * (0.3 + exitWater * 0.7);
            float streamY = rOff + (1.0 - exitWater) * speed * 3.5;
            streamY = clamp(streamY, 0.0, 1.2);
            float dx = abs(uv.x - streamX) / streamW;
            if (dx > 3.0) continue;
            float inStream = smoothstep(2.5, 0.0, dx);
            float headY    = streamY;
            float dy       = uv.y - headY;
            float headMask = 0.0;
            if (abs(dy) < 0.06) {
                vec2 hd = vec2(dx * streamW * 40.0, dy / 0.05);
                float taper = clamp(dy / 0.04, -1.0, 1.0);
                hd.x *= (1.0 - taper * 0.4);
                headMask = smoothstep(1.0, 0.4, dot(hd, hd));
            }
            float trailMask = 0.0;
            if (dy < -0.005 && dy > -0.55) {
                trailMask = smoothstep(1.5, 0.0, dx)
                          * smoothstep(-0.55, -0.02, dy)
                          * (1.0 - headMask) * 0.6;
            }
            float totalMask = (headMask + trailMask) * inStream * fade;
            if (totalMask < 0.001) continue;
            vec2 refractDir = vec2(
                -(uv.x - streamX) / (streamW * streamW) * 0.00015,
                -headMask * WATER_EXIT_REFRACT
            );
            totalRefract += refractDir * totalMask;
            vec2 specD = vec2(dx * streamW * 50.0 + 0.3, (dy + 0.015) / 0.02);
            totalSpecular += smoothstep(1.0, 0.0, dot(specD, specD))
                           * headMask * inStream * fade * 0.7;
        }
    }

    if (enterWater > 0.01) {
        float splash = enterWater * enterWater;
        totalRefract += (0.5 + (uv - 0.5) * (1.0 - splash * 0.12) - uv) * splash * 0.5;
    }

    vec2 refractUV      = clamp(uv + totalRefract, 0.0, 1.0);
    vec3 refractedColor = texture2D(colortex3, refractUV).rgb;
    float effectStrength = clamp(length(totalRefract) * 35.0, 0.0, 1.0);
    color = mix(color, refractedColor, effectStrength);
    color += clamp(totalSpecular, 0.0, 0.9) * 0.45 * vec3(0.92, 0.96, 1.0);

    color = applyRainStreaks(uv, color);
    return color;
}

vec2 raindropsOnScreenRefraction(vec2 coord) { return coord; }
vec2 waterExitDropsRefraction(vec2 coord)     { return coord; }

vec2 underwaterScreenRefraction(vec2 coord) {
    const float refractionMultiplier = 0.003;
    const float refractionSpeed      = 4.0;
    const float refractionSize       = 1.0;
    vec2 refractCoord = vec2(
        sin(frameTimeCounter * refractionSpeed
            + coord.x * 25.0 * refractionSize
            + coord.y * 12.5 * refractionSize),
        0.0);
    return bool(isEyeInWater) ? coord + refractCoord * refractionMultiplier : coord;
}

// ============================================================
// PROCEDURAL DIRTY LENS
// ============================================================
float proceduralDots(vec2 coord) {
    #if PROC_DIRT_ASPECT_CORRECT == 1
        vec2 aspectCorrect = vec2(aspectRatio, 1.0);
    #else
        vec2 aspectCorrect = vec2(1.0, 1.0);
    #endif
    vec2 g = floor(coord * aspectCorrect);
    vec2 f = fract(coord * aspectCorrect) * 2.0 - 1.0;
    vec2 r = vec2(
        fract(sin(dot(g, vec2(12.9898, 78.233))) * 43758.5453),
        fract(cos(dot(g.yx, vec2(8.64947, 45.097))) * 43758.5453)
    ) - 0.5;
    return length(f + r);
}

float getProceduralDirtLens(vec2 coord) {
    float dirt  = 0.0;
    float scale = PROC_DIRT_SCALE_BASE;
    #if PROC_DIRT_EDGE_BOOST > 0.0
        float edgeFactor = 1.0 + PROC_DIRT_EDGE_BOOST * pow(length(coord - 0.5) * 2.0, 1.5);
    #else
        float edgeFactor = 1.0;
    #endif
    for (int i = 0; i < PROC_DIRT_LAYERS; i++) {
        dirt += (1.0 - smoothstep(PROC_DIRT_SMOOTH_IN, PROC_DIRT_SMOOTH_OUT,
                                   proceduralDots(coord * scale)));
        scale *= PROC_DIRT_SCALE_MUL;
    }
    return min(dirt * edgeFactor, 1.0);
}

vec3 applyProceduralDirtyLens(vec2 coord, vec3 color) {
    #if DIRT_STYLE != 2
        return color;
    #endif
    float dirtMask = getProceduralDirtLens(coord);
    vec3 bloomSample = vec3(0.0);
    vec2 texelSize = 1.0 / vec2(viewWidth, viewHeight);
    float bloomRadius = 4.0;
    bloomSample += texture2D(colortex3, coord + vec2( bloomRadius,  0.0) * texelSize).rgb;
    bloomSample += texture2D(colortex3, coord + vec2(-bloomRadius,  0.0) * texelSize).rgb;
    bloomSample += texture2D(colortex3, coord + vec2( 0.0,  bloomRadius) * texelSize).rgb;
    bloomSample += texture2D(colortex3, coord + vec2( 0.0, -bloomRadius) * texelSize).rgb;
    bloomSample /= 4.0;
    vec3 dirtColor = pow(bloomSample, vec3(0.6)) * vec3(DIRTY_LENS_TINT_R, DIRTY_LENS_TINT_G, DIRTY_LENS_TINT_B);
    return mix(color, dirtColor, clamp(dirtMask * DIRTY_LENS_BLOOM_MIX * DIRTY_LENS_INTENSITY, 0.0, 1.0));
}

float bodyCamNoise(vec2 x) {
    vec2 i = floor(x);
    vec2 f = fract(x);
    vec2 u = f * f * (3.0 - 2.0 * f);
    float a = random(i + vec2(0.0, 0.0));
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));
    return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}

vec2 cameraShake(float frameTimeCounter, float intensity) {
#if ENABLE_CAMERA_SHAKE == 1
    return vec2(intensity * sin(frameTimeCounter * 1.5),
                intensity * cos(frameTimeCounter * 1.85));
#else
    return vec2(0.0);
#endif
}

vec2 handSway(float frameTimeCounter, float intensity) {
#if ENABLE_CAMERA_SHAKE == 1
    return vec2(intensity * sin(frameTimeCounter * 2.0),
                intensity * cos(frameTimeCounter * 2.5));
#else
    return vec2(0.0);
#endif
}

float blackFOVMask(vec2 coord) {
    vec2 centered = abs(coord - 0.5);
    float fovScale = 1.0 / (0.01 + 0.99 * (BLACK_FOV / 100.0));
    #if BODYCAM_STYLE == 0
        float r = length(centered * fovScale);
        return 1.0 - smoothstep(0.7, 1.0, r);
    #else
        float r = max(centered.x, centered.y) * fovScale;
        return 1.0 - smoothstep(0.7, 1.0, r);
    #endif
}

vec2 hash2D(vec2 p) {
    p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
    return fract(sin(p) * 43758.5453);
}

float hash(vec2 p) {
    p = fract(p * vec2(123.456, 789.123));
    p += dot(p, p + vec2(45.67, 89.01));
    return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
}

float rainDropShape(vec2 uv, vec2 pos, float size) {
    vec2 d = uv - pos;
    float dist = length(d);
    float shape = smoothstep(size, size * 0.4, dist) * (1.0 - dist / size);
    shape *= 0.5 + 0.5 * sin(dist * 20.0 + frameTimeCounter * 5.0);
    return shape;
}

vec2 lensDistortion(vec2 coord) {
    vec2 centered = coord - 0.5;
    float r = length(centered);
    float lens_effect = FisheyeDistortionStrength * (1.0 - r * r);
    return centered * (1.0 + lens_effect) + 0.5;
}

// НОВЫЕ КРУТЫЕ ЭФФЕКТЫ ДИСТОРШЕНА И СКРУГЛЕНИЯ
vec2 DistortPosition(vec2 coord) {
    #if EDGE_DISTORTION_ENABLED == 1
    vec2 centered = coord - 0.5;
    float r2 = dot(centered, centered);
    float r4 = r2 * r2;
    
    // Круговое и угловое искажение экрана
    float circFactor = 1.0 + r2 * CIRCULAR_DISTORT_STRENGTH;
    float cornerFactor = 1.0 + r4 * CORNER_DISTORT_STRENGTH;
    vec2 distorted = centered * circFactor * cornerFactor;
    
    // Искажение по краям (бочкообразный изгиб с краев)
    distorted.x *= (1.0 + distorted.y * distorted.y * HORIZONTAL_EDGE_STRENGTH);
    distorted.y *= (1.0 + distorted.x * distorted.x * VERTICAL_EDGE_STRENGTH);
    
    return distorted + 0.5;
    #else
    return coord;
    #endif
}

vec2 imageRoundedDistortion(vec2 coord) {
    vec2 centered = coord - 0.5;
    
    // Учитываем растяжение маски
    vec2 aspectScale = vec2(1.0 / IMAGE_HORIZONTAL_STRENGTH, 1.0 / IMAGE_VERTICAL_STRENGTH);
    vec2 scaled = centered * aspectScale;
    float r = length(scaled);
    
    // Искривление координат около радиуса скругления
    if (IMAGE_ROUNDING_RADIUS > 0.0) {
        float warp = pow(r / max(IMAGE_ROUNDING_RADIUS, 0.01), 3.0) * 0.05 * IMAGE_ROUND_STRENGTH;
        centered *= (1.0 + warp);
    }
    
    return centered + 0.5;
}

float ImageRound(vec2 coord) {
    vec2 centered = coord - 0.5;
    
    // Масштабирование размеров маски
    vec2 aspectScale = vec2(IMAGE_HORIZONTAL_STRENGTH, IMAGE_VERTICAL_STRENGTH);
    vec2 scaled = abs(centered) * aspectScale;
    
    // Вычисление SDF (Signed Distance Field) для закругленного прямоугольника.
    // Дает идеально ровные края. Размер прямоугольника берется 0.5 на 0.5 
    vec2 q = scaled - 0.5 + IMAGE_ROUNDING_RADIUS;
    float dist = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - IMAGE_ROUNDING_RADIUS;
    
    // Мягкость краев зависит от IMAGE_ROUND_STRENGTH
    float edgeSmooth = mix(0.001, 0.05, 1.0 - IMAGE_ROUND_STRENGTH);
    
    // Возвращаем маску (1 внутри, плавно уходит в 0 снаружи)
    return 1.0 - smoothstep(0.0, edgeSmooth, dist);
}

vec2 rotateUV(vec2 uv, float angle) {
    vec2 center = vec2(0.5, 0.5);
    vec2 d = uv - center;
    float c = cos(angle), s = sin(angle);
    return center + vec2(d.x * c - d.y * s, d.x * s + d.y * c);
}

vec2 applyCRTCurve(vec2 coord) {
    vec2 centered = coord - 0.5;
    float dist = length(centered);
    float curve = dist * CRT_CURVE;
    return centered * (1.0 + curve * dist) + 0.5;
}

vec3 applyBloom(vec2 coord, vec3 color) {
    #if BLOOM_ENABLED == 1
    vec3 bloom = vec3(0.0);
    const int samples = 5;
    vec2 texelSize = 1.0 / vec2(viewWidth, viewHeight);
    for (int i = -samples / 2; i <= samples / 2; i++)
        for (int j = -samples / 2; j <= samples / 2; j++)
            bloom += max(vec3(0.0), texture2D(colortex3, coord + vec2(float(i),float(j)) * texelSize * 2.0).rgb - 0.5) * 0.05;
    bloom /= float(samples * samples);
    return color + bloom * BLOOM_STRENGTH;
    #else
    return color;
    #endif
}

float getLinearDepth(float depth) {
    return linearizeDepth(depth, 0.1, 1000.0) * 1000.0;
}

vec3 bicubicSample(sampler2D tex, vec2 coord, vec2 texelSize) {
    vec2 f = fract(coord / texelSize);
    coord = floor(coord / texelSize) * texelSize;
    vec2 w0 = f * (-0.5 + f * (1.0 - 0.5 * f));
    vec2 w1 = 1.0 + f * f * (-2.5 + 1.5 * f);
    vec2 w2 = f * (0.5 + f * (2.0 - 1.5 * f));
    vec2 w3 = f * f * (-0.5 + 0.5 * f);
    vec2 s0 = w0 + w1; vec2 s1 = w2 + w3;
    vec2 f0 = w1 / s0; vec2 f1 = w3 / s1;
    vec2 t0 = coord - texelSize + f0 * texelSize;
    vec2 t1 = coord + texelSize + f1 * texelSize;
    return (texture2D(tex, vec2(t0.x, t0.y)).rgb * s0.x +
            texture2D(tex, vec2(t1.x, t0.y)).rgb * s1.x) * s0.y +
           (texture2D(tex, vec2(t0.x, t1.y)).rgb * s0.x +
            texture2D(tex, vec2(t1.x, t1.y)).rgb * s1.x) * s1.y;
}

// ============================================================
// AXON OVERLAY TEXT
// ============================================================

float drawAxonCharGlobal(vec2 uv, vec2 pos, int charCode, bool shadow) {
    vec2 cSize = vec2(AXON_CHAR_W, AXON_CHAR_H);
    vec2 offset = shadow ? vec2(AXON_SHADOW_OFFSET, -AXON_SHADOW_OFFSET) : vec2(0.0);
    vec2 localUV = (uv - pos - offset) / cSize;
    if (localUV.x < 0.0 || localUV.x > 1.0 || localUV.y < 0.0 || localUV.y > 1.0) return 0.0;
    float pixel = 0.0;
    vec2 pp = floor(localUV * vec2(5.0, 7.0));
    if (charCode == 0) {
        if ((pp.x == 0.0 || pp.x == 4.0) && pp.y > 0.0 && pp.y < 6.0) pixel = 1.0;
        if ((pp.y == 0.0 || pp.y == 6.0) && pp.x > 0.0 && pp.x < 4.0) pixel = 1.0;
    } else if (charCode == 1) {
        if (pp.x == 3.0) pixel = 1.0;
        if (pp.x >= 2.0 && pp.x <= 4.0 && pp.y == 0.0) pixel = 1.0;
    } else if (charCode == 2) {
        if (pp.y == 0.0 || pp.y == 3.0 || pp.y == 6.0) pixel = 1.0;
        if (pp.x == 0.0 && pp.y < 3.0) pixel = 1.0;
        if (pp.x == 4.0 && pp.y > 3.0) pixel = 1.0;
    } else if (charCode == 3) {
        if (pp.y == 0.0 || pp.y == 3.0 || pp.y == 6.0) pixel = 1.0;
        if (pp.x == 4.0 && pp.y != 3.0) pixel = 1.0;
    } else if (charCode == 4) {
        if (pp.x == 0.0 && pp.y > 3.0) pixel = 1.0;
        if (pp.x == 4.0) pixel = 1.0;
        if (pp.y == 3.0) pixel = 1.0;
    } else if (charCode == 5) {
        if (pp.y == 0.0 || pp.y == 3.0 || pp.y == 6.0) pixel = 1.0;
        if (pp.x == 0.0 && pp.y > 3.0) pixel = 1.0;
        if (pp.x == 4.0 && pp.y < 3.0) pixel = 1.0;
    } else if (charCode == 6) {
        if (pp.y == 0.0 || pp.y == 3.0 || pp.y == 6.0) pixel = 1.0;
        if (pp.x == 0.0) pixel = 1.0;
        if (pp.x == 4.0 && pp.y < 4.0) pixel = 1.0;
    } else if (charCode == 7) {
        if (pp.y == 6.0) pixel = 1.0;
        if (pp.x == 4.0) pixel = 1.0;
    } else if (charCode == 8) {
        if (pp.y == 0.0 || pp.y == 3.0 || pp.y == 6.0) pixel = 1.0;
        if (pp.x == 0.0 || pp.x == 4.0) pixel = 1.0;
    } else if (charCode == 9) {
        if (pp.y == 0.0 || pp.y == 3.0 || pp.y == 6.0) pixel = 1.0;
        if (pp.x == 0.0 && pp.y > 3.0) pixel = 1.0;
        if (pp.x == 4.0) pixel = 1.0;
    } else if (charCode == 10) {
        if (pp.x == 2.0 && (pp.y == 2.0 || pp.y == 4.0)) pixel = 1.0;
    } else if (charCode == 11) {
        if (pp.y == 3.0 && pp.x >= 1.0 && pp.x <= 3.0) pixel = 1.0;
    }
    return pixel;
}

void drawAxonRow(vec2 uv, vec2 startPos, int c0, int c1, int c2, int c3,
                 int c4, int c5, int c6, int c7,
                 inout float ui, inout float shadow) {
    float sp = AXON_CHAR_W * AXON_CHAR_SPACING;
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 0.0, 0.0), c0, false);
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 1.0, 0.0), c1, false);
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 2.0, 0.0), c2, false);
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 3.0, 0.0), c3, false);
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 4.0, 0.0), c4, false);
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 5.0, 0.0), c5, false);
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 6.0, 0.0), c6, false);
    ui     += drawAxonCharGlobal(uv, startPos + vec2(sp * 7.0, 0.0), c7, false);
    #if AXON_TEXT_SHADOW == 1
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 0.0, 0.0), c0, true);
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 1.0, 0.0), c1, true);
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 2.0, 0.0), c2, true);
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 3.0, 0.0), c3, true);
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 4.0, 0.0), c4, true);
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 5.0, 0.0), c5, true);
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 6.0, 0.0), c6, true);
    shadow += drawAxonCharGlobal(uv, startPos + vec2(sp * 7.0, 0.0), c7, true);
    #endif
}

vec3 drawAxonText(vec2 uv, vec2 axonPos, vec2 axonSize, vec3 baseColor, int position) {
    float textBlockW = AXON_CHAR_W * AXON_CHAR_SPACING * 8.5;
    float textBlockH = AXON_CHAR_H * 2.5;
    float textX;
    if (position == 0) textX = axonPos.x + axonSize.x + AXON_TEXT_GAP;
    else               textX = axonPos.x - textBlockW - AXON_TEXT_GAP;
    float imgCenterY = axonPos.y + axonSize.y * 0.5;
    float textStartY = imgCenterY + textBlockH * 0.5;

    float gameDaySec = 1200.0;
    int totalDays = int(frameTimeCounter / gameDaySec);
    int dayVal = 6  + int(mod(float(totalDays), 25.0));
    int monVal = 9; int yrVal  = 23;
    int dT = dayVal / 10; int dO = dayVal - dT * 10;
    int moT = monVal / 10; int moO = monVal - moT * 10;
    int yT = yrVal  / 10; int yO  = yrVal  - yT  * 10;

    float recTime = frameTimeCounter;
    int recH = int(recTime / 3600.0);
    int recM = int(mod(recTime / 60.0, 60.0));
    int recS = int(mod(recTime, 60.0));
    int hT = recH / 10; int hO = recH - hT * 10;
    int mT = recM / 10; int mO = recM - mT * 10;
    int sT = recS / 10; int sO = recS - sT * 10;

    vec2 datePos  = vec2(textX, textStartY - AXON_CHAR_H);
    vec2 timerPos = vec2(textX, textStartY - AXON_CHAR_H * 2.2);

    float ui = 0.0, sh = 0.0;
    drawAxonRow(uv, datePos,  yT, yO, 11, moT, moO, 11, dT, dO, ui, sh);
    drawAxonRow(uv, timerPos, hT, hO, 10, mT,  mO,  10, sT, sO, ui, sh);

    float recBlink  = step(0.5, fract(frameTimeCounter * 0.8));
    vec2  dotGlobal = timerPos + vec2(AXON_CHAR_W * AXON_CHAR_SPACING * 8.8 + 0.004, AXON_CHAR_H * 0.5);
    float dotDist   = length((uv - dotGlobal) / vec2(0.006, 0.009));
    float dotShape  = smoothstep(1.0, 0.4, dotDist) * recBlink;

    #if AXON_TEXT_SHADOW == 1
    vec2  dotShadow  = dotGlobal + vec2(AXON_SHADOW_OFFSET, -AXON_SHADOW_OFFSET);
    float dotShadowD = length((uv - dotShadow) / vec2(0.006, 0.009));
    float dotShapeS  = smoothstep(1.0, 0.4, dotShadowD) * recBlink;
    #endif

    vec3 result = baseColor;
    #if AXON_TEXT_SHADOW == 1
    if (sh > 0.0) result = mix(result, vec3(0.0), clamp(sh, 0.0, 1.0) * AXON_SHADOW_STRENGTH);
    result = mix(result, vec3(0.0), dotShapeS * AXON_SHADOW_STRENGTH);
    #endif
    if (ui > 0.0) result = mix(result, vec3(0.88, 0.95, 0.88), clamp(ui, 0.0, 1.0) * 0.9);
    result = mix(result, vec3(1.0, 0.08, 0.08), dotShape);
    return result;
}

vec4 DrawAXON(vec2 uv, vec2 pos, vec2 size) {
    vec2 texUV = (uv - pos) / size;
    if (texUV.x < 0.0 || texUV.x > 1.0 || texUV.y < 0.0 || texUV.y > 1.0) return vec4(0.0);
    return texture(colortex20, vec2(texUV.x, 1.0 - texUV.y));
}

// ============================================================
// DC_INTRO СТИЛИ 5–8: SDF-шрифт и proc-функции (из SPLASH)
// ============================================================

float seg_h(vec2 p, float x0, float x1, float y0, float h) {
    float inside_x = smoothstep(x0-h, x0+h, p.x) - smoothstep(x1-h, x1+h, p.x);
    float inside_y = 1.0 - smoothstep(0.0, h, abs(p.y - y0));
    return inside_x * inside_y;
}
float seg_v(vec2 p, float x0, float y0, float y1, float h) {
    float inside_x = 1.0 - smoothstep(0.0, h, abs(p.x - x0));
    float inside_y = smoothstep(y0-h, y0+h, p.y) - smoothstep(y1-h, y1+h, p.y);
    return inside_x * inside_y;
}
float seg_d(vec2 p, vec2 a, vec2 b, float h) {
    vec2 ab = b - a; vec2 ap = p - a;
    float t = clamp(dot(ap, ab) / dot(ab, ab), 0.0, 1.0);
    return 1.0 - smoothstep(0.0, h, length(ap - t * ab));
}
float seg_arc(vec2 p, vec2 center, float rx, float ry, float h) {
    vec2 d = (p - center) / vec2(rx, ry);
    return 1.0 - smoothstep(0.0, h, abs(length(d) - 1.0) * min(rx, ry));
}
float seg_arc_half(vec2 p, vec2 center, float rx, float ry, float h, float side) {
    vec2 d = (p - center) / vec2(rx, ry);
    float dist = abs(length(d) - 1.0) * min(rx, ry);
    return (1.0 - smoothstep(0.0, h, dist)) * step(0.0, (p.x - center.x) * side);
}

float letter_D(vec2 p, float h) {
    float r = seg_v(p, 0.08, 0.0, 1.0, h);
    r += seg_h(p, 0.08, 0.55, 0.0, h); r += seg_h(p, 0.08, 0.55, 1.0, h);
    r += seg_arc_half(p, vec2(0.55,0.5), 0.18, 0.5, h, 1.0);
    return clamp(r, 0.0, 1.0);
}
float letter_E(vec2 p, float h) {
    float r = seg_v(p, 0.08, 0.0, 1.0, h);
    r += seg_h(p, 0.08, 0.85, 0.0, h); r += seg_h(p, 0.08, 0.75, 0.5, h); r += seg_h(p, 0.08, 0.85, 1.0, h);
    return clamp(r, 0.0, 1.0);
}
float letter_R(vec2 p, float h) {
    float r = seg_v(p, 0.08, 0.0, 1.0, h);
    r += seg_h(p, 0.08, 0.6, 1.0, h); r += seg_h(p, 0.08, 0.6, 0.5, h);
    r += seg_arc_half(p, vec2(0.6,0.75), 0.2, 0.25, h, 1.0);
    r += seg_d(p, vec2(0.5,0.5), vec2(0.9,0.0), h*1.2);
    return clamp(r, 0.0, 1.0);
}
float letter_C(vec2 p, float h) {
    vec2 center = vec2(0.5,0.5); vec2 d = (p-center)/vec2(0.42,0.5);
    float dist = abs(length(d)-1.0)*0.45;
    float opening = smoothstep(-0.25,0.0,p.x-center.x)*smoothstep(0.0,-0.25,abs(p.y-center.y)-0.25);
    return clamp((1.0-smoothstep(0.0,h,dist))*(1.0-opening),0.0,1.0);
}
float letter_O(vec2 p, float h) {
    vec2 d = (p-vec2(0.5,0.5))/vec2(0.42,0.5);
    return 1.0-smoothstep(0.0,h,abs(length(d)-1.0)*0.45);
}
float letter_L(vec2 p, float h) {
    return clamp(seg_v(p,0.08,0.0,1.0,h)+seg_h(p,0.08,0.85,0.0,h),0.0,1.0);
}
float letter_I(vec2 p, float h) {
    return clamp(seg_v(p,0.5,0.0,1.0,h)+seg_h(p,0.15,0.85,0.0,h)+seg_h(p,0.15,0.85,1.0,h),0.0,1.0);
}
float letter_T(vec2 p, float h) {
    return clamp(seg_v(p,0.5,0.0,1.0,h)+seg_h(p,0.0,1.0,1.0,h),0.0,1.0);
}
float digit_2(vec2 p, float h) {
    float r = seg_h(p,0.08,0.85,1.0,h)+seg_h(p,0.08,0.85,0.5,h)+seg_h(p,0.08,0.85,0.0,h);
    r += seg_arc_half(p,vec2(0.5,0.75),0.38,0.25,h,1.0)+seg_v(p,0.08,0.0,0.5,h);
    return clamp(r,0.0,1.0);
}
float char_dot(vec2 p, float h) { return 1.0-smoothstep(0.0,h*2.5,length(p-vec2(0.5,0.1))); }
float char_lbracket(vec2 p, float h) {
    return clamp(seg_v(p,0.35,0.0,1.0,h)+seg_h(p,0.35,0.7,0.0,h)+seg_h(p,0.35,0.7,1.0,h),0.0,1.0);
}
float char_rbracket(vec2 p, float h) {
    return clamp(seg_v(p,0.65,0.0,1.0,h)+seg_h(p,0.3,0.65,0.0,h)+seg_h(p,0.3,0.65,1.0,h),0.0,1.0);
}
float letter_b(vec2 p, float h) {
    return clamp(seg_v(p,0.08,0.0,1.0,h)+seg_h(p,0.08,0.65,0.0,h)+seg_h(p,0.08,0.65,0.5,h)+seg_arc_half(p,vec2(0.65,0.25),0.2,0.25,h,1.0),0.0,1.0);
}
float letter_y(vec2 p, float h) {
    return clamp(seg_d(p,vec2(0.08,1.0),vec2(0.5,0.5),h)+seg_d(p,vec2(0.92,1.0),vec2(0.5,0.5),h)+seg_d(p,vec2(0.5,0.5),vec2(0.2,0.0),h),0.0,1.0);
}
float letter_t_sm(vec2 p, float h) {
    return clamp(seg_v(p,0.5,0.05,1.0,h)+seg_h(p,0.1,0.9,0.65,h),0.0,1.0);
}
float letter_e_sm(vec2 p, float h) {
    vec2 c=vec2(0.5,0.35); vec2 d=(p-c)/vec2(0.42,0.35);
    float circ=abs(length(d)-1.0)*0.38;
    float cut=smoothstep(-0.05,0.05,p.x-0.5)*step(p.y,0.35);
    float r=(1.0-smoothstep(0.0,h,circ))*(1.0-cut);
    r+=seg_h(p,0.08,0.85,0.35,h);
    return clamp(r,0.0,1.0);
}
float letter_a_sm(vec2 p, float h) {
    float r=seg_arc(p,vec2(0.45,0.6),0.38,0.4,h);
    r*=(1.0-step(0.5,p.x)*step(p.y,0.6));
    r+=seg_v(p,0.85,0.0,0.65,h)+seg_h(p,0.45,0.85,0.35,h);
    return clamp(r,0.0,1.0);
}
float letter_m_sm(vec2 p, float h) {
    float r=seg_v(p,0.08,0.0,0.65,h)+seg_v(p,0.5,0.0,0.65,h)+seg_v(p,0.92,0.0,0.65,h);
    r+=seg_d(p,vec2(0.08,0.65),vec2(0.5,0.35),h)+seg_d(p,vec2(0.92,0.65),vec2(0.5,0.35),h);
    return clamp(r,0.0,1.0);
}

// --- Пиксельный bitmap 5x7 ---
float pixelChar(vec2 local, int glyphId) {
    vec2 grid = local * vec2(5.0, 7.0);
    int col = int(floor(grid.x)); int row = int(floor(grid.y));
    if (col < 0 || col > 4 || row < 0 || row > 6) return 0.0;
    int c0,c1,c2,c3,c4,c5,c6;
    if      (glyphId==0)  { c6=14;c5=17;c4=17;c3=17;c2=17;c1=17;c0=14; }
    else if (glyphId==1)  { c6=31;c5=16;c4=16;c3=30;c2=16;c1=16;c0=31; }
    else if (glyphId==2)  { c6=30;c5=17;c4=17;c3=30;c2=20;c1=18;c0=17; }
    else if (glyphId==3)  { c6=14;c5=17;c4=16;c3=16;c2=16;c1=17;c0=14; }
    else if (glyphId==4)  { c6=14;c5=17;c4=17;c3=17;c2=17;c1=17;c0=14; }
    else if (glyphId==5)  { c6=16;c5=16;c4=16;c3=16;c2=16;c1=16;c0=31; }
    else if (glyphId==6)  { c6=31;c5=4; c4=4; c3=4; c2=4; c1=4; c0=31; }
    else if (glyphId==7)  { c6=31;c5=4; c4=4; c3=4; c2=4; c1=4; c0=4;  }
    else if (glyphId==8)  { c6=14;c5=17;c4=1; c3=6; c2=8; c1=16;c0=31; }
    else if (glyphId==9)  { c6=0; c5=0; c4=0; c3=0; c2=0; c1=0; c0=4;  }
    else if (glyphId==10) { c6=6; c5=4; c4=4; c3=4; c2=4; c1=4; c0=6;  }
    else if (glyphId==11) { c6=12;c5=4; c4=4; c3=4; c2=4; c1=4; c0=12; }
    else if (glyphId==12) { c6=16;c5=16;c4=30;c3=17;c2=17;c1=17;c0=30; }
    else if (glyphId==13) { c6=17;c5=17;c4=17;c3=15;c2=1; c1=17;c0=14; }
    else if (glyphId==14) { c6=4; c5=4; c4=14;c3=4; c2=4; c1=4; c0=3;  }
    else if (glyphId==15) { c6=0; c5=0; c4=14;c3=17;c2=31;c1=16;c0=14; }
    else if (glyphId==16) { c6=0; c5=0; c4=14;c3=1; c2=15;c1=17;c0=15; }
    else if (glyphId==17) { c6=0; c5=0; c4=26;c3=21;c2=21;c1=21;c0=21; }
    else { c6=0;c5=0;c4=0;c3=0;c2=0;c1=0;c0=0; }
    int rowMask;
    if      (row==0) rowMask=c0; else if (row==1) rowMask=c1;
    else if (row==2) rowMask=c2; else if (row==3) rowMask=c3;
    else if (row==4) rowMask=c4; else if (row==5) rowMask=c5;
    else             rowMask=c6;
    return float((rowMask >> (4-col)) & 1);
}

float introRenderGlyph(vec2 uv, vec2 center, float gw, float gh, int glyphId) {
    vec2 local = (uv - (center - vec2(gw,gh)*0.5)) / vec2(gw,gh);

    #if DC_INTRO_FONT_STYLE == 1
        if (local.x<0.0||local.x>1.0||local.y<0.0||local.y>1.0) return 0.0;
        return pixelChar(local, glyphId);
    #else
        #if DC_INTRO_FONT_STYLE == 4
            if (local.x<-0.2||local.x>1.2||local.y<-0.05||local.y>1.05) return 0.0;
            local.x -= (local.y - 0.5) * 0.22;
        #else
            if (local.x<-0.05||local.x>1.05||local.y<-0.05||local.y>1.05) return 0.0;
        #endif
        local = clamp(local, 0.0, 1.0);
        #if DC_INTRO_FONT_STYLE == 2
            float h = 0.028;
        #elif DC_INTRO_FONT_STYLE == 3
            float h = 0.11;
        #else
            float h = 0.055;
        #endif
        if (glyphId==0)  return letter_D(local,h);
        if (glyphId==1)  return letter_E(local,h);
        if (glyphId==2)  return letter_R(local,h);
        if (glyphId==3)  return letter_C(local,h);
        if (glyphId==4)  return letter_O(local,h);
        if (glyphId==5)  return letter_L(local,h);
        if (glyphId==6)  return letter_I(local,h);
        if (glyphId==7)  return letter_T(local,h);
        if (glyphId==8)  return digit_2(local,h);
        if (glyphId==9)  return char_dot(local,h);
        if (glyphId==10) return char_lbracket(local,h);
        if (glyphId==11) return char_rbracket(local,h);
        if (glyphId==12) return letter_b(local,h);
        if (glyphId==13) return letter_y(local,h);
        if (glyphId==14) return letter_t_sm(local,h);
        if (glyphId==15) return letter_e_sm(local,h);
        if (glyphId==16) return letter_a_sm(local,h);
        if (glyphId==17) return letter_m_sm(local,h);
        return 0.0;
    #endif
}

// Маски текста для DC_INTRO стилей 5–8 (DERCODE 2.0 [LITE])
vec2 introTextMask(vec2 uv, vec2 offset) {
    vec2 uvS = uv - offset;
    float gw1=0.036, gh1=0.060, gap1=0.042, gap1n=0.022, rowY1=0.52;
    float bx=0.195, adv=gap1, adv_n=gap1n;

    float m1=0.0;
    m1 += introRenderGlyph(uvS, vec2(bx+adv*0.0, rowY1), gw1, gh1, 0); // D
    m1 += introRenderGlyph(uvS, vec2(bx+adv*1.0, rowY1), gw1, gh1, 1); // E
    m1 += introRenderGlyph(uvS, vec2(bx+adv*2.0, rowY1), gw1, gh1, 2); // R
    m1 += introRenderGlyph(uvS, vec2(bx+adv*3.0, rowY1), gw1, gh1, 3); // C
    m1 += introRenderGlyph(uvS, vec2(bx+adv*4.0, rowY1), gw1, gh1, 4); // O
    m1 += introRenderGlyph(uvS, vec2(bx+adv*5.0, rowY1), gw1, gh1, 0); // D
    m1 += introRenderGlyph(uvS, vec2(bx+adv*6.0, rowY1), gw1, gh1, 1); // E
    float x_2   = bx + adv * 7.2;
    m1 += introRenderGlyph(uvS, vec2(x_2,         rowY1), gw1,       gh1, 8); // 2
    float x_dot = x_2 + adv_n * 1.4;
    m1 += introRenderGlyph(uvS, vec2(x_dot,       rowY1), gw1*0.5,   gh1, 9); // .
    float x_0   = x_dot + adv_n * 1.2;
    m1 += introRenderGlyph(uvS, vec2(x_0,         rowY1), gw1,       gh1, 4); // 0
    float x_lb  = x_0 + adv * 1.4;
    m1 += introRenderGlyph(uvS, vec2(x_lb,        rowY1), gw1*0.6,   gh1, 10); // [
    float x_L   = x_lb + adv_n * 1.5;
    m1 += introRenderGlyph(uvS, vec2(x_L,         rowY1), gw1,       gh1, 5);  // L
    float x_I   = x_L + adv * 0.8;
    m1 += introRenderGlyph(uvS, vec2(x_I,         rowY1), gw1*0.55,  gh1, 6);  // I
    float x_T   = x_I + adv * 0.7;
    m1 += introRenderGlyph(uvS, vec2(x_T,         rowY1), gw1,       gh1, 7);  // T
    float x_E2  = x_T + adv;
    m1 += introRenderGlyph(uvS, vec2(x_E2,        rowY1), gw1,       gh1, 1);  // E
    float x_rb  = x_E2 + adv * 0.9;
    m1 += introRenderGlyph(uvS, vec2(x_rb,        rowY1), gw1*0.6,   gh1, 11); // ]
    m1 = clamp(m1, 0.0, 1.0);

    float gw2=0.026, gh2=0.042, gap2=0.030, rowY2=0.445;
    float bx2=0.305;
    float m2=0.0;
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*0.0, rowY2), gw2, gh2, 12); // b
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*1.1, rowY2), gw2, gh2, 13); // y
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*2.5, rowY2), gw2, gh2, 0);  // D
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*3.5, rowY2), gw2, gh2, 1);  // E
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*4.5, rowY2), gw2, gh2, 2);  // R
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*6.0, rowY2), gw2, gh2, 14); // t
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*7.0, rowY2), gw2, gh2, 15); // e
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*8.0, rowY2), gw2, gh2, 16); // a
    m2 += introRenderGlyph(uvS, vec2(bx2+gap2*9.0, rowY2), gw2, gh2, 17); // m
    m2 = clamp(m2, 0.0, 1.0);

    return vec2(m1, m2);
}

// ============================================================
// DC_INTRO главная функция
// ============================================================

vec3 drawAxonIntro(vec2 uv, vec3 baseColor) {
    #if DC_INTRO == 0
        return baseColor;
    #endif

    float t         = frameTimeCounter;
    float totalTime = DC_INTRO_IN + DC_INTRO_HOLD + DC_INTRO_OUT;
    if (t > totalTime) return baseColor;

    // --------------------------------------------------------
    // СТИЛИ 1–4: PNG-оверлей из colortex21/22/23/24
    // --------------------------------------------------------
    #if DC_INTRO_STYLE >= 1 && DC_INTRO_STYLE <= 4
    {
        float halfW = DC_INTRO_W * 0.5;
        float alpha = 1.0;
        float centerX;

        if (t < DC_INTRO_IN) {
            float p    = t / DC_INTRO_IN;
            float ease = 1.0 - pow(1.0 - p, 3.0);
            centerX = mix(-halfW, 0.5, ease);
        } else if (t < DC_INTRO_IN + DC_INTRO_HOLD) {
            centerX = 0.5;
        } else {
            float p    = (t - DC_INTRO_IN - DC_INTRO_HOLD) / DC_INTRO_OUT;
            float ease = p * p * p;
            centerX = mix(0.5, 1.5 + halfW, ease);
            alpha   = 1.0 - p * p;
        }

        float halfH    = DC_INTRO_H * 0.5;
        vec2 introPos  = vec2(centerX - halfW, 0.5 - halfH);
        vec2 introSize = vec2(DC_INTRO_W, DC_INTRO_H);
        vec2 texUV     = (uv - introPos) / introSize;

        if (texUV.x < 0.0 || texUV.x > 1.0 ||
            texUV.y < 0.0 || texUV.y > 1.0) return baseColor;

        vec2 finalTexUV = vec2(texUV.x, 1.0 - texUV.y);
        vec4 introSample;
        #if DC_INTRO_STYLE == 1
            introSample = texture(colortex21, finalTexUV);
        #elif DC_INTRO_STYLE == 2
            introSample = texture(colortex22, finalTexUV);
        #elif DC_INTRO_STYLE == 3
            introSample = texture(colortex23, finalTexUV);
        #elif DC_INTRO_STYLE == 4
            introSample = texture(colortex24, finalTexUV);
        #endif

        return mix(baseColor, introSample.rgb, introSample.a * alpha);
    }

    // --------------------------------------------------------
    // СТИЛЬ 5: зелёный текст + тёмный фон (splash style 0)
    // --------------------------------------------------------
    #elif DC_INTRO_STYLE == 5
    {
        float alpha = 0.0;
        vec2  offset = vec2(0.0);
        float hold_end = DC_INTRO_IN + DC_INTRO_HOLD;
        if (t < DC_INTRO_IN) {
            float p = t / DC_INTRO_IN;
            alpha = p * p * (3.0 - 2.0 * p);
        } else if (t < hold_end) {
            alpha = 1.0;
        } else {
            float p = (t - hold_end) / DC_INTRO_OUT;
            alpha = 1.0 - p * p * (3.0 - 2.0 * p);
        }
        if (alpha <= 0.001) return baseColor;

        vec3 textCol1 = vec3(0.40, 1.00, 0.55);
        vec3 textCol2 = vec3(0.25, 0.75, 0.38);
        float flicker = 1.0 - 0.03 * random(vec2(t * 53.1, uv.y * 13.7));
        textCol1 *= flicker; textCol2 *= flicker;

        // Тёмный фон
        vec2 bgCenter = vec2(0.5, 0.485) + offset;
        vec2 bgHalf   = vec2(0.325, 0.105);
        vec2 bgDist   = abs(uv - bgCenter) - bgHalf;
        float bgMask  = 1.0 - smoothstep(0.0, 0.012, max(bgDist.x, bgDist.y));
        baseColor = mix(baseColor, baseColor * 0.07, bgMask * alpha);
        float scan = sin(uv.y * viewHeight * 0.5) * 0.03;
        baseColor -= vec3(scan) * bgMask * alpha * 0.4;

        // Линия
        float lY=0.468; float lX0=0.30; float lX1=0.70;
        if (abs(uv.y-lY)<0.0008 && uv.x>lX0 && uv.x<lX1) {
            float lf = smoothstep(lX0,lX0+0.035,uv.x)*smoothstep(lX1,lX1-0.035,uv.x);
            baseColor = mix(baseColor, mix(textCol2,vec3(0.5),0.3), lf*alpha*0.55);
        }

        vec2 masks = introTextMask(uv, offset);
        float m1=masks.x, m2=masks.y;
        if (m1>0.01) baseColor=mix(baseColor,textCol1,m1*alpha);
        if (m2>0.01) baseColor=mix(baseColor,textCol2,m2*alpha);

        // Курсор
        if (t < 3.0) {
            float blink=step(0.5,fract(t*1.4));
            vec2 cC=vec2(0.732,0.445);
            vec2 cD=abs(uv-cC)-vec2(0.010,0.036)*0.5;
            float cM=1.0-smoothstep(0.0,0.004,max(cD.x,cD.y));
            baseColor=mix(baseColor,textCol2,cM*blink*alpha);
        }
        return baseColor;
    }

    // --------------------------------------------------------
    // СТИЛЬ 6: белый текст + дроп-шедоу (splash style 1)
    // --------------------------------------------------------
    #elif DC_INTRO_STYLE == 6
    {
        float alpha = 0.0;
        vec2  offset = vec2(0.0);
        float hold_end = DC_INTRO_IN + DC_INTRO_HOLD;
        if (t < DC_INTRO_IN) {
            float p = t / DC_INTRO_IN;
            alpha = p * p * (3.0 - 2.0 * p);
        } else if (t < hold_end) {
            alpha = 1.0;
        } else {
            float p = (t - hold_end) / DC_INTRO_OUT;
            alpha = 1.0 - p * p * (3.0 - 2.0 * p);
        }
        if (alpha <= 0.001) return baseColor;

        vec3 textCol1 = vec3(1.0,1.0,1.0);
        vec3 textCol2 = vec3(0.8,0.8,0.8);
        float flicker = 1.0 - 0.03 * random(vec2(t*53.1,uv.y*13.7));
        textCol1*=flicker; textCol2*=flicker;

        float lY=0.468; float lX0=0.30; float lX1=0.70;
        if (abs(uv.y-lY)<0.0008 && uv.x>lX0 && uv.x<lX1) {
            float lf=smoothstep(lX0,lX0+0.035,uv.x)*smoothstep(lX1,lX1-0.035,uv.x);
            baseColor=mix(baseColor,mix(textCol2,vec3(0.5),0.3),lf*alpha*0.55);
        }

        vec2 masks = introTextMask(uv, offset);
        float m1=masks.x, m2=masks.y;

        // Дроп-шедоу
        vec2 shOff=vec2(0.003,-0.003);
        vec2 shMasks=introTextMask(uv, offset-shOff);
        baseColor=mix(baseColor,vec3(0.0),(shMasks.x*(1.0-m1)+shMasks.y*(1.0-m2))*alpha*0.65);

        if (m1>0.01) baseColor=mix(baseColor,textCol1,m1*alpha);
        if (m2>0.01) baseColor=mix(baseColor,textCol2,m2*alpha);

        // Курсор
        if (t < 3.0) {
            float blink=step(0.5,fract(t*1.4));
            vec2 cC=vec2(0.732,0.445);
            vec2 cD=abs(uv-cC)-vec2(0.010,0.036)*0.5;
            float cM=1.0-smoothstep(0.0,0.004,max(cD.x,cD.y));
            baseColor=mix(baseColor,textCol2,cM*blink*alpha);
        }
        return baseColor;
    }

    // --------------------------------------------------------
    // СТИЛЬ 7: белый текст, влетает слева (splash style 2)
    // --------------------------------------------------------
    #elif DC_INTRO_STYLE == 7
    {
        float alpha = 0.0;
        vec2  offset = vec2(0.0);
        float hold_end = DC_INTRO_IN + DC_INTRO_HOLD;
        if (t < DC_INTRO_IN) {
            float p = t / DC_INTRO_IN;
            p = p * p * (3.0 - 2.0 * p);
            offset = vec2(mix(-0.8, 0.0, p), 0.0);
            alpha = p;
        } else if (t < hold_end) {
            offset = vec2(0.0); alpha = 1.0;
        } else {
            float p = (t - hold_end) / DC_INTRO_OUT;
            p = p * p * (3.0 - 2.0 * p);
            offset = vec2(mix(0.0, 0.8, p), 0.0);
            alpha  = 1.0 - p;
        }
        if (alpha <= 0.001) return baseColor;

        vec3 textCol1 = vec3(1.0,1.0,1.0);
        vec3 textCol2 = vec3(0.8,0.8,0.8);
        float flicker = 1.0 - 0.03 * random(vec2(t*53.1,uv.y*13.7));
        textCol1*=flicker; textCol2*=flicker;

        // Полупрозрачный фон
        vec2 bgCenter2 = vec2(0.5,0.485)+offset;
        vec2 bgHalf    = vec2(0.345,0.105);
        vec2 bgDist    = abs(uv-bgCenter2)-bgHalf;
        float bgMask   = 1.0-smoothstep(0.0,0.012,max(bgDist.x,bgDist.y));
        baseColor=mix(baseColor,baseColor*0.12,bgMask*alpha*0.85);

        float lY=0.468-offset.y; float lX0=0.30-offset.x; float lX1=0.70-offset.x;
        if (abs(uv.y-lY)<0.0008 && uv.x>lX0 && uv.x<lX1) {
            float lf=smoothstep(lX0,lX0+0.035,uv.x)*smoothstep(lX1,lX1-0.035,uv.x);
            baseColor=mix(baseColor,mix(textCol2,vec3(0.5),0.3),lf*alpha*0.55);
        }

        vec2 masks=introTextMask(uv,offset);
        float m1=masks.x, m2=masks.y;
        if (m1>0.01) baseColor=mix(baseColor,textCol1,m1*alpha);
        if (m2>0.01) baseColor=mix(baseColor,textCol2,m2*alpha);
        return baseColor;
    }

    // --------------------------------------------------------
    // СТИЛЬ 8: белый текст, следит за камерой (splash style 3)
    // --------------------------------------------------------
    #elif DC_INTRO_STYLE == 8
    {
        float alpha = 0.0;
        vec2  offset = vec2(0.0);
        float hold_end = DC_INTRO_IN + DC_INTRO_HOLD;
        if (t < DC_INTRO_IN) {
            float p = t / DC_INTRO_IN;
            alpha = p * p * (3.0 - 2.0 * p);
        } else if (t < hold_end) {
            alpha = 1.0;
        } else {
            float p = (t - hold_end) / DC_INTRO_OUT;
            alpha = 1.0 - p * p * (3.0 - 2.0 * p);
        }
        if (alpha <= 0.001) return baseColor;

        float followStrength = 0.018;
        vec2 camXZ = vec2(cameraSpeed.x, cameraSpeed.z);
        float camLen = length(camXZ);
        if (camLen > 0.001)
            offset = -normalize(camXZ).xy * min(camLen * followStrength, 0.06);
        else
            offset = vec2(0.0);

        vec3 textCol1 = vec3(1.0,1.0,1.0);
        vec3 textCol2 = vec3(0.8,0.8,0.8);
        float flicker = 1.0 - 0.03 * random(vec2(t*53.1,uv.y*13.7));
        textCol1*=flicker; textCol2*=flicker;

        float lY=0.468-offset.y; float lX0=0.30-offset.x; float lX1=0.70-offset.x;
        if (abs(uv.y-lY)<0.0008 && uv.x>lX0 && uv.x<lX1) {
            float lf=smoothstep(lX0,lX0+0.035,uv.x)*smoothstep(lX1,lX1-0.035,uv.x);
            baseColor=mix(baseColor,mix(textCol2,vec3(0.5),0.3),lf*alpha*0.55);
        }

        vec2 masks=introTextMask(uv,offset);
        float m1=masks.x, m2=masks.y;

        // Дроп-шедоу
        vec2 shOff=vec2(0.003,-0.003);
        vec2 shMasks=introTextMask(uv,offset-shOff);
        baseColor=mix(baseColor,vec3(0.0),(shMasks.x*(1.0-m1)+shMasks.y*(1.0-m2))*alpha*0.65);

        if (m1>0.01) baseColor=mix(baseColor,textCol1,m1*alpha);
        if (m2>0.01) baseColor=mix(baseColor,textCol2,m2*alpha);
        return baseColor;
    }

    #endif // DC_INTRO_STYLE

    return baseColor;
}

// ============================================================
// LUMINANCE HELPERS + TAA
// ============================================================

float taaLuma(vec3 c) { return dot(c, vec3(0.2126, 0.7152, 0.0722)); }

vec3 sampleHistoryCatmullRom(sampler2D tex, vec2 uv) {
    #if TAA_SAMPLE_CATMULL_ROM == 0
        return texture2D(tex, uv).rgb;
    #endif
    vec2 texelSize = 1.0 / vec2(viewWidth, viewHeight);
    vec2 pos = uv / texelSize - 0.5;
    vec2 f   = fract(pos);
    vec2 p   = (floor(pos) + 0.5) * texelSize;
    float fx=f.x, fy=f.y;
    vec4 wx, wy;
    wx.x=-0.5*fx*fx*fx+fx*fx-0.5*fx; wx.y=1.5*fx*fx*fx-2.5*fx*fx+1.0;
    wx.z=-1.5*fx*fx*fx+2.0*fx*fx+0.5*fx; wx.w=0.5*fx*fx*fx-0.5*fx*fx;
    wy.x=-0.5*fy*fy*fy+fy*fy-0.5*fy; wy.y=1.5*fy*fy*fy-2.5*fy*fy+1.0;
    wy.z=-1.5*fy*fy*fy+2.0*fy*fy+0.5*fy; wy.w=0.5*fy*fy*fy-0.5*fy*fy;
    vec3 col = vec3(0.0);
    col += texture2D(tex, p+vec2(-1.0,-1.0)*texelSize).rgb*(wx.x*wy.x);
    col += texture2D(tex, p+vec2( 0.0,-1.0)*texelSize).rgb*(wx.y*wy.x);
    col += texture2D(tex, p+vec2( 1.0,-1.0)*texelSize).rgb*(wx.z*wy.x);
    col += texture2D(tex, p+vec2(-1.0, 0.0)*texelSize).rgb*(wx.x*wy.y);
    col += texture2D(tex, p+vec2( 0.0, 0.0)*texelSize).rgb*(wx.y*wy.y);
    col += texture2D(tex, p+vec2( 1.0, 0.0)*texelSize).rgb*(wx.z*wy.y);
    col += texture2D(tex, p+vec2(-1.0, 1.0)*texelSize).rgb*(wx.x*wy.z);
    col += texture2D(tex, p+vec2( 0.0, 1.0)*texelSize).rgb*(wx.y*wy.z);
    col += texture2D(tex, p+vec2( 1.0, 1.0)*texelSize).rgb*(wx.z*wy.z);
    return max(col, vec3(0.0));
}

vec3 clipToAABB(vec3 history, vec3 boxMin, vec3 boxMax) {
    vec3 p_clip = 0.5*(boxMax+boxMin);
    vec3 e_clip = 0.5*(boxMax-boxMin)+TAA_CLAMP_MARGIN;
    vec3 v_clip = history-p_clip;
    vec3 v_unit = v_clip/e_clip;
    vec3 a_unit = abs(v_unit);
    float ma = max(a_unit.x,max(a_unit.y,a_unit.z));
    return (ma>1.0) ? p_clip+v_clip/ma : history;
}

void gatherNeighbourhood(vec2 texcoord, out vec3 boxMin, out vec3 boxMax, out vec3 mean, out vec3 variance) {
    vec2 ts = 1.0/vec2(viewWidth,viewHeight);
    boxMin=vec3(1e9); boxMax=vec3(-1e9); mean=vec3(0.0); variance=vec3(0.0);
    vec3 s0=texture2D(colortex3,texcoord).rgb;
    vec3 s1=texture2D(colortex3,texcoord+vec2(ts.x,0.0)).rgb;
    vec3 s2=texture2D(colortex3,texcoord+vec2(-ts.x,0.0)).rgb;
    vec3 s3=texture2D(colortex3,texcoord+vec2(0.0,ts.y)).rgb;
    vec3 s4=texture2D(colortex3,texcoord+vec2(0.0,-ts.y)).rgb;
    boxMin=min(s0,min(s1,min(s2,min(s3,s4))));
    boxMax=max(s0,max(s1,max(s2,max(s3,s4))));
    mean=(s0+s1+s2+s3+s4)*0.2;
    variance=(s0*s0+s1*s1+s2*s2+s3*s3+s4*s4)*0.2-mean*mean;
    #if TAA_NEIGHBOR_SAMPLES == 9
        vec3 d0=texture2D(colortex3,texcoord+vec2(ts.x,ts.y)).rgb;
        vec3 d1=texture2D(colortex3,texcoord+vec2(-ts.x,ts.y)).rgb;
        vec3 d2=texture2D(colortex3,texcoord+vec2(ts.x,-ts.y)).rgb;
        vec3 d3=texture2D(colortex3,texcoord+vec2(-ts.x,-ts.y)).rgb;
        boxMin=min(boxMin,min(d0,min(d1,min(d2,d3))));
        boxMax=max(boxMax,max(d0,max(d1,max(d2,d3))));
        vec3 mean9=mean*(5.0/9.0)+(d0+d1+d2+d3)*(1.0/9.0);
        variance=abs(variance-(mean9-mean)*mean9);
        mean=mean9;
    #endif
}

vec2 reprojectCoord(vec2 texcoord) {
    #if TAA_VELOCITY_ENABLED == 1
        vec4 clipPos=vec4(texcoord*2.0-1.0,texture2D(depthtex0,texcoord).r*2.0-1.0,1.0);
        vec4 viewPos=gbufferProjectionInverse*clipPos;
        viewPos/=viewPos.w;
        vec3 cameraDelta=cameraPosition-previousCameraPosition;
        vec3 prevViewPos=viewPos.xyz+cameraDelta;
        vec4 prevClip=gbufferProjection*vec4(prevViewPos,1.0);
        return (prevClip.xy/prevClip.w)*0.5+0.5;
    #else
        return texcoord;
    #endif
}

vec3 applyTAA(vec2 texcoord, vec3 currentColor, float depth) {
    #if TAA_ENABLED == 0
        return currentColor;
    #endif
    if (depth >= 0.9999) return currentColor;
    vec2 prevUV = reprojectCoord(texcoord);
    if (prevUV.x<0.0||prevUV.x>1.0||prevUV.y<0.0||prevUV.y>1.0) return currentColor;
    vec3 historyColor = sampleHistoryCatmullRom(colortex5, prevUV);
    vec3 boxMin,boxMax,mean,variance;
    gatherNeighbourhood(texcoord,boxMin,boxMax,mean,variance);
    #if TAA_VARIANCE_CLIP == 1
        vec3 sigma=sqrt(max(variance,vec3(0.0)))*TAA_VARIANCE_GAMMA;
        historyColor=clipToAABB(historyColor,mean-sigma,mean+sigma);
    #elif TAA_CLAMP_ENABLED == 1
        historyColor=clipToAABB(historyColor,boxMin,boxMax);
    #endif
    float blendFactor=TAA_BLEND_FACTOR;
    #if TAA_LUMA_WEIGHT == 1
        float lumaH=taaLuma(historyColor); float lumaC=taaLuma(currentColor);
        float lumaDiff=abs(lumaH-lumaC)/max(max(lumaH,lumaC),0.001);
        blendFactor=mix(TAA_BLEND_FACTOR,0.45,lumaDiff*lumaDiff);
    #endif
    float distanceBlocks=getLinearDepth(depth);
    float distanceFactor=smoothstep(DLSS_DISTANCE_START,DLSS_DISTANCE_END,distanceBlocks);
    float maxBlend=mix(TAA_MAX_BLEND*0.6,TAA_MAX_BLEND,distanceFactor);
    blendFactor=clamp(blendFactor,1.0-maxBlend,1.0);
    vec3 result=mix(historyColor,currentColor,blendFactor);
    #if TAA_SHARPENING == 1
    {
        vec2 ts=1.0/vec2(viewWidth,viewHeight);
        vec3 up=texture2D(colortex3,texcoord+vec2(0.0,ts.y)).rgb;
        vec3 down=texture2D(colortex3,texcoord+vec2(0.0,-ts.y)).rgb;
        vec3 left=texture2D(colortex3,texcoord+vec2(-ts.x,0.0)).rgb;
        vec3 right=texture2D(colortex3,texcoord+vec2(ts.x,0.0)).rgb;
        #if TAA_SHARPNESS_STYLE == 0
            vec3 sharp=result-(up+down+left+right-4.0*result)*TAA_SHARPNESS*0.25;
        #elif TAA_SHARPNESS_STYLE == 1
            vec3 mnC=min(result,min(up,min(down,min(left,right))));
            vec3 mxC=max(result,max(up,max(down,max(left,right))));
            vec3 wt=sqrt(min(mnC,vec3(1.0)-mxC)/max(mxC,vec3(1e-6)));
            vec3 sharp=(result+(up+down+left+right)*wt*(-0.125))/(1.0+4.0*wt*(-0.125));
        #else
            vec3 blur=(up+down+left+right)*0.25;
            vec3 sharp=result+(result-blur)*TAA_SHARPNESS;
        #endif
        float sf=mix(0.2,0.7,distanceFactor)*TAA_SHARPNESS;
        result=mix(result,sharp,sf);
    }
    #endif
    return max(result,vec3(0.0));
}

// ============================================================
// DLSS-like
// ============================================================

vec3 dlssEdgeSharpen(vec2 texcoord, vec3 color, float strength) {
    #if DLSS_EDGE_SHARPEN == 0
        return color;
    #endif
    vec2 ts=1.0/vec2(viewWidth,viewHeight);
    vec3 n=texture2D(colortex3,texcoord+vec2(0.0,ts.y)).rgb;
    vec3 s=texture2D(colortex3,texcoord+vec2(0.0,-ts.y)).rgb;
    vec3 e=texture2D(colortex3,texcoord+vec2(ts.x,0.0)).rgb;
    vec3 w=texture2D(colortex3,texcoord+vec2(-ts.x,0.0)).rgb;
    vec3 lum=vec3(0.2126,0.7152,0.0722);
    float edgeMag=(abs(dot(n-color,lum))+abs(dot(s-color,lum))+abs(dot(e-color,lum))+abs(dot(w-color,lum)))*0.25;
    float edgeMask=smoothstep(0.0,DLSS_EDGE_THRESHOLD,edgeMag);
    vec3 unsharp=(n+s+e+w)*0.25;
    vec3 sharp=color+(color-unsharp)*strength;
    return mix(color,sharp,edgeMask);
}

vec3 adaptiveResolutionSample(vec2 texcoord, float depth) {
    float distanceBlocks=getLinearDepth(depth);
    float distanceFactor=smoothstep(DLSS_DISTANCE_START,DLSS_DISTANCE_END,distanceBlocks);
    float scaleFactor;
    #if DLSS_QUALITY == 0
        scaleFactor=mix(1.0,0.50,distanceFactor);
    #elif DLSS_QUALITY == 1
        scaleFactor=mix(1.0,0.67,distanceFactor);
    #elif DLSS_QUALITY == 2
        scaleFactor=mix(1.0,0.77,distanceFactor);
    #elif DLSS_QUALITY == 3
        scaleFactor=mix(1.0,0.88,distanceFactor);
    #else
        scaleFactor=1.0;
    #endif
    vec2 texelSize=1.0/vec2(viewWidth,viewHeight);
    vec2 scaledTexelSize=texelSize/max(scaleFactor,0.1);
    vec3 color=bicubicSample(colortex3,texcoord,scaledTexelSize);
    color=dlssEdgeSharpen(texcoord,color,DLSS_SHARPNESS*distanceFactor);
    #if DLSS_DEBUG_DISTANCE == 1
        color=mix(vec3(0.0,0.3,1.0),vec3(1.0,0.1,0.0),distanceFactor);
    #endif
    return color;
}

vec3 applyDLSSLike(vec2 texcoord, vec3 color) {
    #if DLSS_LIKE_ENABLED == 0
        return color;
    #endif
    float depth=texture2D(depthtex0,texcoord).r;
    if (depth>=0.9999) return color;
    return applyTAA(texcoord,adaptiveResolutionSample(texcoord,depth),depth);
}

// ============================================================
// DYNAMIC VIGNETTE
// ============================================================

float applyDynamicVignette(vec2 coord, vec2 centered) {
    #if DYNAMIC_VIGNETTE == 0
        return 0.0;
    #endif
    float distance_=length(centered);
    float baseVignette=smoothstep(VIGNETTE_RADIUS_NEW,VIGNETTE_RADIUS_NEW+VIGNETTE_STRENGTH_NEW,distance_);
    #if DYNAMIC_VIGNETTE_SWAY == 1
        float cameraMotion=length(cameraSpeed.xz);
        float verticalMotion=abs(cameraSpeed.y);
        float totalMotion=clamp((cameraMotion+verticalMotion*0.5)*0.1,0.0,1.0);
        vec2 motionDir=normalize(vec2(cameraSpeed.x,-cameraSpeed.z)+vec2(0.001));
        float tiltEffect=dot(normalize(centered),motionDir)*0.5+0.5;
        float dynamicBoost=totalMotion*DYNAMIC_VIGNETTE_STRENGTH;
        float tiltBoost=tiltEffect*DYNAMIC_VIGNETTE_TILT*totalMotion;
        baseVignette+=dynamicBoost*distance_;
        baseVignette+=tiltBoost*0.3;
        baseVignette+=sin(frameTimeCounter*10.0*totalMotion)*0.05*totalMotion;
    #endif
    return clamp(baseVignette,0.0,1.0);
}

float applyCubicVignette(vec2 coord) {
    #if CUBIC_VIGNETTE_ENABLED == 1
    vec2 centered=abs(coord-0.5);
    float vertical=pow(centered.y,3.0);
    float corner=length(centered)*0.2;
    return clamp(vertical+corner,0.0,1.0)*CUBIC_VIGNETTE_STRENGTH;
    #else
    return 0.0;
    #endif
}

// ============================================================
// EYE IMITATION
// ============================================================

vec3 applyEyeImitation(vec2 texcoord, vec3 color) {
#if EYE_SQUINT_ENABLED == 1
    float bottom = 0.0;
    float top    = 0.0;
    float bottomplus = 0.0;
    float topplus    = 0.0;

    bottom = EYE_SQUINT_OFFSET;
    top    = EYE_SQUINT_OFFSET;

    bottomplus = mix(bottom, EYE_SQUINT_HEIGHT_PIXELS * 0.01 + EYE_SQUINT_OFFSET, sneakSmooth);
    topplus    = mix(top,    EYE_SQUINT_HEIGHT_PIXELS * 0.01 + EYE_SQUINT_OFFSET, sneakSmooth);

    float softness = max(EYE_SQUINT_SOFTNESS * 0.001, 0.001);

    float bottombandfade = clamp((texcoord.y - bottomplus) / softness, 0.0, 1.0);
    float topbandfade    = clamp((1.0 - texcoord.y - topplus) / softness, 0.0, 1.0);

    if (bottomplus < 0.001) bottombandfade = 1.0;
    if (topplus    < 0.001) topbandfade    = 1.0;

    color.rgb = mix(vec3(0.0), color.rgb, bottombandfade * topbandfade);
#endif
    return color;
}

// ============================================================
// CHROMATIC ABERRATION
// ============================================================

vec3 applyChromaticAberration(vec2 uv, vec3 color) {
    #if (CHROMATIC_ABERRATION_ENABLED == 1 && BODYCAM_ENABLED == 0)
        vec2 coord=uv-0.5;
        float dist=length(coord);
        float fovMask=mix(dist*2.3,1.0,CHROMATIC_ABERRATION_CENTER);
        float amount=CHROMATIC_ABERRATION_STRENGTH*fovMask;
        vec2 offset=coord*amount;
        #if CHROMATIC_ABERRATION_STYLE == 1
            color.r=texture2D(colortex3,uv+offset).r;
            color.g=texture2D(colortex3,uv).g;
            color.b=texture2D(colortex3,uv-offset).b;
        #elif CHROMATIC_ABERRATION_STYLE == 2
            color.r=texture2D(colortex3,uv+offset*1.7).r;
            color.g=texture2D(colortex3,uv-offset*0.4).g;
            color.b=texture2D(colortex3,uv-offset*0.7).b;
        #elif CHROMATIC_ABERRATION_STYLE == 3
            float hue=frameTimeCounter*0.9*0.3;
            vec3 rainbow=0.5+0.5*cos(hue+vec3(0.0,2.094,4.188));
            color.r=texture2D(colortex3,uv+offset*(0.8+0.6*rainbow.r)).r;
            color.g=texture2D(colortex3,uv+offset*(0.8+0.6*rainbow.g)*vec2(1.0,-0.7)).g;
            color.b=texture2D(colortex3,uv-offset*(0.8+0.6*rainbow.b)*vec2(0.8,1.1)).b;
        #elif CHROMATIC_ABERRATION_STYLE == 4
            color.r=texture2D(colortex3,uv).r;
            color.g=texture2D(colortex3,uv+offset*0.9).g;
            color.b=texture2D(colortex3,uv-offset*1.3).b;
        #endif
    #endif
    return color;
}

// ============================================================
// PS1 STYLE
// ============================================================

vec3 applyPS1Style(vec2 coord, vec3 color) {
    #if PS1_STYLE_ENABLED == 1
    vec2 lowResCoord=floor(coord*vec2(viewWidth,viewHeight)/4.0)*4.0/vec2(viewWidth,viewHeight);
    vec3 lowResColor=texture2D(colortex3,lowResCoord).rgb;
    float dither=bayer16(gl_FragCoord.xy)*0.05*PS1_STYLE_INTENSITY;
    return mix(color,lowResColor+dither,PS1_STYLE_INTENSITY);
    #else
    return color;
    #endif
}

// ============================================================
// MOTION BLUR
// ============================================================

vec3 motionBlurTest(vec2 coord, vec3 color) {
    vec2 centered=coord-0.5;
    float r=length(centered);
    float blur_mask=1.0-smoothstep(MOTION_BLUR_RADIUS*0.8,MOTION_BLUR_RADIUS,r);
    if (blur_mask<=0.0) return color;
    vec2 blur_dir=vec2(cos(frameTimeCounter*2.0),sin(frameTimeCounter*2.0))*MOTION_BLUR_STRENGTH;
    vec3 blurred_color=vec3(0.0);
    const int samples=5;
    for (int i=-samples/2;i<=samples/2;i++)
        blurred_color+=texture2D(colortex3,coord+blur_dir*float(i)/float(samples/2)).rgb;
    return mix(color,blurred_color/float(samples),blur_mask);
}

vec3 motionBlurMouse(vec2 coord, vec3 color) {
    #ifdef USE_MOUSE_DELTA
    vec2 motion=mouseDelta;
    #else
    vec2 motion=vec2(viewDir.x,viewDir.y)*sin(frameTimeCounter*0.5)*0.01;
    #endif
    float motion_magnitude=length(motion);
    if (motion_magnitude<0.0001) return color;
    vec2 blur_dir=normalize(motion)*MOTION_BLUR_MOUSE_STRENGTH*motion_magnitude;
    vec3 blurred_color=vec3(0.0);
    const int samples=7;
    for (int i=-samples/2;i<=samples/2;i++)
        blurred_color+=texture2D(colortex3,coord+blur_dir*float(i)/float(samples/2)).rgb;
    return mix(color,blurred_color/float(samples),clamp(motion_magnitude*10.0,0.0,1.0));
}

// ============================================================
// IMAGE OVERLAY
// ============================================================

vec3 drawImage(vec2 coord, vec3 base_color) {
    #ifdef USE_PNG_TEXTURE
    vec2 image_size=vec2(0.2,0.2*(float(textureSize(texture,0).y)/float(textureSize(texture,0).x)));
    vec2 image_pos;
    if (IMAGE_POSITION==0) image_pos=vec2(1.0-image_size.x-0.02,0.02);
    else                   image_pos=vec2(0.02,0.02);
    if (coord.x>=image_pos.x && coord.x<=image_pos.x+image_size.x &&
        coord.y>=image_pos.y && coord.y<=image_pos.y+image_size.y) {
        vec2 tex_coord=lensDistortion((coord-image_pos)/image_size);
        vec4 image_color=texture2D(texture,tex_coord);
        float flicker=(random(tex_coord+vec2(frameTimeCounter))*2.0-1.0)*FLICKER_STRENGTH;
        image_color.rgb*=(1.0+flicker);
        return mix(base_color,image_color.rgb,image_color.a);
    }
    #endif
    return base_color;
}

// ============================================================
// LENS FLARE
// ============================================================

float clamp01(float x) { return clamp(x,0.0,1.0); }
float fovmult=gbufferProjection[1][1]/1.37373871;

float BaseLens(vec2 texcoord,vec2 lightPos,float size,float dist,float hardness){
    vec2 lensCoord=(texcoord+(lightPos*dist-0.5))*vec2(aspectRatio,1.0);
    float lens=clamp(1.0-length(lensCoord)/(size*fovmult),0.0,1.0/hardness)*hardness;
    lens*=lens;lens*=lens;return lens;
}
float OverlapLens(vec2 tc,vec2 lp,float sz,float da,float db){
    return BaseLens(tc,lp,sz,da,2.0)*BaseLens(tc,lp,sz,db,2.0);
}
float PointLens(vec2 tc,vec2 lp,float sz,float dist){
    return BaseLens(tc,lp,sz,dist,1.5)+BaseLens(tc,lp,sz*4.0,dist,1.0)*0.5;
}
float RingLensTransform(float lf){
    return pow(1.0-pow(1.0-pow(lf,0.25),10.0),5.0);
}
float RingLens(vec2 tc,vec2 lp,float sz,float dA,float dB){
    float lf=clamp01(RingLensTransform(BaseLens(tc,lp,sz,dB,1.0))-RingLensTransform(BaseLens(tc,lp,sz,dA,1.0)));
    return lf*sqrt(lf);
}
float AnamorphicLens(vec2 tc,vec2 lp,float sz,float dist){
    vec2 lc=abs(tc+(lp*dist-0.5))*vec2(aspectRatio*0.07,2.0);
    float lens=clamp01(1.0-length(pow(lc/(sz*fovmult),vec2(0.85)))*4.0);
    return lens*lens*lens;
}
vec3 RainbowLens(vec2 tc,vec2 lp,float sz,float dist,float rad){
    vec2 lc=(tc+(lp*dist-0.5))*vec2(aspectRatio,1.0);
    float lens=clamp01(1.0-length(lc)/(sz*fovmult));
    return (smoothstep(0.0,rad,lens)-smoothstep(rad,rad*2.0,lens))*vec3(1.0,0.0,0.0)
          +(smoothstep(rad*0.5,rad*1.5,lens)-smoothstep(rad*1.5,rad*2.5,lens))*vec3(0.0,1.0,0.0)
          +(smoothstep(rad,rad*2.0,lens)-smoothstep(rad*2.0,rad*3.0,lens))*vec3(0.0,0.0,1.0);
}
vec3 LensTint(vec3 lens,float truePos){
    float isMoon=truePos*0.5+0.5;
    float visibility=mix(sunVisibility,moonVisibility,isMoon);
    lens=mix(lens,GetLuminance(lens)*lightNight*0.5,isMoon*0.98);
    return lens*visibility;
}
void LensFlare(inout vec3 color,vec2 texcoord,vec2 lightPos,float truePos,float multiplier){
    float falloffBase=length(lightPos*vec2(aspectRatio,1.0));
    float falloffIn=pow(clamp01(falloffBase*10.0),2.0);
    float falloffOut=clamp01(falloffBase*3.0-1.5);
    if (falloffOut<0.999) {
        vec3 lensFlare=(
            BaseLens(texcoord,lightPos,0.3,-0.45,1.0)*vec3(2.2,1.2,0.1)*0.07+
            BaseLens(texcoord,lightPos,0.3, 0.10,1.0)*vec3(2.2,0.4,0.1)*0.03+
            BaseLens(texcoord,lightPos,0.3, 0.30,1.0)*vec3(2.2,0.2,0.1)*0.04+
            BaseLens(texcoord,lightPos,0.3, 0.50,1.0)*vec3(2.2,0.4,2.5)*0.05+
            BaseLens(texcoord,lightPos,0.3, 0.70,1.0)*vec3(1.8,0.4,2.5)*0.06+
            BaseLens(texcoord,lightPos,0.3, 0.95,1.0)*vec3(0.1,0.2,2.5)*0.10+
            BaseLens(texcoord,lightPos,0.3, 1.15,1.0)*vec3(0.08,0.1,2.8)*0.12+
            BaseLens(texcoord,lightPos,0.3, 1.35,1.0)*vec3(0.04,0.1,3.4)*0.14+
            OverlapLens(texcoord,lightPos,0.18,-0.30,-0.41)*vec3(2.5,1.2,0.1)*0.010+
            OverlapLens(texcoord,lightPos,0.16,-0.18,-0.29)*vec3(2.5,0.5,0.1)*0.020+
            OverlapLens(texcoord,lightPos,0.15, 0.06, 0.19)*vec3(2.5,0.2,0.1)*0.015+
            OverlapLens(texcoord,lightPos,0.14, 0.15, 0.28)*vec3(1.8,0.1,1.2)*0.015+
            OverlapLens(texcoord,lightPos,0.16, 0.24, 0.37)*vec3(1.0,0.1,2.5)*0.015+
            PointLens(texcoord,lightPos,0.03,-0.55)*vec3(2.5,1.6,0.0)*0.20+
            PointLens(texcoord,lightPos,0.02,-0.40)*vec3(2.5,1.0,0.0)*0.15+
            PointLens(texcoord,lightPos,0.04, 0.43)*vec3(2.5,0.6,0.6)*0.20+
            PointLens(texcoord,lightPos,0.02, 0.60)*vec3(0.2,0.6,2.5)*0.15+
            PointLens(texcoord,lightPos,0.03, 0.67)*vec3(0.2,1.6,2.5)*0.25+
            PointLens(texcoord,lightPos,0.03, 0.73)*vec3(0.2,1.9,2.5)*0.35+
            RingLens(texcoord,lightPos,0.25,0.43,0.45)*vec3(0.10,0.35,2.50)*1.5+
            RingLens(texcoord,lightPos,0.18,0.98,0.99)*vec3(0.15,1.00,2.55)*2.5+
            RingLens(texcoord,lightPos,0.10,1.32,1.33)*vec3(0.30,1.55,2.85)*1.5
        )*(falloffIn-falloffOut)+(
            AnamorphicLens(texcoord,lightPos,1.0,-1.0)*vec3(0.3,0.7,1.0)*0.35+
            RainbowLens(texcoord,lightPos,0.425,-1.0,0.2)*0.035+
            RainbowLens(texcoord,lightPos,2.0,4.0,0.1)*0.05
        )*(1.0-falloffOut);
        lensFlare=LensTint(lensFlare,truePos);
        color=mix(color,vec3(1.0),lensFlare*multiplier*multiplier);
    }
}

// ============================================================
// VHS EFFECT
// ============================================================

float hash(float n) { return fract(sin(n)*43758.5453); }
vec2 hash2(vec2 p) {
    p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3)));
    return -1.0+2.0*fract(sin(p)*43758.5453123);
}
vec2 vhsDistortion(vec2 uv,float time){
    float wave1=sin(uv.y*8.0+time*2.0)*0.001;
    float wave2=sin(uv.y*15.0+time*3.5)*0.001;
    float glitchLine=floor(uv.y*200.0);
    float glitchRandom=hash(glitchLine+floor(time*5.0));
    float glitchStrength=step(0.98,glitchRandom)*0.02;
    float horizontalShift=glitchStrength*(hash(glitchLine*13.7+time)-0.5);
    return uv+vec2(wave1+wave2+horizontalShift,0.0);
}
vec3 chromaShift(sampler2D tex,vec2 uv,float time){
    float shift=0.002+sin(time*0.5)*0.001;
    return vec3(texture2D(tex,uv+vec2(shift,0.0)).r,
                texture2D(tex,uv).g,
                texture2D(tex,uv-vec2(shift,0.0)).b);
}
float scanlines(vec2 uv){ return 1.0-abs(sin(uv.y*viewHeight*0.7)*0.08); }
float filmGrain(vec2 uv,float time){
    return (random(uv*300.0+time*50.0)-0.5)*0.25;
}
float trackingLines(vec2 uv,float time){
    float speed=time*0.1;
    float t1=abs(uv.y-(fract(speed)*2.0-1.0));
    float t2=abs(uv.y-(fract(speed*0.7+0.3)*2.0-1.0));
    return smoothstep(0.01,0.0,t1)*0.3+smoothstep(0.005,0.0,t2)*0.3;
}
vec3 vhsColor(vec3 color,float time){
    float gray=dot(color,vec3(0.299,0.587,0.114));
    color=mix(color,vec3(gray),0.3);
    color.r*=1.1;color.g*=0.95;color.b*=0.9;
    color=(color-0.5)*1.3+0.6;
    color+=vec3(0.05,0.03,0.0);
    return color;
}
vec3 glitchBlocks(vec3 color,vec2 uv,float time){ return color; }

float drawRect(vec2 uv,vec2 pos,vec2 size){
    vec2 d=abs(uv-pos)-size;
    return 1.0-smoothstep(0.0,0.002,max(d.x,d.y));
}

float drawChar(vec2 uv, vec2 pos, int charCode) {
    vec2 localUV=(uv-pos)/vec2(0.015,0.025);
    if (localUV.x<0.0||localUV.x>1.0||localUV.y<0.0||localUV.y>1.0) return 0.0;
    float pixel=0.0;
    vec2 pixelPos=floor(localUV*vec2(5.0,7.0));
    if (charCode==0){if((pixelPos.x==0.0||pixelPos.x==4.0)&&pixelPos.y>0.0&&pixelPos.y<6.0)pixel=1.0;if((pixelPos.y==0.0||pixelPos.y==6.0)&&pixelPos.x>0.0&&pixelPos.x<4.0)pixel=1.0;}
    else if(charCode==1){if(pixelPos.x==3.0)pixel=1.0;if(pixelPos.x==2.0&&pixelPos.y<1.0)pixel=1.0;if(pixelPos.x==3.0&&pixelPos.y<1.0)pixel=1.0;if(pixelPos.x==4.0&&pixelPos.y<1.0)pixel=1.0;if(pixelPos.y==5.0&&pixelPos.x>=2.0&&pixelPos.x<=3.0)pixel=1.0;}
    else if(charCode==2){if(pixelPos.y==0.0||pixelPos.y==3.0||pixelPos.y==6.0)pixel=1.0;if(pixelPos.x==0.0&&pixelPos.y<3.0)pixel=1.0;if(pixelPos.x==4.0&&pixelPos.y>3.0)pixel=1.0;}
    else if(charCode==3){if(pixelPos.y==0.0||pixelPos.y==3.0||pixelPos.y==6.0)pixel=1.0;if(pixelPos.x==4.0&&pixelPos.y!=3.0)pixel=1.0;}
    else if(charCode==4){if(pixelPos.x==0.0&&pixelPos.y>3.0)pixel=1.0;if(pixelPos.x==4.0)pixel=1.0;if(pixelPos.y==3.0)pixel=1.0;}
    else if(charCode==5){if(pixelPos.y==0.0||pixelPos.y==3.0||pixelPos.y==6.0)pixel=1.0;if(pixelPos.x==0.0&&pixelPos.y>3.0)pixel=1.0;if(pixelPos.x==4.0&&pixelPos.y<3.0)pixel=1.0;}
    else if(charCode==6){if(pixelPos.y==0.0||pixelPos.y==3.0||pixelPos.y==6.0)pixel=1.0;if(pixelPos.x==0.0)pixel=1.0;if(pixelPos.x==4.0&&pixelPos.y<4.0)pixel=1.0;}
    else if(charCode==7){if(pixelPos.y==6.0)pixel=1.0;if(pixelPos.x==4.0)pixel=1.0;}
    else if(charCode==8){if(pixelPos.y==0.0||pixelPos.y==3.0||pixelPos.y==6.0)pixel=1.0;if(pixelPos.x==0.0||pixelPos.x==4.0)pixel=1.0;}
    else if(charCode==9){if(pixelPos.y==0.0||pixelPos.y==3.0||pixelPos.y==6.0)pixel=1.0;if(pixelPos.x==0.0&&pixelPos.y>3.0)pixel=1.0;if(pixelPos.x==4.0)pixel=1.0;}
    else if(charCode==10){if(pixelPos.x==2.0&&(pixelPos.y==2.0||pixelPos.y==4.0))pixel=1.0;}
    else if(charCode==11){if(pixelPos.x==0.0)pixel=1.0;if(pixelPos.y==6.0||pixelPos.y==3.0)pixel=1.0;if(pixelPos.x==2.0&&(pixelPos.y>5.0||pixelPos.y==2.0))pixel=1.0;if(pixelPos.x==3.0&&(pixelPos.y>5.0||pixelPos.y==1.0))pixel=1.0;if(pixelPos.x==4.0&&(pixelPos.y>3.0||pixelPos.y==0.0))pixel=1.0;}
    else if(charCode==12){if(pixelPos.x==0.0)pixel=1.0;if(pixelPos.y==0.0||pixelPos.y==3.0||pixelPos.y==6.0)pixel=1.0;}
    else if(charCode==13){if(pixelPos.x==0.0&&pixelPos.y>0.0&&pixelPos.y<6.0)pixel=1.0;if((pixelPos.y==0.0||pixelPos.y==6.0)&&pixelPos.x>0.0)pixel=1.0;}
    else if(charCode==14){if(pixelPos.x==0.0&&pixelPos.y>0.0&&pixelPos.y<1.0)pixel=1.0;if((pixelPos.y==1.0||pixelPos.y==0.0)&&pixelPos.x>2.0)pixel=1.0;}
    return pixel;
}

vec3 drawVHSUI(vec3 color, vec2 uv, float time) {
    vec3 uiColor=color;
    float ui=0.0;
    #if VHS_LETTERBOX_ORIENTATION == 0
    float letterboxHeight=0.15;
    if (uv.x<0.55&&uv.y>0.85&&uv.y<1.0) {
        ui+=drawChar(uv,vec2(0.17,0.92),11);
        ui+=drawChar(uv,vec2(0.19,0.92),12);
        ui+=drawChar(uv,vec2(0.21,0.92),13);
        float blink=step(0.5,fract(time*0.5));
        if (uv.x>0.235&&uv.x<0.245&&uv.y>0.915&&uv.y<0.925)
            uiColor=mix(uiColor,vec3(1.0,0.0,0.0),blink);
    }
    if (uv.x>0.6&&uv.y>0.85&&uv.y<1.0) {
        float totalSeconds=time+01.0*3600.0+15.0*60.0;
        int hours=int(mod(totalSeconds/3600.0,24.0));
        int minutes=int(mod(totalSeconds/60.0,60.0));
        int hourTens=hours/10; int hourOnes=hours-hourTens*10;
        ui+=drawChar(uv,vec2(0.73,0.92),hourTens); ui+=drawChar(uv,vec2(0.75,0.92),hourOnes);
        ui+=drawChar(uv,vec2(0.77,0.92),10);
        int minuteTens=minutes/10; int minuteOnes=minutes-minuteTens*10;
        ui+=drawChar(uv,vec2(0.79,0.92),minuteTens); ui+=drawChar(uv,vec2(0.81,0.92),minuteOnes);
    }
    if (uv.x<0.55&&uv.y>0.0&&uv.y<letterboxHeight) {
        float daysSinceStart=floor(time/86400.0);
        int currentDay=int(mod(25.0+daysSinceStart,31.0));
        if (currentDay==0) currentDay=31;
        int dayTens=currentDay/10; int dayOnes=currentDay-dayTens*10;
        ui+=drawChar(uv,vec2(0.17,0.08),dayTens); ui+=drawChar(uv,vec2(0.19,0.08),dayOnes);
        ui+=drawChar(uv,vec2(0.21,0.08),14); ui+=drawChar(uv,vec2(0.23,0.08),1);
        ui+=drawChar(uv,vec2(0.25,0.08),2);  ui+=drawChar(uv,vec2(0.27,0.08),14);
        ui+=drawChar(uv,vec2(0.29,0.08),1);  ui+=drawChar(uv,vec2(0.31,0.08),9);
        ui+=drawChar(uv,vec2(0.33,0.08),9);  ui+=drawChar(uv,vec2(0.35,0.08),8);
    }
    if (uv.x>0.6&&uv.y>0.0&&uv.y<letterboxHeight) {
        float recordingTime=time;
        int recordHours=int(recordingTime/3600.0);
        int recordMinutes=int(mod(recordingTime/60.0,60.0));
        int recordSeconds=int(mod(recordingTime,60.0));
        int hourTens=recordHours/10; int hourOnes=recordHours-hourTens*10;
        ui+=drawChar(uv,vec2(0.67,0.08),hourTens); ui+=drawChar(uv,vec2(0.69,0.08),hourOnes);
        ui+=drawChar(uv,vec2(0.71,0.08),10);
        int minuteTens=recordMinutes/10; int minuteOnes=recordMinutes-minuteTens*10;
        ui+=drawChar(uv,vec2(0.73,0.08),minuteTens); ui+=drawChar(uv,vec2(0.75,0.08),minuteOnes);
        ui+=drawChar(uv,vec2(0.77,0.08),10);
        int secondTens=recordSeconds/10; int secondOnes=recordSeconds-secondTens*10;
        ui+=drawChar(uv,vec2(0.79,0.08),secondTens); ui+=drawChar(uv,vec2(0.81,0.08),secondOnes);
    }
    #else
    float letterboxWidth=0.15;
    if (uv.y<0.55&&uv.x>0.85&&uv.x<1.0) {
        ui+=drawChar(uv,vec2(0.92,0.17),11);
        ui+=drawChar(uv,vec2(0.92,0.19),12);
        ui+=drawChar(uv,vec2(0.92,0.21),13);
        float blink=step(0.5,fract(time*0.5));
        if (uv.y>0.235&&uv.y<0.245&&uv.x>0.915&&uv.x<0.925)
            uiColor=mix(uiColor,vec3(1.0,0.0,0.0),blink);
    }
    if (uv.y>0.6&&uv.x>0.85&&uv.x<1.0) {
        float totalSeconds=time+01.0*3600.0+15.0*60.0;
        int hours=int(mod(totalSeconds/3600.0,24.0));
        int minutes=int(mod(totalSeconds/60.0,60.0));
        int hourTens=hours/10; int hourOnes=hours-hourTens*10;
        ui+=drawChar(uv,vec2(0.92,0.73),hourTens); ui+=drawChar(uv,vec2(0.92,0.75),hourOnes);
        ui+=drawChar(uv,vec2(0.92,0.77),10);
        int minuteTens=minutes/10; int minuteOnes=minutes-minuteTens*10;
        ui+=drawChar(uv,vec2(0.92,0.79),minuteTens); ui+=drawChar(uv,vec2(0.92,0.81),minuteOnes);
    }
    if (uv.y<0.55&&uv.x>0.0&&uv.x<letterboxWidth) {
        float daysSinceStart=floor(time/86400.0);
        int currentDay=int(mod(25.0+daysSinceStart,31.0));
        if (currentDay==0) currentDay=31;
        int dayTens=currentDay/10; int dayOnes=currentDay-dayTens*10;
        ui+=drawChar(uv,vec2(0.08,0.17),dayTens); ui+=drawChar(uv,vec2(0.08,0.19),dayOnes);
        ui+=drawChar(uv,vec2(0.08,0.21),14); ui+=drawChar(uv,vec2(0.08,0.23),1);
        ui+=drawChar(uv,vec2(0.08,0.25),2);  ui+=drawChar(uv,vec2(0.08,0.27),14);
        ui+=drawChar(uv,vec2(0.08,0.29),1);  ui+=drawChar(uv,vec2(0.08,0.31),9);
        ui+=drawChar(uv,vec2(0.08,0.33),9);  ui+=drawChar(uv,vec2(0.08,0.35),8);
    }
    if (uv.y>0.6&&uv.x>0.0&&uv.x<letterboxWidth) {
        float recordingTime=time;
        int recordHours=int(recordingTime/3600.0);
        int recordMinutes=int(mod(recordingTime/60.0,60.0));
        int recordSeconds=int(mod(recordingTime,60.0));
        int hourTens=recordHours/10; int hourOnes=recordHours-hourTens*10;
        ui+=drawChar(uv,vec2(0.08,0.67),hourTens); ui+=drawChar(uv,vec2(0.08,0.69),hourOnes);
        ui+=drawChar(uv,vec2(0.08,0.71),10);
        int minuteTens=recordMinutes/10; int minuteOnes=recordMinutes-minuteTens*10;
        ui+=drawChar(uv,vec2(0.08,0.73),minuteTens); ui+=drawChar(uv,vec2(0.08,0.75),minuteOnes);
        ui+=drawChar(uv,vec2(0.08,0.77),10);
        int secondTens=recordSeconds/10; int secondOnes=recordSeconds-secondTens*10;
        ui+=drawChar(uv,vec2(0.08,0.79),secondTens); ui+=drawChar(uv,vec2(0.08,0.81),secondOnes);
    }
    #endif
    if (ui>0.0) uiColor=mix(uiColor,vec3(1.0,1.0,1.0),ui*0.8);
    return uiColor;
}

vec3 vhs_effect(vec2 texcoord, vec3 base_color) {
    float time=frameTimeCounter;
    vec2 uv=texcoord;
    vec3 color=base_color;

    #if VHS_LETTERBOX_ENABLED == 1
    #if VHS_LETTERBOX_ORIENTATION == 0
    float letterboxHeight=0.15;
    bool inLetterbox=(uv.y<letterboxHeight||uv.y>(1.0-letterboxHeight));
    vec2 mainUV=uv;
    if (!inLetterbox) mainUV.y=(uv.y-letterboxHeight)/(1.0-2.0*letterboxHeight);
    if (inLetterbox) {
        color=vec3(0.0);
    } else {
        float glitchLine=floor(mainUV.y*200.0);
        float glitchRandom=hash(glitchLine+floor(time*5.0));
        float glitchStrength=step(0.98,glitchRandom)*0.02;
        float horizontalShift=glitchStrength*(hash(glitchLine*13.7+time)-0.5);
        vec2 distortedUV=mainUV+vec2(horizontalShift,0.0);
        color=chromaShift(colortex3,distortedUV,time);
        if (length(color)<0.05) color=texture2D(colortex3,mainUV).rgb;
        color=glitchBlocks(color,mainUV,time);
        color*=scanlines(mainUV);
        color+=filmGrain(mainUV,time);
        color=vhsColor(color,time);
        vec2 center=mainUV-0.5;
        color*=1.0-dot(center,center)*0.3;
        color=clamp(color,0.0,1.0);
    }
    color=drawVHSUI(color,uv,time);
    #else
    float letterboxWidth=0.15;
    bool inLetterbox=(uv.x<letterboxWidth||uv.x>(1.0-letterboxWidth));
    vec2 mainUV=uv;
    if (!inLetterbox) mainUV.x=(uv.x-letterboxWidth)/(1.0-2.0*letterboxWidth);
    if (inLetterbox) {
        color=vec3(0.0);
    } else {
        float glitchLine=floor(mainUV.y*200.0);
        float glitchRandom=hash(glitchLine+floor(time*5.0));
        float glitchStrength=step(0.98,glitchRandom)*0.02;
        float horizontalShift=glitchStrength*(hash(glitchLine*13.7+time)-0.5);
        vec2 distortedUV=mainUV+vec2(horizontalShift,0.0);
        color=chromaShift(colortex3,distortedUV,time);
        if (length(color)<0.02) color=texture2D(colortex3,mainUV).rgb;
        color=glitchBlocks(color,mainUV,time);
        color*=scanlines(mainUV);
        color+=filmGrain(mainUV,time);
        color=vhsColor(color,time);
        vec2 center=mainUV-0.5;
        color*=1.0-dot(center,center)*0.3;
        color=clamp(color,0.0,1.0);
    }
    color=drawVHSUI(color,uv,time);
    #endif
    #else
    float glitchLine=floor(uv.y*200.0);
    float glitchRandom=hash(glitchLine+floor(time*5.0));
    float glitchStrength=step(0.98,glitchRandom)*0.02;
    float horizontalShift=glitchStrength*(hash(glitchLine*13.7+time)-0.5);
    vec2 distortedUV=uv+vec2(horizontalShift,0.0);
    color=chromaShift(colortex3,distortedUV,time);
    if (length(color)<0.02) color=texture2D(colortex3,uv).rgb;
    color=glitchBlocks(color,uv,time);
    color*=scanlines(uv);
    color+=filmGrain(uv,time);
    color=vhsColor(color,time);
    vec2 center=uv-0.5;
    color*=1.0-dot(center,center)*0.3;
    color=clamp(color,0.0,1.0);
    #endif
    return color;
}

// ============================================================
// CAS and Catmull-Rom
// ============================================================

#define minOf(a,b,c,d,e,f,g,h,i) min(a,min(b,min(c,min(d,min(e,min(f,min(g,min(h,i))))))))
#define maxOf(a,b,c,d,e,f,g,h,i) max(a,max(b,max(c,max(d,max(e,max(f,max(g,max(h,i))))))))
#define SampleColor(texel) texelFetch(colortex3, texel, 0).rgb

vec3 CASFilter(in ivec2 texel) {
    #ifndef CAS_ENABLED
        return SampleColor(texel);
    #endif
    vec3 a=SampleColor(texel+ivec2(-1,-1)); vec3 b=SampleColor(texel+ivec2(0,-1));
    vec3 c=SampleColor(texel+ivec2(1,-1));  vec3 d=SampleColor(texel+ivec2(-1,0));
    vec3 e=SampleColor(texel);              vec3 f=SampleColor(texel+ivec2(1,0));
    vec3 g=SampleColor(texel+ivec2(-1,1)); vec3 h=SampleColor(texel+ivec2(0,1));
    vec3 i_=SampleColor(texel+ivec2(1,1));
    vec3 minColor=minOf(a,b,c,d,e,f,g,h,i_);
    vec3 maxColor=maxOf(a,b,c,d,e,f,g,h,i_);
    vec3 sharpeningAmount=sqrt(min(1.0-maxColor,minColor)/maxColor);
    vec3 w=sharpeningAmount*mix(-0.125,-0.2,CAS_STRENGTH);
    return ((b+d+f+h)*w+e)/(4.0*w+1.0);
}

vec3 textureCatmullRomFast(in sampler2D tex, in vec2 position, in const float sharpness) {
    vec2 centerPosition=floor(position-0.5)+0.5;
    vec2 f=position-centerPosition;
    vec2 f2=f*f; vec2 f3=f*f2;
    vec2 w0=-sharpness*f3+2.0*sharpness*f2-sharpness*f;
    vec2 w1=(2.0-sharpness)*f3-(3.0-sharpness)*f2+1.0;
    vec2 w2=(sharpness-2.0)*f3+(3.0-2.0*sharpness)*f2+sharpness*f;
    vec2 w3=sharpness*f3-sharpness*f2;
    vec2 w12=w1+w2;
    vec2 tc0=screenPixelSize*(centerPosition-1.0);
    vec2 tc3=screenPixelSize*(centerPosition+2.0);
    vec2 tc12=screenPixelSize*(centerPosition+w2/w12);
    float l0=w12.x*w0.y; float l1=w0.x*w12.y; float l2=w12.x*w12.y;
    float l3=w3.x*w12.y; float l4=w12.x*w3.y;
    vec3 color=
        texture(tex,vec2(tc12.x,tc0.y)).rgb*l0+
        texture(tex,vec2(tc0.x,tc12.y)).rgb*l1+
        texture(tex,vec2(tc12.x,tc12.y)).rgb*l2+
        texture(tex,vec2(tc3.x,tc12.y)).rgb*l3+
        texture(tex,vec2(tc12.x,tc3.y)).rgb*l4;
    return color/(l0+l1+l2+l3+l4);
}

// ============================================================
// BODYCAM EFFECTS
// ============================================================

vec3 applyBodycamEffects(vec2 texcoord, vec3 base_color) {
    vec3 color=base_color;

    #if BODYCAMMISC_ENABLED == 1 || BODYCAM_ENABLED == 1
    vec2 centered=(texcoord-0.5)*ZOOM_NEW+0.5;
    float distance_=length(centered-0.5);
    float depth=texture2D(depthtex0,texcoord).r;
    float linearDepth=linearizeDepth(depth,0.1,100.0);

    #if BODYCAMMISC_ENABLED == 1
    vec2 crtUV=applyCRTCurve(centered);
    #else
    vec2 crtUV=centered;
    #endif

    vec2 shake=cameraShake(frameTimeCounter,INTENSITY_CAM_SHAKE_NEW)+handSway(frameTimeCounter,HAND_SWAY_STRENGTH);
    vec2 rotatedUV=rotateUV(crtUV+shake,sin(frameTimeCounter*0.5)*0.02);

    #if BODYCAM_ENABLED == 1
    float center_factor=pow(distance_,2.0)*FISHEYE_CENTER_STRENGTH;
    vec2 fisheyeUV=(rotatedUV-0.5)*(1.0+-(DIST_STRENGTH)*(distance_*distance_+center_factor))+0.5;
    #else
    vec2 fisheyeUV=rotatedUV;
    #endif

    #if BODYCAM_ENABLED == 1
    float caStrength=BODYCAM_CHROMA_STRENGTH*distance_;
    vec3 caColor;
    caColor.r=texture2D(colortex3,fisheyeUV+vec2(caStrength,0.0)).r;
    caColor.g=texture2D(colortex3,fisheyeUV).g;
    caColor.b=texture2D(colortex3,fisheyeUV+vec2(-caStrength,0.0)).b;
    color=mix(color,caColor,BODYCAM_CHROMA_OPACITY);
    #else
    color=texture2D(colortex3,fisheyeUV).rgb;
    #endif

    #if BODYCAMMISC_ENABLED == 1
    vec2 texelSize=1.0/vec2(viewWidth,viewHeight);
    vec3 sharpenedColor=vec3(0.0);
    sharpenedColor+=texture2D(colortex3,fisheyeUV+texelSize*vec2(-1.0,0.0)).rgb*-0.25;
    sharpenedColor+=texture2D(colortex3,fisheyeUV+texelSize*vec2(1.0,0.0)).rgb*-0.25;
    sharpenedColor+=texture2D(colortex3,fisheyeUV+texelSize*vec2(0.0,-1.0)).rgb*-0.25;
    sharpenedColor+=texture2D(colortex3,fisheyeUV+texelSize*vec2(0.0,1.0)).rgb*-0.25;
    sharpenedColor+=texture2D(colortex3,fisheyeUV).rgb*2.0;
    color=mix(color,sharpenedColor,SHARPNESS_STRENGTH);
    #endif

    color=clamp(color,0.0,1.0);

    #if BODYCAMMISC_ENABLED == 1
    color=applyBloom(fisheyeUV,color);
    color=applyPS1Style(fisheyeUV,color);
    #endif

    float luminance=dot(color,vec3(0.299,0.587,0.114));
    vec3 desaturated=mix(vec3(luminance),color,SATURATION);
    desaturated=pow(desaturated,vec3(0.9));
    float newLum=dot(desaturated,vec3(0.299,0.587,0.114));
    if (newLum>0.0) desaturated*=luminance/newLum;
    color=desaturated;

    #if BODYCAM_ENABLED == 1
    color.r*=0.975; color.g*=1.025; color.b*=1.05;
    #endif

    #if SCANLINE == 1
    float scanline=sin(fisheyeUV.y*SCANLINE_WIDTH_NEW*1.5)*SCANLINE_STRENGTH_NEW;
    color+=scanline;
    #endif

    #if GRAIN == 1
    float noise=(bodyCamNoise(fisheyeUV+vec2(frameTimeCounter))-0.5)*GRAIN_STRENGTH;
    #if DYNAMIC_NOISE == 1 && BODYCAMMISC_ENABLED == 1
    noise*=(1.0+DYNAMIC_NOISE_STRENGTH*(isSneaking+sin(frameTimeCounter*2.0)));
    #endif
    color+=vec3(noise);
    #endif

    #if COLOR_DIST == 1
    float colorDistort=COLOR_DIST_STRENGTH*sin(frameTimeCounter*2.0);
    color*=vec3(1.0+colorDistort,1.0-colorDistort,1.0+colorDistort);
    #endif

    #if ENABLE_NVG_IsSneaking == 1
    if (isSneaking==1.0||NVG==1) {
        float gray=dot(color,vec3(0.299,0.587,0.114));
        color=vec3(gray)*(vec3(R,G,B)*degree_brightness_increase);
    }
    #endif

    color*=pow(2.0,EXPOSURE);
    color+=BRIGHTNESS;
    color=((color-0.5)*CONTRAST)+0.5;

    #if VIGNETTE == 1
    {
        vec2 vc=texcoord-0.5;
        color=mix(color,vec3(0.0),applyDynamicVignette(texcoord,vc));
    }
    #endif

    #if BODYCAMMISC_ENABLED == 1
    color=mix(color,vec3(0.0),applyCubicVignette(texcoord));
    #endif

    #if BLACK_STRIPES == 1
    float leftStripe=smoothstep(BLACK_STRIPES_WIDTH_NEW,BLACK_STRIPES_WIDTH_NEW-BLACK_STRIPES_SOFT_NEW,texcoord.x);
    float rightStripe=smoothstep(1.0-BLACK_STRIPES_WIDTH_NEW,1.0-(BLACK_STRIPES_WIDTH_NEW-BLACK_STRIPES_SOFT_NEW),texcoord.x);
    color=mix(color,vec3(0.0),max(leftStripe,rightStripe));
    #endif

    color=mix(color,vec3(0.0),1.0-blackFOVMask(texcoord));
    color=drawImage(texcoord,color);
    #endif

    return color;
}

// ============================================================ 
// GAMEPLAY EFFECTS
// ============================================================

void applyGameplayEffects(inout vec3 color, in vec2 texcoord, float noise) {
    bool isDead=currentPlayerHealth*maxPlayerHealth<=0.0&&currentPlayerHealth>-1.0;
    float distortmask=0.0;
    float vignette=sqrt(clamp(dot(texcoord*2.0-1.0,texcoord*2.0-1.0)*0.5,0.0,1.0));

    #if defined LOW_HEALTH_EFFECT || defined DAMAGE_TAKEN_EFFECT
        float heartBeat=(pow(sin(frameTimeCounter*15.0)*0.5+0.5,2.0)*0.2+0.1);
        float damageDistortion=vignette*noise*heartBeat*threeHeart;
        damageDistortion=mix(damageDistortion,vignette*(0.5+noise),CriticalDamageTaken)*MOTION_AMOUNT;
        distortmask=isDead?vignette*(0.7+noise*0.3):damageDistortion;
    #endif

    #ifdef WATER_ON_CAMERA_EFFECT
        if (enterWater>0.0) color=mix(color,vec3(0.0,0.15,0.3),enterWater*0.25);
    #endif

    #ifdef ON_FIRE_DISTORT_EFFECT
        if (exitLava>0.0) {
            vec2 zoomin=0.5+(texcoord-0.5)
                *(1.0-pow(1.0-clamp(-texcoord.y*0.5+0.75,0.0,1.0),1.0))
                *(1.0-pow(1.0-exitLava,2.0));
            float flameDistort=texture2D(noisetex,
                zoomin*vec2(aspectRatio,1.0)-vec2(0.0,frameTimeCounter*0.3)
            ).b*clamp(-texcoord.y*0.3+0.3,0.0,1.0)*ON_FIRE_DISTORT_EFFECT_STRENGTH*exitLava;
            distortmask=max(distortmask,flameDistort);
        }
    #endif

    vec2 zoomUV=0.5+(texcoord-0.5)*(1.0-distortmask);
    vec3 distortedColor=texture2D(colortex3,zoomUV).rgb;

    #if defined ON_FIRE_DISTORT_EFFECT
        if (exitLava>0.01) color=distortedColor;
    #endif

    #if defined LOW_HEALTH_EFFECT || defined DAMAGE_TAKEN_EFFECT
        float distortedLuma=dot(distortedColor,vec3(0.21,0.72,0.07));
        vec3 distortedColorLuma=vec3(1.0,0.0,0.0)*distortedLuma;

        #ifdef LOW_HEALTH_EFFECT
            float colorLuma=dot(color,vec3(0.21,0.72,0.07));
            vec3 lumaRedEdges=mix(vec3(colorLuma),vec3(1.0,0.3,0.3)*distortedColorLuma.r,vignette);
            color=mix(color,lumaRedEdges,mix(vignette*threeHeart,oneHeart,oneHeart));
        #endif

        #ifdef DAMAGE_TAKEN_EFFECT
            color=mix(color,distortedColorLuma,vignette*sqrt(min(MinorDamageTaken,1.0)));
            color=mix(color,distortedColorLuma,sqrt(CriticalDamageTaken));
        #endif

        if (isDead) color=distortedColorLuma*0.35;
    #endif

    #ifdef DROWNING_EFFECT
        if (currentPlayerAir!=-1.0) color*=0.2+0.8*drowningSmooth;
    #endif
}

// ============================================================
// MAIN
// ============================================================

void main() {
    ivec2 texelRaw   = ivec2(gl_FragCoord.xy);
    vec2 texcoordRaw = gl_FragCoord.xy / vec2(viewWidth, viewHeight);
    vec2 texcoord    = texcoordRaw;

    // 1. Подводная рефракция
    texcoord = underwaterScreenRefraction(texcoord);

    ivec2 texel = ivec2(clamp(
        texcoord * vec2(viewWidth, viewHeight),
        vec2(0.0),
        vec2(viewWidth - 1.0, viewHeight - 1.0)
    ));

    #ifdef DEBUG_DRAWBUFFERS
        finalData = texelFetch(colortex4, texel, 0).rgb;
    #else

        // TSR / CAS
        if (abs(MC_RENDER_QUALITY - 1.0) < 1e-2) {
            finalData = CASFilter(texel);
        } else {
            finalData = textureCatmullRomFast(colortex3, texcoord * MC_RENDER_QUALITY, 0.6);
        }

        {
            vec3 tsrOutput = texture(colortex5, texcoord).rgb;
            if (texel != ivec2(0) && texel != ivec2(1)) finalData = tsrOutput;
        }

        finalData += (bayer16(gl_FragCoord.xy) - 0.5) * rcp(255.0);

        // GAMEPLAY EFFECTS
        #if defined LOW_HEALTH_EFFECT || defined DAMAGE_TAKEN_EFFECT || defined WATER_ON_CAMERA_EFFECT || defined ON_FIRE_DISTORT_EFFECT || defined DROWNING_EFFECT
        {
            float geNoise = fract(
                dot(vec2(gl_FragCoord.xy), vec2(0.06711056, 0.00583715)) * 52.9829189
            );
            applyGameplayEffects(finalData, texcoordRaw, geNoise);
        }
        #endif

        // VHS / BODYCAM
        if (VHS_ENABLED == 1) {
            finalData = vhs_effect(texcoord, finalData);
        } else if (BODYCAM_ENABLED == 1 || BODYCAMMISC_ENABLED == 1) {
            finalData = applyBodycamEffects(texcoord, finalData);
        }

        // CHROMATIC ABERRATION
        finalData = applyChromaticAberration(texcoord, finalData);

        // POSTERIZATION
        #if POSTERIZATION_ENABLED == 1
        {
            vec3 lum = vec3(0.299, 0.587, 0.114);
            float gray = dot(finalData.rgb, lum);
            finalData.rgb = mix(vec3(gray), finalData.rgb, SATURATION);
            float maxC   = max(finalData.r, max(finalData.g, finalData.b));
            float levels = float(POSTERIZATION_LEVELS);
            finalData.rgb *= floor(maxC * levels) / levels / maxC;
        }
        #endif

        // LENS FLARE
        {
            vec4 sunClipPos = gbufferProjection * vec4(sunPosition, 1.0);
            vec2 lightPos   = (sunClipPos.xy / sunClipPos.w) * 0.5 + 0.5;
            if (sunVisibility > 0.0 && rainStrength < 0.3)
                LensFlare(finalData, texcoord, lightPos, 1.0, LENS_FLARE_STRENGTH);
        }

        // EYE IMITATION
        finalData = applyEyeImitation(texcoord, finalData);

        // LENS WATER + RAIN STREAKS
        finalData = applyLensWater(texcoordRaw, finalData);

        // AXON PNG OVERLAY + TEXT
        #if (AXON_OVERLAY == 1 && minecraftversion <= 1.21)
        {
            vec2 axonSize = vec2(AXON_IMG_W, AXON_IMG_H);
            vec2 axonPos;
            #if AXON_POSITION == 0
                axonPos = vec2(AXON_IMG_MARGIN, 1.0 - AXON_IMG_MARGIN - axonSize.y);
            #else
                axonPos = vec2(1.0 - AXON_IMG_MARGIN - axonSize.x, 1.0 - AXON_IMG_MARGIN - axonSize.y);
            #endif
            vec4 axon = DrawAXON(texcoordRaw, axonPos, axonSize);
            finalData = mix(finalData, axon.rgb, axon.a);
            finalData = drawAxonText(texcoordRaw, axonPos, axonSize, finalData, AXON_POSITION);
        }
        #endif

        // INTRO ЗАСТАВКА
        #if DC_INTRO == 1
            finalData = drawAxonIntro(texcoordRaw, finalData);
        #endif

    #endif
}
