#if !defined MATERIAL_STRUCT_LIB
#define MATERIAL_STRUCT_LIB
    struct Bounce {
        vec3 n;
        vec3 k;
        vec3 normal;
        vec3 flatNormal;
        vec3 albedo;

        vec3 emissive;

        float opacity;
        float ao;
        float sss;
        float f0;
        float roughness;
        float roughnessSquared;
        float id;
        float albedoMetal;
    };

    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);
    }

    vec3 clampNormal(in vec3 normals, in vec3 viewDirection) {
        float nDotV = saturate(dot(normals, -viewDirection));
        return fNormalize(normals - saturate(dot(viewDirection, normals)) * viewDirection);
    }

    Bounce hitMaterial(in vec4 albedoMap, in vec4 specularMap, in vec3 surfaceNormal, in vec3 hitNormal, in float id, in float ambientOcclusion) {
        Bounce b;

        b.albedo = srgbToLinear(albedoMap.rgb);
        vec3 metalAlbedo = b.albedo;
        b.albedo *= (1.0 - float(specularMap.g > 0.9));
        b.normal = surfaceNormal;
        b.flatNormal = hitNormal;

        b.emissive = vec3(0.0);
        if(id == 18 || id == 20 || id >= 147 && id <= 150 || id == 240) {
            b.emissive = b.albedo * 3.0;
        }

        if(id == 241) {
            b.emissive = b.albedo * 3.0;
        }

        if(id == 242) {
            b.emissive = b.albedo * pow(dot(b.albedo, vec3(0.7)), 2.0) * 16.0;
        }

        b.opacity = albedoMap.a;
        b.ao = ambientOcclusion;


        b.sss = 0.0;
        b.roughness = square(1.0 - specularMap.r);
        b.roughnessSquared = square(b.roughness);
        b.f0 = specularMap.g;

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

        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

        b.albedoMetal = 0.0;

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

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

        if(specularMap.g > 0.999999) {
            b.n = vec3(10.0);
            b.k = metalAlbedo;
            b.albedoMetal = 1.0;
        }

        return b;
    }

    Bounce getBounceMaterial(in vec2 uv, in vec3 hitNormal, in mat3 tbn, in vec4[2] voxel, in int bounceID) {
        float id = int((255.5 - OCTREE_LEVELS) - voxel[0].a * 255.0);

        ivec2 atlasSize = ivec2(textureSize(atlas, 0));

        vec4 albedoMap = texelFetch(atlas, ivec2(uv * atlasSize), 0) * vec4(voxel[0].rgb, 1.0);
        //if(bounceID == 0) {
        //    albedoMap.rgb = vec3(1.0);
        //}

        vec4 specularMap = texelFetch(atlas_s, ivec2(uv * atlasSize), 0);
        vec4 normalMap = texelFetch(atlas_n, ivec2(uv * atlasSize), 0) * 2.0 - 1.0;

        float ao = normalMap.z;

        normalMap.xyz = vec3(normalMap.xy, sqrt(saturate(1.0 - dot(normalMap.xy, normalMap.xy))));
        normalMap.xyz = normalize(tbn * normalMap.xyz);

        //normalMap.xyz = hitNormal;

        return hitMaterial(albedoMap, specularMap, normalMap.xyz, hitNormal, id, ao);
    }
#endif