#version 460 compatibility
#define COMP 1
/*
    References:
        [WHY23] Whyte, Killian. "Soft Clamp Function". 2023.
            https:

        You can find full license texts in /licenses
*/
// This file is generated by options.main.kts. Do not edit this file manually.
#define TITLE_VERSION 3//[0 1 2 3 4 5]
#define SETTING_NORMAL_MAPPING
#ifdef SETTING_NORMAL_MAPPING
#endif
#define SETTING_SHADOW_MAP_RESOLUTION 2048//[1024 2048 3072 4096]
const float shadowDistance = 512.0;//[64.0 128.0 192.0 256.0 384.0 512.0]
#define SETTING_WATER_WAVE_FREQUENCY 0.0//[-2.5 -2.4 -2.3 -2.2 -2.1 -2.0 -1.9 -1.8 -1.7 -1.6 -1.5 -1.4 -1.3 -1.2 -1.1 -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 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.1 2.2 2.3 2.4 2.5]
#define SETTING_WATER_WAVE_SPEED 1.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.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.0]
#define SETTING_WATER_NORMAL_SCALE 1.0//[0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0]
#define SETTING_WATER_PARALLAX
#ifdef SETTING_WATER_PARALLAX
#endif
#define SETTING_WATER_PARALLAX_STRENGTH 1.0//[0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0]
#define SETTING_WATER_PARALLAX_LINEAR_STEPS 8//[4 6 8 12 16 24 32]
const float sunPathRotation = -20.0;//[-90.0 -89.0 -88.0 -87.0 -86.0 -85.0 -84.0 -83.0 -82.0 -81.0 -80.0 -79.0 -78.0 -77.0 -76.0 -75.0 -74.0 -73.0 -72.0 -71.0 -70.0 -69.0 -68.0 -67.0 -66.0 -65.0 -64.0 -63.0 -62.0 -61.0 -60.0 -59.0 -58.0 -57.0 -56.0 -55.0 -54.0 -53.0 -52.0 -51.0 -50.0 -49.0 -48.0 -47.0 -46.0 -45.0 -44.0 -43.0 -42.0 -41.0 -40.0 -39.0 -38.0 -37.0 -36.0 -35.0 -34.0 -33.0 -32.0 -31.0 -30.0 -29.0 -28.0 -27.0 -26.0 -25.0 -24.0 -23.0 -22.0 -21.0 -20.0 -19.0 -18.0 -17.0 -16.0 -15.0 -14.0 -13.0 -12.0 -11.0 -10.0 -9.0 -8.0 -7.0 -6.0 -5.0 -4.0 -3.0 -2.0 -1.0 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 14.0 15.0 16.0 17.0 18.0 19.0 20.0 21.0 22.0 23.0 24.0 25.0 26.0 27.0 28.0 29.0 30.0 31.0 32.0 33.0 34.0 35.0 36.0 37.0 38.0 39.0 40.0 41.0 42.0 43.0 44.0 45.0 46.0 47.0 48.0 49.0 50.0 51.0 52.0 53.0 54.0 55.0 56.0 57.0 58.0 59.0 60.0 61.0 62.0 63.0 64.0 65.0 66.0 67.0 68.0 69.0 70.0 71.0 72.0 73.0 74.0 75.0 76.0 77.0 78.0 79.0 80.0 81.0 82.0 83.0 84.0 85.0 86.0 87.0 88.0 89.0 90.0]
//#define SETTING_SCREENSHOT_MODE
#ifdef SETTING_SCREENSHOT_MODE
#endif
//#define SETTING_ASSUME_NVIDIA_GPU
#ifdef SETTING_ASSUME_NVIDIA_GPU
#endif
//#define SETTING_DEBUG_AE
#ifdef SETTING_DEBUG_AE
#endif
#if SETTING_SHADOW_MAP_RESOLUTION == 1024
#define SHADOW_MAP_SIZE_D16 64
const int shadowMapResolution = 1024;
#elif SETTING_SHADOW_MAP_RESOLUTION == 2048
#define SHADOW_MAP_SIZE_D16 128
const int shadowMapResolution = 2048;
#elif SETTING_SHADOW_MAP_RESOLUTION == 3072
#define SHADOW_MAP_SIZE_D16 192
const int shadowMapResolution = 3072;
#elif SETTING_SHADOW_MAP_RESOLUTION == 4096
#define SHADOW_MAP_SIZE_D16 256
const int shadowMapResolution = 4096;
#endif
const vec2 SHADOW_MAP_SIZE = vec2(float(shadowMapResolution), 1.0 / float(shadowMapResolution));
#ifndef SKIP_UNIFORMS
uniform float frameTimeCounter;
uniform float near;
uniform float far;
uniform vec3 cameraPosition;
uniform mat4 gbufferModelView;
uniform mat4 gbufferModelViewInverse;
uniform mat4 gbufferPreviousModelView;
uniform mat4 textureMatrix = mat4(1.0);
#endif
float vanillaFarPlane = far;
float vanillaNearPlane = near;
#if defined(DISTANT_HORIZONS)
uniform float dhNearPlane;
uniform float dhFarPlane;
#elif defined(VOXY)
uniform int vxRenderDistance;
#endif
#if defined(DISTANT_HORIZONS)
float farPlane = max(dhFarPlane, far);
float nearPlane = min(dhNearPlane, near);
#elif defined(VOXY)
float farPlane = max(far, float(vxRenderDistance * 16));
float nearPlane = near;
#else
float farPlane = far;
float nearPlane = near;
#endif
mat4 gbufferPrevModelView = gbufferPreviousModelView;
#ifndef SKIP_UNIFORMS
uniform vec3 uval_upDirView;
uniform vec2 uval_mainImageSizeRcp;
uniform int uval_mainImageSizeIX;
uniform int uval_mainImageSizeIY;
uniform int uval_restirSpatialTileOffsetX;
uniform int uval_restirSpatialTileOffsety;
ivec2 uval_restirSpatialTileOffset = ivec2(uval_restirSpatialTileOffsetX, uval_restirSpatialTileOffsety);
#endif
ivec2 uval_mainImageSizeI = ivec2(uval_mainImageSizeIX, uval_mainImageSizeIY);
#ifndef GLOBAL_DATA_MODIFIER
#define GLOBAL_DATA_MODIFIER restrict readonly buffer
#endif
struct AEData {
    vec4 lastScreenAvgLum;
    vec4 screenAvgLum;
    vec4 expValues;
    vec2 hsPercents;
    uint shadowCount;
    uint highlightCount;
    uint weightSum;
    #ifdef SETTING_DEBUG_AE
    uint lumHistogram[256];
    uint lumHistogramMaxBinCount;
    float finalAvgLum;
    #endif
};
struct CameraData {
    uint frustumPlaneCount;
    vec4 frustumPlanes[6];
};
layout(std430, binding = 0) GLOBAL_DATA_MODIFIER GlobalData {
    uvec4 global_dispatchSize1;
    uvec4 global_dispatchSize2;
    uvec4 global_dispatchSize3;
    uvec4 global_dispatchSize4;
    mat4 gbufferPrevModelViewInverse;
    mat4 global_shadowRotationMatrix;
    mat4 global_shadowRotationMatrixInverse;
    mat4 global_taaJitterMat;
    mat4 global_camProj;
    mat4 global_camProjInverse;
    mat4 global_prevCamProj;
    mat4 global_prevCamProjInverse;
    mat4 global_shadowProj;
    mat4 global_shadowProjInverse;
    mat4 global_shadowProjNext;
    mat4 global_shadowProjNextInverse;
    mat4 global_shadowView;
    mat4 global_shadowViewInverse;
    mat4 global_sceneToShadowNDC;
    mat4 global_shadowViewToShadowNDC;
    mat4 global_shadowNDCToScene;
    vec3 global_prevCameraDelta;
    CameraData global_cameraData;
    vec2 global_mipmapSizes[16];
    vec2 global_mipmapSizesRcp[16];
    ivec4 global_mipmapTiles3[16];
    ivec2 global_mipmapSizesI[16];
    ivec2 global_mipmapSizePrefixesPadded[16];
    ivec2 global_mipmapSizePrefixes[16];
    ivec4 global_hizTiles[16];
    ivec4 global_mipmapTileCeil[16];
    ivec4 global_mipmapTileCeilPadded[16];
    ivec3 global_shadowAABBMinPrev;
    ivec3 global_shadowAABBMaxPrev;
    ivec3 global_shadowAABBMin;
    ivec3 global_shadowAABBMax;
    vec3 global_shadowAABBMinHistory;
    vec3 global_shadowAABBMaxHistory;
    ivec3 global_shadowAABBMinNew;
    ivec3 global_shadowAABBMaxNew;
    float global_focusDistance;
    int global_lastWorldTime;
    float global_historyResetFactor;
    vec4 global_motionFactor;
    vec4 global_taaResetFactor;
    float global_turbidity;
    AEData global_aeData;
    uint global_atomicCounters[16];
};
layout(std430, binding = 1) GLOBAL_DATA_MODIFIER IndirectComputeData {
    uint indirectComputeData[];
};
#ifndef SKIP_UNIFORMS
uniform usampler2D colortex16;
uniform usampler2D colortex17;
uniform sampler2D colortex18;
uniform sampler2D usam_csr32f;
uniform sampler2D usam_waveNoise;
uniform sampler2D usam_waveHFCurl;
#endif
#ifndef SKIP_UNIFORMS
#endif
ivec2 _textile_texelToTexel(ivec2 texelPos, ivec2 tileOffset, ivec2 tileSize) {
    return clamp(texelPos, ivec2(0), tileSize - 1) + tileOffset;
}
vec2 _textile_uvToUV(vec2 uv, vec2 tileOffsetF, vec2 tileSizeF, vec2 atlastSizeRcp) {
    vec2 textureTexelPos = clamp(uv * tileSizeF, vec2(0.5), tileSizeF - 0.5) + tileOffsetF;
    return clamp(textureTexelPos * atlastSizeRcp, 0.0, 1.0);
}
vec2 _textile_uvToGatherUV(vec2 uv, vec2 tileOffsetF, vec2 tileSizeF, vec2 atlastSizeRcp) {
    vec2 textureTexelPos = clamp(uv * tileSizeF, vec2(1.0), tileSizeF - 1.0) + tileOffsetF;
    return clamp(textureTexelPos * atlastSizeRcp, 0.0, 1.0);
}
vec2 _textile_texelToGatherUV(vec2 texelPos, vec2 tileOffsetF, vec2 tileSizeF, vec2 atlastSizeRcp) {
    vec2 textureTexelPos = clamp(texelPos, vec2(1.0), tileSizeF - 1.0) + tileOffsetF;
    return clamp(textureTexelPos * atlastSizeRcp, 0.0, 1.0);
}
#ifdef DISABLE_FP16
#define NO_HALF a
#define hf
#define float16_t float
#define f16vec2 vec2
#define f16vec3 vec3
#define f16vec4 vec4
#define f16mat2 mat2
#define f16mat3 mat3
#define f16mat4 mat4
#else
#if defined MC_GL_AMD_gpu_shader_half_float
#extension GL_AMD_gpu_shader_half_float : enable
#elif defined MC_GL_NV_gpu_shader5 || defined SETTING_ASSUME_NVIDIA_GPU
#extension GL_NV_gpu_shader5 : enable
#else
#define NO_HALF a
#define hf
#define float16_t float
#define f16vec2 vec2
#define f16vec3 vec3
#define f16vec4 vec4
#define f16mat2 mat2
#define f16mat3 mat3
#define f16mat4 mat4
#endif
#endif
#define PI 3.14159265358979323846
#define PI_2 (2.0 * PI)
#define PI_HALF (0.5 * PI)
#define PI_QUARTER (0.25 * PI)
#define RCP_PI (1.0 / PI)
#define RCP_PI_2 (1.0 / PI_2)
#define RCP_PI_HALF (1.0 / PI_HALF)
#define GOLDEN_RATIO 1.618033988749
#define GOLDEN_ANGLE 2.39996322972865332
#define SPHERE_SOLID_ANGLE (4.0 * PI)
#define FLT_MAX uintBitsToFloat(0x7F7FFFFF)
#define FLT_MIN uintBitsToFloat(0x00800000)
#define FLT_TRUE_MIN uintBitsToFloat(0x00000001)
#define FLT_POS_INF uintBitsToFloat(0x7F800000)
#define FLT_NEG_INF uintBitsToFloat(0xFF800000)
#define FP16_MAX 65504.0
#define INT32_MAX 2147483647
#define INT32_MIN -2147483648
#define rcp(x) (1.0 / (x))
#define saturate(x) clamp(x, 0.0, 1.0)
float pow3(float x) { return x * x * x; }
vec2 pow3(vec2 x) { return x * x * x; }
vec3 pow3(vec3 x) { return x * x * x; }
vec4 pow3(vec4 x) { return x * x * x; }
#ifndef NO_HALF
float16_t pow3(float16_t x) { return x * x * x; }
f16vec2 pow3(f16vec2 x) { return x * x * x; }
f16vec3 pow3(f16vec3 x) { return x * x * x; }
f16vec4 pow3(f16vec4 x) { return x * x * x; }
#endif
/*
    References:
        [WRE18] Wrensch, Benjamin. "Reverse Z Cheatsheet". IOLITE Development Blog. 2023.
*/
vec3 coords_toViewCoord(vec2 texCoord, float viewZ, mat4 projInv) {
    vec2 ndcXY = texCoord * 2.0 - 1.0;
    vec2 clipXY = ndcXY * -viewZ;
    vec2 viewXY = clipXY * vec2(projInv[0][0], projInv[1][1]);
    return vec3(viewXY, viewZ);
}
vec2 OctWrap(vec2 v) {
    return (1.0 - abs(v.yx)) * mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0)));
}
vec2 coords_octEncode11(vec3 n) {
    n /= (abs(n.x) + abs(n.y) + abs(n.z));
    n.xy = n.z >= 0.0 ? n.xy : OctWrap(n.xy);
    return n.xy;
}
const mat3 _COORDS_EQUATORIAL_TO_GALACTIC = mat3(
    -0.0548755604, 0.4941094279, -0.8676661490,
    -0.8734370902, -0.4448296300, -0.1980763734,
    -0.4838350155, 0.7469822445, 0.4559837762
);
const mat3 _COORDS_WORLD_TO_EQUATORIAL = mat3(
    0.0, 1.0, 0.0,
    1.0, 0.0, 0.0,
    0.0, 0.0, -1.0
);
vec3 coords_dir_viewToWorld(vec3 dirView) {
    return normalize((mat3(gbufferModelViewInverse) * dirView));
}
vec3 coords_dir_worldToView(vec3 dirWorld) {
    return normalize((mat3(gbufferModelView) * dirWorld));
}
uint nzpacking_packNormalOct32(vec3 normal) {
    return packSnorm2x16(coords_octEncode11(normal));
}
void nzpacking_packNormalOct16(out uint packedNormal, vec3 normal1, vec3 normal2) {
    vec4 xyzw = vec4(coords_octEncode11(normal1), coords_octEncode11(normal2));
    packedNormal = packSnorm4x8(xyzw);
}
const uint MATERIAL_ID_UNDEFINED = 65535u;
struct GBufferData {
    vec3 geomNormal;
    vec3 geomTangent;
    vec4 pbrSpecular;
    vec3 normal;
    vec2 lmCoord;
    uint materialID;
    vec3 albedo;
    bool isHand;
    bool forceBuiltInPBR;
    int bitangentSign;
};
GBufferData gbufferData_init() {
    GBufferData gData;
    gData.geomNormal = vec3(0.0);
    gData.geomTangent = vec3(0.0);
    gData.pbrSpecular = vec4(0.0);
    gData.normal = vec3(0.0);
    gData.lmCoord = vec2(0.0);
    gData.materialID = MATERIAL_ID_UNDEFINED;
    gData.albedo = vec3(0.0);
    gData.isHand = false;
    gData.forceBuiltInPBR = false;
    return gData;
}
void gbufferData1_pack(out uvec4 packedData, GBufferData gData) {
    nzpacking_packNormalOct16(packedData.r, coords_dir_viewToWorld(gData.geomNormal), coords_dir_viewToWorld(gData.geomTangent));
    packedData.g = packUnorm4x8(vec4(gData.pbrSpecular));
    packedData.b = nzpacking_packNormalOct32(coords_dir_viewToWorld(gData.normal));
    packedData.a = packUnorm4x8(vec4(gData.lmCoord, 0.0, 0.0)) & 0x0000FFFFu;
    packedData.a |= (gData.materialID & 0xFFFFu) << 16;
}
void gbufferData2_pack(out uvec4 packedData, GBufferData gData) {
    packedData.r = packUnorm4x8(vec4(gData.albedo, 0.0)) & 0x00FFFFFFu;
    packedData.r = bitfieldInsert(packedData.r, uint(gData.isHand), 24, 1);
    packedData.r = bitfieldInsert(packedData.r, uint(clamp(gData.bitangentSign, 0, 1)), 25, 1);
    packedData.r = bitfieldInsert(packedData.r, uint(gData.forceBuiltInPBR), 26, 1);
}
const uint MATERIAL_ID_WATER = 1u;
ivec2 textile_texelToTexel(ivec2 texelPos, ivec2 tileOffset, ivec2 tileSize) {
    return clamp(texelPos, ivec2(0), tileSize - 1) + tileOffset;
}
ivec2 csr32f_tile1_texelToTexel(ivec2 texelPos) {
    return textile_texelToTexel(
        texelPos,
        ivec2(0),
        uval_mainImageSizeI
    );
}
ivec2 csr32f_tile2_texelToTexel(ivec2 texelPos) {
    return textile_texelToTexel(
        texelPos,
        ivec2(uval_mainImageSizeI.x, 0),
        uval_mainImageSizeI
    );
}
ivec2 csr32f_tile3_texelToTexel(ivec2 texelPos) {
    return textile_texelToTexel(
        texelPos,
        ivec2(0, uval_mainImageSizeI.y),
        uval_mainImageSizeI
    );
}
ivec2 csr32f_tile4_texelToTexel(ivec2 texelPos) {
    return textile_texelToTexel(
        texelPos,
        ivec2(uval_mainImageSizeI.xy),
        uval_mainImageSizeI
    );
}
#define MAT2_GOLDEN_ANGLE mat2(-0.737368878, 0.675490294, -0.675490294, -0.737368878)
/*
    References:
        [QUI13a] Quilez, Inigo. "Noise - gradient - 2D". 2013.
            MIT License. Copyright (c) 2013 Inigo Quilez.
            https:
        [QUI13b] Quilez, Inigo. "Noise - gradien  - 3D". 2013.
            MIT License. Copyright (c) 2013 Inigo Quilez.
            https:
        [QUI17a] Quilez, Inigo. "Noise - Gradient - 2D - Deriv". 2017.
            MIT License. Copyright (c) 2017 Inigo Quilez.
            https:
        [QUI17b] Quilez, Inigo. "Noise - Gradient - 3D - Deriv". 2017.
            MIT License. Copyright (c) 2017 Inigo Quilez.
            https:
        [QUI17c] Quilez, Inigo. "Gradient Noise Derivatives". 2017.
            https:

        You can find full license texts in /licenses
*/
/*
    References:
        [QUI17] Quilez, Inigo. "Integer Hash Functions". 2017.
            MIT License. Copyright (c) 2017,2024 Inigo Quilez.
            https:
            https:
            https:
        [JAR20] Jarzynski, Mark. Olano, Marc. "Hash Functions for GPU Rendering". 2020.
            https:

        You can find full license texts in /licenses
*/
const uvec4 _HASH_LINEAR_COMB_MAGIC_MUL = uvec4(19u, 47u, 101u, 131u);
const uint _HASH_LINEAR_COMB_MAGIC_ADD = 173u;
const uint _HASH_XXHASH32_PRIME32_2 = 0x85EBCA77u;
const uint _HASH_XXHASH32_PRIME32_3 = 0xC2B2AE3Du;
const uint _HASH_XXHASH32_PRIME32_4 = 0x27D4EB2Fu;
const uint _HASH_XXHASH32_PRIME32_5 = 0x165667B1u;
#define _NOISE_INTERPOLANT 1
struct FBMParameters {
    float frequency;
    float persistence;
    float lacunarity;
    uint octaveCount;
};
#if _NOISE_INTERPOLANT == 1
#define _NOISE_INTERPO(w) (w * w * w * (w * (w * 6.0 - 15.0) + 10.0))
#define _NOISE_INTERPO_GRAD(w) (30.0 * w * w * (w * (w - 2.0) + 1.0))
#else
#define _NOISE_INTERPO(w) (w * w * (3.0 - 2.0 * w))
#define _NOISE_INTERPO_GRAD(w) (6.0 * w * (1.0 - w))
#endif
struct AxisAngle {
    vec3 axis;
    vec3 csc;
};
/*
    References:
        [QUI15] Quilez, Inigo. "Texture Repetition". 2015.
            https:
        [QUI17] Quilez, Inigo. "Texture Repetition V". 2017.
            MIT License. Copyright (c) 2017 Inigo Quilez
            https:
        [DJO12] Djonov, Phill. "Bicubic Filtering in Fewer Taps". 2012.
            https:
        [MJP19] MJP. "An HLSL function for sampling a 2D texture with Catmull-Rom filtering, using 9 texture samples instead of 16". 2019.
            https:

        You can find full license texts in /licenses
*/
#if DERIVATIVE_AVAILABLE
#endif
vec4 sampling_catmullBicubic5Tap(sampler2D texSampler, vec2 texelPos, float sharpness, vec2 texRcpSize){
    vec2 t = fract(texelPos - 0.5);
    vec2 centerUV = (floor(texelPos - 0.5) + vec2(0.5f, 0.5f)) * texRcpSize;
    vec2 f = t;
    vec2 f2 = t * t;
    vec2 f3 = t * t * t;
    float s = sharpness;
    vec2 w0 = -s * f3 + 2.0 * s * f2 - s * f;
    vec2 w1 = (2.0 - s) * f3 + (s - 3.0) * f2 + 1.0;
    vec2 w2 = (s - 2.0) * f3 + (3.0 - 2.0 * s) * f2 + s * f;
    vec2 w3 = s * f3 - s * f2;
    vec2 w12 = w1 + w2;
    vec2 tc12 = centerUV + (w2 / w12) * texRcpSize;
    vec2 tc0 = centerUV - 1.0f * texRcpSize;
    vec2 tc3 = centerUV + 2.0f * texRcpSize;
    vec4 c1 = vec4(texture(texSampler, vec2(tc12.x, tc0.y)));
    vec4 c2 = vec4(texture(texSampler, vec2(tc0.x, tc12.y)));
    vec4 c3 = vec4(texture(texSampler, vec2(tc12.x, tc12.y)));
    vec4 c4 = vec4(texture(texSampler, vec2(tc3.x, tc12.y)));
    vec4 c5 = vec4(texture(texSampler, vec2(tc12.x, tc3.y)));
    float weight1 = w12.x * w0.y;
    float weight2 = w0.x * w12.y;
    float weight3 = w12.x * w12.y;
    float weight4 = w3.x * w12.y;
    float weight5 = w12.x * w3.y;
    vec4 color = weight1 * c1;
    color += weight2 * c2;
    color += weight3 * c3;
    color += weight4 * c4;
    color += weight5 * c5;
    return color * rcp(weight1 + weight2 + weight3 + weight4 + weight5);
}
struct CatmullRomBicubic5TapData {
    vec3 uv1AndWeight;
    vec3 uv2AndWeight;
    vec3 uv3AndWeight;
    vec3 uv4AndWeight;
    vec3 uv5AndWeight;
};
vec4 sampling_catmullBicubic5Tap(sampler2D texSampler, vec2 uv, float sharpness){
    vec2 texSize = vec2(textureSize(texSampler, 0));
    vec2 texelPos = uv * texSize;
    vec2 texRcpSize = rcp(texSize);
    return sampling_catmullBicubic5Tap(texSampler, texelPos, sharpness, texRcpSize);
}
vec4 sampling_bSplineBicubic4Tap(sampler2D texSampler, vec2 texelPos, vec2 texRcpSize) {
    vec2 f = fract(texelPos - 0.5);
    vec2 f2 = f * f;
    vec2 f3 = f2 * f;
    vec2 w0 = f2 - 0.5 * (f3 + f);
    vec2 w1 = 1.5 * f3 - 2.5 * f2 + 1.0;
    vec2 w3 = 0.5 * (f3 - f2);
    vec2 w2 = 1.0 - w0 - w1 - w3;
    vec2 s0 = w0 + w1;
    vec2 s1 = w2 + w3;
    vec2 centerUV = (floor(texelPos - 0.5) + 0.5) * texRcpSize;
    vec2 t0 = centerUV + (w1 / s0 - 1.0) * texRcpSize;
    vec2 t1 = centerUV + (w3 / s1 + 1.0) * texRcpSize;
    return (texture(texSampler, vec2(t0.x, t0.y)) * s0.x
    + texture(texSampler, vec2(t1.x, t0.y)) * s1.x) * s0.y
    + (texture(texSampler, vec2(t0.x, t1.y)) * s0.x
    + texture(texSampler, vec2(t1.x, t1.y)) * s1.x) * s1.y;
}
vec4 sampling_bSplineBicubic4Tap(sampler2D texSampler, vec2 uv) {
    vec2 texSize = vec2(textureSize(texSampler, 0));
    vec2 texelPos = uv * texSize;
    vec2 texRcpSize = rcp(texSize);
    return sampling_bSplineBicubic4Tap(texSampler, texelPos, texRcpSize);
}
struct BSplineBicubic4TapData {
    vec2 uv00;
    vec2 uv10;
    vec2 uv01;
    vec2 uv11;
    vec2 weight0;
    vec2 weight1;
};
vec4 sampling_catmullRomBicubic9Tap(sampler2D texSampler, vec2 texelPos, vec2 texRcpSize) {
    vec2 samplePos = texelPos;
    vec2 texPos1 = floor(samplePos - 0.5) + 0.5;
    vec2 f = samplePos - texPos1;
    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 w12 = w1 + w2;
    vec2 offset12 = w2 / w12;
    vec2 texPos0 = (texPos1 - 1.0) * texRcpSize;
    vec2 texPos3 = (texPos1 + 2.0) * texRcpSize;
    vec2 texPos12 = (texPos1 + offset12) * texRcpSize;
    vec4 result = vec4(0.0);
    result += texture(texSampler, vec2(texPos0.x, texPos0.y)) * w0.x * w0.y;
    result += texture(texSampler, vec2(texPos12.x, texPos0.y)) * w12.x * w0.y;
    result += texture(texSampler, vec2(texPos3.x, texPos0.y)) * w3.x * w0.y;
    result += texture(texSampler, vec2(texPos0.x, texPos12.y)) * w0.x * w12.y;
    result += texture(texSampler, vec2(texPos12.x, texPos12.y)) * w12.x * w12.y;
    result += texture(texSampler, vec2(texPos3.x, texPos12.y)) * w3.x * w12.y;
    result += texture(texSampler, vec2(texPos0.x, texPos3.y)) * w0.x * w3.y;
    result += texture(texSampler, vec2(texPos12.x, texPos3.y)) * w12.x * w3.y;
    result += texture(texSampler, vec2(texPos3.x, texPos3.y)) * w3.x * w3.y;
    return result;
}
vec4 sampling_catmullRomBicubic9Tap(sampler2D texSampler, vec2 uv) {
    vec2 texSize = vec2(textureSize(texSampler, 0));
    vec2 texelPos = uv * texSize;
    vec2 texRcpSize = rcp(texSize);
    return sampling_catmullRomBicubic9Tap(texSampler, texelPos, texRcpSize);
}
struct CatmullRomBicubic9TapData {
    vec2 uv00;
    vec2 uv12_0;
    vec2 uv30;
    vec2 uv01_2;
    vec2 uv12_12;
    vec2 uv31_2;
    vec2 uv03;
    vec2 uv12_3;
    vec2 uv33;
    vec2 weight0;
    vec2 weight12;
    vec2 weight3;
};
/*
    References:
        [GIL23] Gilcher, Pascal. "A Better R2 Sequence". 2023.
            https:
        [JIM17] Jimenez, Jorge. "Interleaved Gradient Noise". 2017.
            https:
        [ROB18] Roberts, Martine. "The Unreasonable Effectiveness of Quasirandom Sequences". 2018.
            https:
        [WOL22] Wolfe, Alan. "Interleaved Gradient Noise: A Different Kind of Low Discrepancy Sequence". 2022.
            MIT License. Copyright (c) 2019 Alan Wolfe.
            https:

        You can find full license texts in /licenses
*/
float oscillate(float x) {
    return cos(1.1 * x + 0.5) * 0.95 + sin(1.6 * x + 1.5) * 0.43 + cos(3.7 * x + 2.2) * 0.15;
}
float sampleNoise(vec2 coord) {
    return textureLod(usam_waveNoise, coord * 0.175, 0.0).r;
}
const float WAVE_POS_BASE = 0.03 * exp2(SETTING_WATER_WAVE_FREQUENCY);
float waveHeight(vec3 wavePos, bool base) {
    const vec2 WAVE_DIR = vec2(0.777, -0.555);
    const vec2 CURL_DIR = vec2(-0.21, 0.15);
    #ifndef SETTING_SCREENSHOT_MODE
    float timeV = frameTimeCounter * SETTING_WATER_WAVE_SPEED;
    #else
    float timeV = 13.37;
    #endif
    vec2 waveTime = vec2(0.0);
    waveTime += timeV * WAVE_DIR * 0.1;
    vec2 waveTexCoordOg = wavePos.xz + wavePos.y * 0.07;
    vec2 waveTexCoordOgCurl = waveTexCoordOg;
    vec2 waveTexCoord = waveTexCoordOg;
    vec2 curl = vec2(0.0);
    {
        vec2 curlCoord = waveTexCoordOgCurl * 0.11;
        float ff = oscillate(timeV * 4.5 + 6.9);
        curlCoord += ff * CURL_DIR * 0.0018;
        curlCoord += waveTime * 0.11;
        curl = textureLod(usam_waveHFCurl, curlCoord, 0.0).rg * 0.061;
    }
    waveTexCoord = MAT2_GOLDEN_ANGLE * (waveTexCoord + waveTime * -0.025);
    float wave = 0.0;
    if (base) {
        #ifdef DISTANT_HORIZONS
        wave += 0.4 * sampleNoise((waveTexCoord + curl + waveTime * 0.31) * vec2(0.1, 0.06)) * 2.0;
        #endif
        wave += 0.4 * sampleNoise((waveTexCoord + curl + waveTime * 0.29) * vec2(0.5, 0.8));
    }
    waveTexCoord = MAT2_GOLDEN_ANGLE * (waveTexCoord * 2.23);
    curl = MAT2_GOLDEN_ANGLE * (curl * 1.85);
    {
        waveTexCoordOgCurl = MAT2_GOLDEN_ANGLE * waveTexCoordOgCurl;
        vec2 curlCoord2 = waveTexCoordOgCurl * 0.45;
        curlCoord2 -= waveTime * 0.78;
        curlCoord2 -= (MAT2_GOLDEN_ANGLE * waveTime) * 1.57;
        curl += textureLod(usam_waveHFCurl, curlCoord2, 0.0).rg * 0.026;
    }
    wave += -0.16 * sampleNoise((waveTexCoord + curl - waveTime * 0.96) * vec2(-0.85, 0.52));
    waveTexCoord = MAT2_GOLDEN_ANGLE * (waveTexCoord * 1.33 - waveTime * 1.87);
    curl = MAT2_GOLDEN_ANGLE * (curl * 1.35);
    wave += -0.59 * (sampleNoise((waveTexCoord + curl) * vec2(-0.13, -0.36)));
    waveTexCoord = MAT2_GOLDEN_ANGLE * (waveTexCoord * 1.88 - waveTime * 1.58);
    curl = MAT2_GOLDEN_ANGLE * (curl * 1.35);
    {
        waveTexCoordOgCurl = MAT2_GOLDEN_ANGLE * waveTexCoordOgCurl;
        vec2 curlCoord2 = waveTexCoordOgCurl;
        curlCoord2 = curlCoord2 * 0.98;
        curlCoord2 += sin(timeV * 6.1 + 2.1) * 0.042 * CURL_DIR;
        curlCoord2 -= waveTime * 2.17;
        curlCoord2 -= (MAT2_GOLDEN_ANGLE * waveTime) * 1.63;
        curl += textureLod(usam_waveHFCurl, curlCoord2, 0.0).rg * 0.068;
    }
    wave += -0.07 * sampleNoise((waveTexCoord + curl) * vec2(-0.57, -0.69) + waveTime * vec2(3.2, -5.1));
    waveTexCoord = MAT2_GOLDEN_ANGLE * (waveTexCoord * 1.87 - waveTime * 1.68);
    curl = MAT2_GOLDEN_ANGLE * (curl * 1.73);
    wave += -0.05 * sampleNoise((waveTexCoord + curl) * vec2(0.4, 0.6) - waveTime * vec2(1.1, 1.1));
    return wave;
}
layout(local_size_x = 16, local_size_y = 16) in;
const vec2 workGroupsRender = vec2(1.0, 1.0);
layout(rgba32ui) uniform restrict uimage2D colorimg8;
layout(r32ui) uniform restrict uimage2D colorimg9;
layout(r32f) uniform restrict image2D colorimg10;
layout(rgba32ui) uniform restrict uimage2D colorimg11;
layout(r32ui) uniform restrict uimage2D colorimg12;
layout(rgba16f) uniform restrict image2D colorimg14;
layout(r32i) uniform restrict iimage2D uimg_csr32f;
shared uvec4 shared_voxyData[18][18];
vec3 voxy_faceWorldNormal(uint face) {
    return normalize(vec3(
        uint((face >> 1u) == 2u),
        uint((face >> 1u) == 0u),
        uint((face >> 1u) == 1u)
    ) * (float(int(face) & 1) * 2.0 - 1.0));
}
vec3 voxy_faceWorldTangent(uint face) {
    return ((face >> 1u) == 2u) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
}
void main() {
    ivec2 texelPos = ivec2(gl_GlobalInvocationID.xy);
    ivec2 groupBase = ivec2(gl_WorkGroupID.xy) * 16 - 1;
    uint localIndex = gl_LocalInvocationIndex;
    for (uint i = localIndex; i < 324u; i += 256u) {
        ivec2 localPos = ivec2(i % 18u, i / 18u);
        ivec2 loadPos = clamp(groupBase + localPos, ivec2(0), uval_mainImageSizeI - 1);
        shared_voxyData[localPos.x][localPos.y] = texelFetch(colortex16, loadPos, 0);
    }
    barrier();
    if (any(greaterThanEqual(texelPos, uval_mainImageSizeI))) return;
    ivec2 localPos = ivec2(gl_LocalInvocationID.xy) + 1;
    uvec4 voxyCenter = shared_voxyData[localPos.x][localPos.y];
    bool hasSolid = (voxyCenter.w != 0u || voxyCenter.x != 0u);
    uvec4 voxyTransCenter = texelFetch(colortex17, texelPos, 0);
    bool hasTranslucent = (voxyTransCenter.w != 0u || voxyTransCenter.x != 0u);
    if (!hasSolid && !hasTranslucent) return;
    float solidZ = imageLoad(colorimg10, texelPos).r;
    if (hasSolid) {
        float voxyZ = uintBitsToFloat(voxyCenter.w);
        if (voxyZ > solidZ) {
            imageStore(colorimg10, texelPos, vec4(voxyZ));
            vec2 uvCenter = unpackUnorm2x16(voxyCenter.x);
            vec4 colorFace = unpackUnorm4x8(voxyCenter.y);
            vec3 albedo = colorFace.rgb;
            uint face = bitfieldExtract(voxyCenter.y, 24, 3);
            uint rawProp = voxyCenter.z;
            uint matID = (rawProp >> 16) & 0xFFFFu;
            vec2 lmCoord = vec2(rawProp & 0xFFu, (rawProp >> 8) & 0xFFu) / 255.0;
            vec2 screenPos = (vec2(texelPos) + 0.5) * uval_mainImageSizeRcp;
            vec3 viewPosCenter = coords_toViewCoord(screenPos, voxyZ, global_camProjInverse);
            vec2 dUVdx = vec2(0.0);
            vec2 dUVdy = vec2(0.0);
            vec3 dPdx = vec3(0.0);
            vec3 dPdy = vec3(0.0);
            float weightX = 0.0;
            float weightY = 0.0;
            for (int dx = -1; dx <= 1; dx += 2) {
                uvec4 voxyNeighbor = shared_voxyData[localPos.x + dx][localPos.y];
                if (voxyNeighbor.w != 0u || voxyNeighbor.x != 0u) {
                    uint neighborFace = bitfieldExtract(voxyNeighbor.y, 24, 3);
                    if (neighborFace == face) {
                        float neighborZ = uintBitsToFloat(voxyNeighbor.w);
                        if (abs(neighborZ - voxyZ) < 0.2) {
                            vec2 uvNeighbor = unpackUnorm2x16(voxyNeighbor.x);
                            vec2 neighborScreenPos = (vec2(texelPos + ivec2(dx, 0)) + 0.5) * uval_mainImageSizeRcp;
                            vec3 viewPosNeighbor = coords_toViewCoord(neighborScreenPos, neighborZ, global_camProjInverse);
                            dUVdx += (uvNeighbor - uvCenter) * float(dx);
                            dPdx += (viewPosNeighbor - viewPosCenter) * float(dx);
                            weightX += 1.0;
                        }
                    }
                }
            }
            for (int dy = -1; dy <= 1; dy += 2) {
                uvec4 voxyNeighbor = shared_voxyData[localPos.x][localPos.y + dy];
                if (voxyNeighbor.w != 0u || voxyNeighbor.x != 0u) {
                    uint neighborFace = bitfieldExtract(voxyNeighbor.y, 24, 3);
                    if (neighborFace == face) {
                        float neighborZ = uintBitsToFloat(voxyNeighbor.w);
                        if (abs(neighborZ - voxyZ) < 0.2) {
                            vec2 uvNeighbor = unpackUnorm2x16(voxyNeighbor.x);
                            vec2 neighborScreenPos = (vec2(texelPos + ivec2(0, dy)) + 0.5) * uval_mainImageSizeRcp;
                            vec3 viewPosNeighbor = coords_toViewCoord(neighborScreenPos, neighborZ, global_camProjInverse);
                            dUVdy += (uvNeighbor - uvCenter) * float(dy);
                            dPdy += (viewPosNeighbor - viewPosCenter) * float(dy);
                            weightY += 1.0;
                        }
                    }
                }
            }
            if (weightX > 0.5) {
                dUVdx /= weightX;
                dPdx /= weightX;
            }
            if (weightY > 0.5) {
                dUVdy /= weightY;
                dPdy /= weightY;
            }
            vec3 geomWorldNormal = voxy_faceWorldNormal(face);
            vec3 geomViewNormal = coords_dir_worldToView(geomWorldNormal);
            vec3 tangent = vec3(1.0, 0.0, 0.0);
            vec3 bitangent = vec3(0.0, 1.0, 0.0);
            bool singlePixel = (weightX < 0.5 && weightY < 0.5);
            if (!singlePixel) {
                float det = dUVdx.x * dUVdy.y - dUVdy.x * dUVdy.y;
                if (abs(det) > 1e-6) {
                    float invDet = 1.0 / det;
                    tangent = (dPdx * dUVdy.y - dPdy * dUVdx.y) * invDet;
                    bitangent = (dPdy * dUVdx.x - dPdx * dUVdy.x) * invDet;
                    tangent = normalize(tangent - geomViewNormal * dot(geomViewNormal, tangent));
                    bitangent = normalize(cross(geomViewNormal, tangent) * sign(det));
                    bitangent = normalize(bitangent - geomViewNormal * dot(geomViewNormal, bitangent));
                    bitangent = normalize(bitangent - tangent * dot(tangent, bitangent));
                } else {
                    singlePixel = true;
                }
            }
            if (singlePixel) {
                vec3 worldTangent = voxy_faceWorldTangent(face);
                tangent = coords_dir_worldToView(worldTangent);
                bitangent = normalize(cross(tangent, geomViewNormal));
                tangent = normalize(cross(geomViewNormal, bitangent));
            }
            GBufferData gData = gbufferData_init();
            gData.geomNormal = geomViewNormal;
            gData.geomTangent = tangent;
            gData.pbrSpecular = vec4(0.0);
            gData.normal = geomViewNormal;
            gData.lmCoord = lmCoord;
            gData.materialID = matID;
            gData.albedo = albedo;
            gData.isHand = false;
            gData.forceBuiltInPBR = true;
            gData.bitangentSign = (dot(cross(tangent, geomViewNormal), bitangent) > 0.0) ? 1 : -1;
            uvec4 d1;
            uvec4 d2;
            gbufferData1_pack(d1, gData);
            gbufferData2_pack(d2, gData);
            imageStore(colorimg8, texelPos, d1);
            imageStore(colorimg9, texelPos, d2);
        }
    }
    if (hasTranslucent) {
        float voxyZ = uintBitsToFloat(voxyTransCenter.w);
        solidZ = imageLoad(colorimg10, texelPos).r;
        if (voxyZ > solidZ) {
            uint face = bitfieldExtract(voxyTransCenter.y, 24, 3);
            uint rawProp = voxyTransCenter.z;
            uint matID = (rawProp >> 16) & 0xFFFFu;
            bool isWater = matID == MATERIAL_ID_WATER;
            vec2 lmCoord = vec2(rawProp & 0xFFu, (rawProp >> 8) & 0xFFu) / 255.0;
            vec3 geomViewNormal = coords_dir_worldToView(voxy_faceWorldNormal(face));
            vec3 geomViewTangent = coords_dir_worldToView(voxy_faceWorldTangent(face));
            vec3 geomViewBitangent = normalize(cross(geomViewTangent, geomViewNormal));
            geomViewTangent = normalize(cross(geomViewNormal, geomViewBitangent));
            vec2 screenPos = (vec2(texelPos) + 0.5) * uval_mainImageSizeRcp;
            vec3 viewPos = coords_toViewCoord(screenPos, voxyZ, global_camProjInverse);
            float zOffset = 0.0;
            vec3 finalNormal = geomViewNormal;
            #if defined(SETTING_NORMAL_MAPPING)
            if (isWater) {
                vec3 scenePos = (gbufferModelViewInverse * vec4(viewPos, 1.0)).xyz;
                vec3 waveWorldPos = (scenePos + cameraPosition) * WAVE_POS_BASE;
                #ifdef SETTING_WATER_PARALLAX
                const float UP_DIR_COS_EPSILON = 0.001;
                if (dot(geomViewNormal, uval_upDirView) > UP_DIR_COS_EPSILON) {
                    const uint PARALLAX_LINEAR_STEPS = uint(SETTING_WATER_PARALLAX_LINEAR_STEPS);
                    const float PARALLAX_STRENGTH = float(SETTING_WATER_PARALLAX_STRENGTH) / 0.83;
                    vec3 rayVector = scenePos / max(abs(scenePos.y), 1e-4);
                    float rayVectorLength = length(rayVector);
                    vec3 rayDir = rayVector / max(rayVectorLength, 1e-4);
                    const float MAX_WAVE_HEIGHT = -rcp(0.83);
                    vec2 prevXY = vec2(0.0, 1.0);
                    for (uint i = 0u; i < PARALLAX_LINEAR_STEPS; i++) {
                        float fi = float(i) / float(max(PARALLAX_LINEAR_STEPS - 1u, 1u));
                        fi = 1.0 - pow3(1.0 - fi);
                        fi *= rayVectorLength;
                        vec3 sampleDelta = rayDir * fi;
                        vec3 samplePos = waveWorldPos + sampleDelta * WAVE_POS_BASE * PARALLAX_STRENGTH;
                        samplePos.y = waveWorldPos.y;
                        float sampleHeight = saturate(waveHeight(samplePos, false) * MAX_WAVE_HEIGHT);
                        float currHeight = 1.0 + sampleDelta.y;
                        if (currHeight <= sampleHeight) {
                            vec2 xy1 = prevXY;
                            vec2 xy2 = vec2(fi, currHeight - sampleHeight);
                            for (uint j = 0u; j < 2u; j++) {
                                float x3 = xy2.x - xy2.y * (xy2.x - xy1.x) / (xy2.y - xy1.y);
                                fi = x3;
                                sampleDelta = rayDir * x3;
                                samplePos = waveWorldPos;
                                samplePos.xz += sampleDelta.xz * (WAVE_POS_BASE * PARALLAX_STRENGTH);
                                sampleHeight = saturate(waveHeight(samplePos, false) * MAX_WAVE_HEIGHT);
                                float depthDiff = (1.0 + sampleDelta.y) - sampleHeight;
                                if (depthDiff < 0.01) break;
                                xy1 = xy2;
                                xy2 = vec2(x3, depthDiff);
                            }
                            waveWorldPos = samplePos;
                            zOffset = fi * PARALLAX_STRENGTH * 0.5 + 0.4 / rayDir.y;
                            break;
                        }
                        prevXY = vec2(fi, currHeight - sampleHeight);
                    }
                }
                #endif
                const float NORMAL_EPS = 0.1;
                const float NORMAL_WEIGHT = SETTING_WATER_NORMAL_SCALE;
                float waveHeightC = waveHeight(waveWorldPos, true);
                float waveOffset = NORMAL_EPS * WAVE_POS_BASE;
                vec3 offsetTangentX = coords_dir_viewToWorld(geomViewTangent) * waveOffset;
                vec3 offsetTangentY = coords_dir_viewToWorld(geomViewBitangent) * waveOffset;
                float waveHeightX = waveHeight(waveWorldPos + offsetTangentX, true);
                float waveHeightY = waveHeight(waveWorldPos + offsetTangentY, true);
                vec3 tangentNormal = vec3(waveHeightX, waveHeightY, NORMAL_EPS);
                tangentNormal.xy -= waveHeightC;
                tangentNormal.xy *= NORMAL_WEIGHT;
                finalNormal = normalize(mat3(geomViewTangent, geomViewBitangent, geomViewNormal) * normalize(tangentNormal));
            }
            #endif
            float offsetViewZ = voxyZ - clamp(zOffset, -16.0, 16.0);
            ivec2 nearDepthTexelPos = isWater ? csr32f_tile1_texelToTexel(texelPos) : csr32f_tile3_texelToTexel(texelPos);
            ivec2 farDepthTexelPos = isWater ? csr32f_tile2_texelToTexel(texelPos) : csr32f_tile4_texelToTexel(texelPos);
            float waterNearViewZ = -texelFetch(usam_csr32f, csr32f_tile1_texelToTexel(texelPos), 0).r;
            float translucentNearViewZ = -texelFetch(usam_csr32f, csr32f_tile3_texelToTexel(texelPos), 0).r;
            float frontBefore = max(waterNearViewZ, translucentNearViewZ);
            imageAtomicMin(uimg_csr32f, nearDepthTexelPos, floatBitsToInt(-offsetViewZ));
            imageAtomicMax(uimg_csr32f, farDepthTexelPos, floatBitsToInt(-offsetViewZ));
            if (offsetViewZ >= frontBefore) {
                vec4 transmittanceV = texelFetch(colortex18, texelPos, 0);
                GBufferData gData = gbufferData_init();
                gData.geomNormal = geomViewNormal;
                gData.geomTangent = geomViewTangent;
                gData.pbrSpecular = vec4(0.0);
                gData.normal = finalNormal;
                gData.lmCoord = lmCoord;
                gData.materialID = matID;
                gData.albedo = transmittanceV.rgb;
                gData.isHand = false;
                gData.forceBuiltInPBR = true;
                gData.bitangentSign = (dot(cross(geomViewTangent, geomViewNormal), geomViewBitangent) > 0.0) ? 1 : -1;
                uvec4 d1;
                uvec4 d2;
                gbufferData1_pack(d1, gData);
                gbufferData2_pack(d2, gData);
                imageStore(colorimg11, texelPos, d1);
                imageStore(colorimg12, texelPos, d2);
                imageStore(colorimg14, texelPos, transmittanceV);
            }
        }
    }
}