/**
 * NOTE: This file is autogenerated. Do not edit.
 */
export const ifcShader = {
    vertex: (options?: Record<string, () => string>): string => /* glsl */ `
        precision highp float;
        
        attribute vec3 position;
        attribute vec2 uv;
        
        uniform mat4 worldViewProjection;
        // uniform vec3 cameraPositionW;
        uniform mat4 worldMatrix;
        // uniform float packSize;
        // uniform vec3 size;
        // uniform vec3 eyePositionW; // Remember that the eye position is always (0, 0, 0) when it's in viewspace 
        
        out float vColorPixelIndex;
        out vec3 vPositionW;
        
        void main(void) {                
            vec4 worldSpaceVertex = worldMatrix * vec4(position, 1.0);
            vPositionW = worldSpaceVertex.xyz;
            vColorPixelIndex = uv.x;
            gl_Position = worldViewProjection * vec4(position, 1.0);
        }`,
    fragment: (options?: Record<string, () => string>): string => /* glsl */ `
        precision highp float;
        precision highp int;
        
        uniform vec3 highlightColors[3];
        
        uniform mat4 worldViewProjection_custom;
        uniform vec3 cameraPositionW;
        uniform vec3 groundColor;
        uniform vec4 materialDiffuseColor;
        uniform vec3 ambientColor;
        uniform vec3 hemisphericLightColor;
        uniform float hemisphericLightStrength;
        uniform vec3 hemisphericLightWorldSpace;
        uniform vec3 directionalLightColor;
        uniform vec3 directionalLightWorldSpaceDirection;
        uniform float directionalLightStrength;
        uniform sampler2D diffuseSampler;
        uniform sampler2D propertiesSampler;
        uniform float packSize;
        uniform mat4 worldMatrix;
        uniform vec3 size;
        
        uniform bool isPerspective;
        uniform float farPlane;
        uniform float nearPlane;
        uniform float orthoSize;
        uniform float ditherDistanceFade;
        
        uniform float directionalLightLambertStrength;
        uniform float directionalLightSpecularStrength;
        
        // #typescript options?.clipPlaneUniforms()
        ${options?.clipPlaneUniforms()}
        
        in float vColorPixelIndex;
        in vec3 vPositionW;
        
        // #include DitherUniforms.glsl
        #ifdef dithering
            uniform sampler2D ditherSampler;
            uniform vec2 ditherSize;
            uniform vec2 resolution;
        #endif
        
        vec3 computeHemisphericLightingDiffuseTerm(vec3 normalW, vec3 hemisphericLightDirectionW, vec3 diffuseColor, vec3 groundColor) {
        	float ndl = dot(normalW, hemisphericLightDirectionW) * 0.5 + 0.5;
        	vec3 diffuse = mix(groundColor, diffuseColor, ndl);
        	
        	return diffuse;
        }
        
        vec3 computeDirectionalLight(vec3 worldE, vec3 worldN) {
            vec3 normalReflectedLightDirection = reflect(normalize(directionalLightWorldSpaceDirection), worldN);
        
            // float shininess = 128.0; // Hardcoded to 128, since we don't have shininess in the properties texture.
            // float specular = pow(max(0.0, dot(normalReflectedLightDirection, worldE)), shininess) * directionalLightSpecularStrength;
            // float specular = specRaw * directionalLightSpecularStrength;
            // pow is expensive so allegedly hardcoding multiplication is faster. Since we know its 128 we can hardcode it.
            float specular = max(0.0, dot(normalReflectedLightDirection, worldE));
            specular = specular * specular;
            specular = specular * specular;
            specular = specular * specular;
            specular = specular * specular;
            specular = specular * specular;
            specular = specular * specular;
            specular = specular * specular * directionalLightSpecularStrength;
        
            float diffuse = max(dot(worldN, -normalize(directionalLightWorldSpaceDirection)), 0.0) * directionalLightLambertStrength;
            return max(directionalLightColor * (diffuse + specular), vec3(0.0));
        }
        
        // #include HSVMapping.glsl
        #ifdef useHSVMapping
            // Official HSV to RGB conversion 
            vec3 hsv2rgb( in vec3 c )
            {
                vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );
        
                return c.z * mix( vec3(1.0), rgb, c.y);
            }
        
            // Smooth HSV to RGB conversion 
            vec3 hsv2rgb_smooth( in vec3 c )
            {
                vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );
        
                rgb = rgb*rgb*(3.0-2.0*rgb); // cubic smoothing	
        
                return c.z * mix( vec3(1.0), rgb, c.y);
            }
        
            vec3 rgb2hsv_2(vec3 c){
                vec4 K=vec4(0.,-1./3.,2./3.,-1.),
                    p=mix(vec4(c.bg ,K.wz),vec4(c.gb,K.xy ),step(c.b,c.g)),
                    q=mix(vec4(p.xyw,c.r ),vec4(c.r ,p.yzx),step(p.x,c.r));
                float d=q.x-min(q.w,q.y),
                    e=1e-10;
                return vec3(abs(q.z+(q.w-q.y)/(6.*d+e)),d/(q.x+e),q.x);
            }
            
            uniform vec3 hsvValues;
        #endif
        
        // #include LinearizeDepth.glsl
        //Note that this is linearized but NOT normalized, to normalize divide the result of this function by the far plane.
        float linearizeDepth(float depth, float near, float far)
        {
            float z = depth * 2.0 - 1.0;
            return (2.0 * near * far) / (far + near - z * (far - near));	
        }
        
        void main(void) {    
        
            // NOTE: Normal calculation MUST happen BEFORE any discard operations (like dithering) OR if branches
            // because dFdx/dFdy derivatives become undefined when neighboring fragments are discarded.
            // This causes broken normals on some drivers (especially Linux).
            vec3 fdx = dFdx(vPositionW);
            vec3 fdy = dFdy(vPositionW);
        
        
            
        
            // used by ColorPickingIndex.glsl below
            ivec2 textureSize = textureSize(diffuseSampler, 0);
        
            // Calculates pixelIndex used by PropertiesPixel.glsl and to get fragment color further down
            // #include ColorPickingIndex.glsl
        float colorPixelIndex = vColorPixelIndex + 0.5;
        float uvY = floor(colorPixelIndex / float(textureSize.x)); 
        float uvX = floor(floor(colorPixelIndex) - uvY * float(textureSize.x));    
        vec2 pixelIndex = vec2(uvX, uvY);
        
            // This include sets (among other things) the visible variable to true or false.
            // #include PropertiesPixel.glsl
        vec4 properties = texelFetch(propertiesSampler, ivec2(floor(pixelIndex)), 0);
        
        int castedA = int(ceil(clamp(properties.a, 0., 1.) * 255.0));
        #ifdef depthWriteIgnoresVisibilityProperty
            int lastBitMask = 1; // Depth write bit
            int depthWriteIgnoresVisibilityValue = castedA & lastBitMask;
            bool depthWriteIgnoresVisibility = depthWriteIgnoresVisibilityValue == lastBitMask;
        #endif
        
        #ifdef visibilityProperty
            int secondLastBitMask = 2; // Visibility bit
            int visibilityValue = castedA & secondLastBitMask;
            bool visible = visibilityValue == secondLastBitMask;
        #endif
        
        #ifdef highlightProperty
            int fourthAndThirdLastBitsMask = 12; // Highlight bits
            int highlightIndex = (castedA & fourthAndThirdLastBitsMask) >> 2; // Move 2 bits right to get 0-3 range
            bool highlighted = highlightIndex != 0;
        #endif
        
        #ifdef outlinedProperty
            int fifthBitMask = 16; // Outline bit
            int outlinedValue = castedA & fifthBitMask;
            bool outlined = outlinedValue == fifthBitMask;
        #endif
        
        #ifdef ignoreClipPlanesProperty
            int sixthBitMask = 32; // Clip plane ignore bit
            int clipPlaneIgnoreValue = castedA & sixthBitMask;
            bool clipPlaneIgnore = clipPlaneIgnoreValue == sixthBitMask;
        #endif
        
        
            if (!visible) {
                // Good for debugging if a texture fails for some reason
                // if (int(colorPixelIndex) % textureSize.x == 0 && diffuseColor == vec4(0, 0, 0, 0)) {
                //     gl_FragColor = vec4(1, 0, 0, 1);
                //     return;
                // }
                discard;
            }
        
        
            
        
        
            
            vec4 diffuseColor = texelFetch(diffuseSampler, ivec2(pixelIndex), 0);
            
            if (diffuseColor.a == 0.0) {
                // Good for debugging if a texture fails for some reason
                // if (int(colorPixelIndex) % textureSize.x == 0 && diffuseColor == vec4(0, 0, 0, 0)) {
                //     gl_FragColor = vec4(1, 0, 0, 1);
                //     return;
                // }
                discard;
            }
        
            
            vec3 worldSpaceVertex = vPositionW + cameraPositionW;
        
            
        
            // #typescript options?.clipPlaneDiscarding()
        ${options?.clipPlaneDiscarding()}
        
            vec3 worldE = normalize(cameraPositionW - vPositionW);
            vec3 normal = normalize(cross(fdy, fdx));
            vec3 hemisphericLighting = computeHemisphericLightingDiffuseTerm(normal, hemisphericLightWorldSpace, hemisphericLightColor, groundColor);
            vec3 directionalLighting = computeDirectionalLight(worldE, normal);
        
            vec3 finalDiffuse = clamp((directionalLighting * directionalLightStrength + hemisphericLighting * hemisphericLightStrength) * materialDiffuseColor.rgb + ambientColor, 0.0, 1.0) * diffuseColor.rgb;
            float opaqueness = 0.0;
            #ifdef dithering
                opaqueness = min(diffuseColor.a, 1.0);
                float distanceImpact = 0.25;
                // #include DitherDiscard.glsl
        // Cranked up a bit since the new blending mode has a less noticeable impact
        float perspectiveDitherCutoffDistance = 500.0;
        float orthoDitherCutoffDistance = 1000.0;
        
        float transparency = (1.0 - step(0.99, opaqueness)) * max(1.0 - opaqueness * DITHERING_OPACITY_COEFFICIENT, 0.0);
        
        float fakeDistance = pow(min((gl_FragCoord.z / gl_FragCoord.w) / 7.5, 1.0), 1.15);
        
        vec2 samplePosition = (gl_FragCoord.xy / resolution) * ditherSize;
        vec3 dither = texture2D(ditherSampler, samplePosition).xyz;
        
        float exponent = dither.r;
        float mantissa = dither.g;
        float unpackedValue = mantissa * exp2(exponent);
        
        float transparencyWithDistanceImpact = transparency - (fakeDistance * distanceImpact * transparency);
        float depth = 0.0;
        
        if(isPerspective) {
            depth = linearizeDepth(gl_FragCoord.z, nearPlane, farPlane);
            depth = smoothstep(0.0, perspectiveDitherCutoffDistance, depth);
        } else {
            depth = smoothstep(0.0, orthoDitherCutoffDistance, orthoSize);
        }
        transparencyWithDistanceImpact = mix(transparencyWithDistanceImpact, 0.0, depth * ditherDistanceFade);
        if (unpackedValue < transparencyWithDistanceImpact) {
            discard;
        }
            #endif
            
            // #include HSVColorChanger.glsl
        #ifdef useHSVMapping
            finalDiffuse = rgb2hsv_2(finalDiffuse);
        
            finalDiffuse.x *= hsvValues.x;
            finalDiffuse.y *= hsvValues.y;
            finalDiffuse.z *= hsvValues.z;
        
            finalDiffuse = hsv2rgb_smooth(finalDiffuse);
        #endif
        
        
        
            if (highlighted) {
                finalDiffuse = highlightColors[highlightIndex - 1];
            }
            
            
            // #typescript options?.clipPlaneColorBlending()
        ${options?.clipPlaneColorBlending()}
            
            gl_FragColor = vec4(finalDiffuse, opaqueness);
        }`
};
