#ifdef s_usePBR

float integerLinStep(in float x, const int low, const int high) {
    int data = int(x*255.0);
    int mapped = clamp((data-low)/(high-low), 0, 255);

    return float(mapped/255.0);
}
int bitmask(in float x, const int bit) {
    int data = int(x*255.0);
    if (data == bit) return 1;
    else return 0;
}

void getLabPbr() {
    vec4 texsample  = pbrSample;
    pbr.roughness   = 1.0-texsample.r;
    pbr.roughness   = max(pbr.roughness, 0.02);
    pbr.f0          = pow2(clamp(texsample.g, 0.0, 229.0/255.0));
    pbr.porosity    = int(texsample.b*255.0)<65 ? integerLinStep(texsample.b, 0, 64) : 0.0;

    #ifdef s_useTexEmission
        pbr.emission    = int(texsample.a*255.0)<255 ? texsample.a : 0.0;
        emissiveTex    += pbr.emission;
    #endif

    #ifdef s_useTexSSS
        pbr.sss         = integerLinStep(texsample.b, 65, 255);
    #else
        pbr.sss         = 0.0;
    #endif

    roughness       = pbr.roughness;
    metalness       = float(int(texsample.g*255.0)>=230);
    specularity     = pbr.f0;

    #if (defined s_useNormal && defined s_useTexAO)
        ao *= saturate(pbr.ao);
    #endif
}

void PBRLegacy() {
    vec4 textureSpecular = pbrSample;

    roughness   = max(1.0-textureSpecular.r, 0.04);
    specularity = textureSpecular.g;
    metalness   = metal;
}

void PBRCommon() {
    vec4 textureSpecular = pbrSample;

    roughness   = max(1.0-textureSpecular.r, 0.04);
    metalness   = textureSpecular.g;
    specularity = 0.5;
}

void PBRChromaHills() {
    vec4 textureSpecular = pbrSample;

    roughness   = max(1.0-textureSpecular.r, 0.04);
    specularity = 0.85;
    metalness   = textureSpecular.b;
}

void PBRContinuum() {
    vec4 textureSpecular = pbrSample;

    roughness   = max(1.0-textureSpecular.b, 0.04);
    specularity = textureSpecular.r;
    metalness   = float(textureSpecular.r>0.45);
}

void PBRStratum() {
    vec4 textureSpecular = pbrSample;

    roughness   = max(1.0-textureSpecular.b, 0.04);
    specularity = 0.85;
    metalness   = textureSpecular.b;
}

void PBRPulchra() {
    vec4 textureSpecular = pbrSample;

    roughness   = max(1.0-textureSpecular.b, 0.08);
    metalness   = textureSpecular.r;
    specularity = 0.5;
    emissiveTex = 1.0-textureSpecular.a;

    #ifdef s_useNormal
        pbr.ao      = length(normalSample*2.0-1.0);
        ao *= saturate(pbr.ao);
    #endif
}

void getTexPbr() {
    #if s_pbrMode==0
        getLabPbr();
    #elif s_pbrMode==1
        PBRLegacy();
    #elif s_pbrMode==2
        PBRCommon();
    #elif s_pbrMode==3
        PBRContinuum();
    #elif s_pbrMode==4
        PBRChromaHills();
    #elif s_pbrMode==5
        PBRStratum();
    #elif s_pbrMode==6
        PBRPulchra();
    #endif
}
#endif

#ifdef s_useNormal
void getLabNormal() {
    vec3 texnormal      = normalSample;
        texnormal       = texnormal*2.0-(254.0/255.0);

        #ifdef s_useTexAO
            pbr.ao          = pow2(length(texnormal));
        #endif

        texnormal       = normalize(texnormal);
        
        texnormal       = flattenNormal(texnormal);

    mat3 tbnMatrix = mat3(tangent.x, binormal.x, nrm.x,
				tangent.y, binormal.y, nrm.y,
				tangent.z, binormal.z, nrm.z);

    normal  = normalize(texnormal*tbnMatrix);
}

void getTexNormal() {
    vec3 textureNormal  = normalSample;
        textureNormal.xy = textureNormal.xy*2.0-1.0;
        
        #if s_pbrMode==6
            textureNormal = normalize(textureNormal);
        #endif

        #ifdef setNormalFix
            textureNormal.xy *= 1.0-textureNormal.z;
        #endif

        textureNormal   = normalize(textureNormal);
        textureNormal   = flattenNormal(textureNormal);

    mat3 tbnMatrix = mat3(tangent.x, binormal.x, nrm.x,
				tangent.y, binormal.y, nrm.y,
				tangent.z, binormal.z, nrm.z);

    normal  = textureNormal*tbnMatrix;
}

void textureNormals() {
    #if s_pbrMode==0
        getLabNormal();
    #else
        getTexNormal();
    #endif
}
#endif