// Normal Generation System from Super Duper Vanilla
// Automatically generates bumped normals from albedo texture

// Enable/Disable normal generation
#define ENABLE_NORMAL_GENERATION 1 // [0 1] - Set to 1 to enable, 0 to disable

#ifndef NORMAL_GENERATION_RESOLUTION
    #define NORMAL_GENERATION_RESOLUTION 64.0 // [16.0 32.0 64.0 128.0 256.0]
#endif

#ifndef NORMAL_STRENGTH
    #define NORMAL_STRENGTH 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]
#endif

// Helper function to sum RGB channels
float sumOf(vec3 color) {
    return color.r + color.g + color.b;
}

// Fast normalize using inverse square root
vec3 fastNormalize(vec3 v) {
    return v * inversesqrt(dot(v, v));
}

// Length squared (avoids sqrt)
float lengthSquared(vec2 v) {
    return dot(v, v);
}

// Generate normals from albedo texture
vec3 generateNormals(
    in sampler2D tex,
    in vec2 texCoord,
    in vec2 dcdx,
    in vec2 dcdy,
    in vec2 vTexCoord,
    in vec2 vTexCoordScale,
    in vec2 vTexCoordPos,
    in mat3 TBN,
    in uint materialID
) {
    // Skip normal generation for certain blocks
    // Water (11102), End portal (12100), etc.
    if (materialID == 11102u || materialID == 12100u) {
        return TBN[2]; // Return flat normal
    }
    
    const float autoGenNormPixSize = 1.0 / NORMAL_GENERATION_RESOLUTION;
    
    // Calculate sampling positions
    vec2 topRightCorner = fract(vTexCoord - autoGenNormPixSize) * vTexCoordScale + vTexCoordPos;
    vec2 bottomLeftCorner = fract(vTexCoord + autoGenNormPixSize) * vTexCoordScale + vTexCoordPos;
    
    // Sample texture at 3 positions using textureGrad for proper mipmapping
    float d0 = sumOf(textureGrad(tex, topRightCorner, dcdx, dcdy).rgb);
    float d1 = sumOf(textureGrad(tex, vec2(bottomLeftCorner.x, topRightCorner.y), dcdx, dcdy).rgb);
    float d2 = sumOf(textureGrad(tex, vec2(topRightCorner.x, bottomLeftCorner.y), dcdx, dcdy).rgb);
    
    // Calculate slope from height differences
    vec2 slopeNormal = d0 - vec2(d1, d2);
    
    // Fast normalization: TBN * normalize(vec3(slopeNormal, 1))
    float lengthInv = inversesqrt(lengthSquared(slopeNormal) + 1.0);
    vec3 bumpedNormal = TBN * vec3(slopeNormal * lengthInv, lengthInv);
    
    // Mix with flat normal based on strength
    return mix(TBN[2], bumpedNormal, NORMAL_STRENGTH);
}

// Simplified version for when you don't have vTexCoord data
vec3 generateNormalsSimple(
    in sampler2D tex,
    in vec2 texCoord,
    in mat3 TBN,
    in uint materialID
) {
    // Skip normal generation for certain blocks
    if (materialID == 11102u || materialID == 12100u) {
        return TBN[2];
    }
    
    const float pixelSize = 1.0 / NORMAL_GENERATION_RESOLUTION;
    
    // Sample texture at 3 positions
    vec2 dx = dFdx(texCoord);
    vec2 dy = dFdy(texCoord);
    
    float d0 = sumOf(textureGrad(tex, texCoord + vec2(pixelSize, pixelSize), dx, dy).rgb);
    float d1 = sumOf(textureGrad(tex, texCoord + vec2(-pixelSize, pixelSize), dx, dy).rgb);
    float d2 = sumOf(textureGrad(tex, texCoord + vec2(pixelSize, -pixelSize), dx, dy).rgb);
    
    vec2 slopeNormal = d0 - vec2(d1, d2);
    float lengthInv = inversesqrt(lengthSquared(slopeNormal) + 1.0);
    vec3 bumpedNormal = TBN * vec3(slopeNormal * lengthInv, lengthInv);
    
    return mix(TBN[2], bumpedNormal, NORMAL_STRENGTH);
}
