#if !defined SURFACE_DATA_LIB
#define SURFACE_DATA_LIB
    struct surfaceData {
        vec3 albedo;
        vec3 normals;
        vec3 flatNormals;
        vec3 viewNormals;
        vec3 viewFlatNormals;
        vec3 n;
        vec3 k;

        vec2 lightmap;

        float id;

        float sss;
        float f0;
        float roughness;
        float roughnessSquared;
        float metalness;
        float isAlbedoMetal;

        float puddles;
        float vanillaAO;

        bool particle;
    } sd;

    float f0ToIOR(float f0) {
        f0 = sqrt(f0);
        f0 *= 0.99999; // Prevents divide by 0
        return (1.0 + f0) / (1.0 - f0);
    }

    float IORTof0(in float ior) {
        float sqrtf0 = (ior - 1.00029) / (ior + 1.00029);
        return square(sqrtf0);
    }

    void fillSurfaceStruct() {
        uvec4 data0 = texture(colortex2, textureCoordinate);
        uvec4 data1 = texture(colortex3, textureCoordinate);

        sd.albedo = srgbToLinear(unpackUnorm4x8(data0.r).rgb);

        sd.puddles = unpackSnorm4x8(data0.a).b;

        sd.normals = DecodeUnitVector(unpackSnorm2x16(data0.g));
        //sd.normals = mat3(gbufferModelViewInverse) * clampNormal(mat3(gbufferModelView) * sd.normals, fNormalize(-pd.viewPosition[0]));
        sd.flatNormals = DecodeUnitVector(unpackSnorm4x8(data0.b).zw);
        sd.viewNormals = mat3(gbufferModelView) * sd.normals;
        sd.viewFlatNormals = mat3(gbufferModelView) * sd.flatNormals;

        sd.lightmap = unpackSnorm4x8(data0.b).xy;
        sd.lightmap.x = pow(sd.lightmap.x, 2.6) * 1.6;
        sd.lightmap.y = pow(sd.lightmap.y, 4.0) * 1.6;

        sd.id = unpackUnorm4x8(data0.r).a * 255.0;

        sd.particle = unpackSnorm4x8(data0.a).r < 0.5;
        sd.vanillaAO = unpackSnorm4x8(data0.a).g;

        {
            vec4 specularData = vec4(unpackUnorm2x16(data1.r), unpackUnorm2x16(data1.g));

            if(sd.id == 9.0) {
                specularData = vec4(1.0, 0.0336845007, 0.0, 0.0);
            }

            sd.f0 = specularData.g;
            sd.metalness = float(sd.f0 > 0.9);
            sd.roughness = 1.0 - specularData.r;
            if(sd.id == 8.0) sd.roughness = 1.0 - 0.999;
            sd.roughness = square(sd.roughness);
            sd.roughnessSquared = square(sd.roughness);

            sd.n = vec3(f0ToIOR(sd.f0));
            sd.k = vec3(0.0);

            if(sd.id == 8.0) {
                sd.n = vec3(1.3310, 1.3330, 1.3374);
                sd.k = vec3(2.4540e-8, 1.9600e-9, 1.1320e-9);
            }

            float iron = 0.0;     //1
            float gold = 0.0;     //2
            float aluminum = 0.0; //3
            float chrome = 0.0;   //4
            float copper = 0.0;   //5
            float lead = 0.0;     //6
            float platinum = 0.0; //7
            float silver = 0.0;   //8

            if(specularData.g > 0.900 && specularData.g < 0.902) {
                iron = 1.0;     //1
            }
            if(specularData.g > 0.902 && specularData.g < 0.906) {
                gold = 1.0;     //2
            }
            if(specularData.g > 0.906 && specularData.g < 0.910) {
                aluminum = 1.0; //3
            }
            if(specularData.g > 0.910 && specularData.g < 0.913) {
                chrome = 1.0;   //4
            }
            if(specularData.g > 0.914 && specularData.g < 0.918) {
                copper = 1.0;   //5
            }
            if(specularData.g > 0.918 && specularData.g < 0.922) {
                lead = 1.0;     //6
            }
            if(specularData.g > 0.922 && specularData.g < 0.926) {
                platinum = 1.0; //7
            }
            if(specularData.g > 0.926 && specularData.g < 0.930) {
                silver = 1.0;   //8
            }

            if(iron > 0.9) {
                sd.n = vec3(2.9114, 2.9497, 2.5845);
                sd.k = vec3(3.0893, 2.9318, 2.7670);
            }
            if(gold > 0.9) {
                sd.n = vec3(0.18299, 0.42108, 1.3734);
                sd.k = vec3(3.4242, 2.3459, 1.7704);
            }
            if(aluminum > 0.9) {
                sd.n = vec3(1.3456, 0.96521, 0.61722);
                sd.k = vec3(7.4746, 6.3995, 5.3031);
            }
            if(chrome > 0.9) {
                sd.n = vec3(3.1071, 3.1812, 2.3230);
                sd.k = vec3(3.3314, 3.3291, 3.1350);
            }
            if(copper > 0.9) {
                sd.n = vec3(0.27105, 0.67693, 1.3164);
                sd.k = vec3(3.6092, 2.6248, 2.2921);
            }
            if(lead > 0.9) {
                sd.n = vec3(1.9100, 1.8300, 1.4400);
                sd.k = vec3(3.5100, 3.4000, 3.1800);
            }
            if(platinum > 0.9) {
                sd.n = vec3(2.3757, 2.0847, 1.8453);
                sd.k = vec3(4.2655, 3.7153, 3.1365);
            }
            if(silver > 0.9) {
                sd.n = vec3(0.15943, 0.14512, 0.13547);
                sd.k = vec3(3.9291, 3.1900, 2.3808);
            }

            if(specularData.g > 0.999999) {
                sd.n = vec3(10.0);
                sd.k = sd.albedo;
                sd.isAlbedoMetal = 1.0;
            } else {
                sd.isAlbedoMetal = 0.0;
            }
        }
    }
#endif