#include "/lib/config.glsl"

/* Color utils */

#if defined THE_END
    #include "/lib/color_utils_end.glsl"
#elif defined NETHER
    #include "/lib/color_utils_nether.glsl"
#else
    #include "/lib/color_utils.glsl"
#endif

/* Uniforms */

uniform float viewWidth;
uniform float viewHeight;
uniform vec3 sunPosition;
uniform int isEyeInWater;
uniform float dayNightMix;
uniform float far;
uniform float rainStrength;
uniform ivec2 eyeBrightnessSmooth;
uniform mat4 gbufferProjectionInverse;

#ifdef DISTANT_HORIZONS
    uniform int dhRenderDistance;
#endif

#ifdef VOXY
    uniform int vxRenderDistance;
#endif

#ifdef DYN_HAND_LIGHT
    uniform int heldItemId;
    uniform int heldItemId2;
#endif

#ifdef UNKNOWN_DIM
    uniform sampler2D lightmap;
#endif

#if defined FOLIAGE_V || defined THE_END || defined NETHER
    uniform mat4 gbufferModelView;
#endif

#if defined FOLIAGE_V || defined SHADOW_CASTING || defined GBUFFER_WEATHER || defined GBUFFER_TERRAIN || (defined MATERIAL_GLOSS && !defined NETHER)
    uniform mat4 gbufferModelViewInverse;
#endif

#if defined MATERIAL_GLOSS && !defined NETHER
    uniform int worldTime;
    uniform vec3 moonPosition;
#endif

#if defined SHADOW_CASTING && !defined NETHER
    uniform mat4 shadowModelView;
    uniform mat4 shadowProjection;
    uniform vec3 shadowLightPosition;
#endif

#if WAVING == 1 || defined GBUFFER_WEATHER || defined PLAYER_INTERACTIVE_FOLIAGE
    uniform vec3 cameraPosition;
#endif

#ifdef PLAYER_INTERACTIVE_FOLIAGE
    // Iris: cameraPosition - player head position. Unlike cameraPosition alone,
    // this keeps interaction centered on the player in third-person views.
    uniform vec3 relativeEyePosition;
#endif

#if WAVING == 1 || defined GBUFFER_WEATHER
    uniform float frameTimeCounter;
#endif

#ifdef GBUFFER_WEATHER
    uniform vec3 previousCameraPosition;
#endif

#if defined IS_IRIS && defined THE_END && MC_VERSION >= 12109
    uniform float endFlashIntensity;
#endif

#if defined GBUFFER_ENTITIES
    uniform int entityId;
#endif

/* Ins / Outs */

varying vec2 texcoord;
varying vec4 tintColor;
varying float frogAdjust;
varying vec3 directLightColor;
varying vec3 candleColor;
varying float directLightStrength;
varying vec3 omniLight;

#ifdef PROCEDURAL_TUFT_GRASS
    // Private bridge to the geometry stage. These values describe the source
    // terrain vertex; they are not consumed by the fragment stage directly.
    varying vec3 grassPlayerPosition;
    varying vec3 grassSourceNormal;
    varying float grassEntityId;
    varying float grassFogCoord;
#endif

#ifdef GBUFFER_WEATHER
    varying vec3 weatherWindView;
    varying float weatherCameraResponse;
    varying vec3 weatherViewPosition;
#endif

#ifdef GBUFFER_TERRAIN
    varying float surfaceSkyExposure;
#endif

#if defined SHADOW_CASTING && SHADOW_LOCK > 0 && !defined NETHER
    varying vec3 vWorldPos;
    varying vec3 vNormal;
    varying vec3 vBias;
#endif

#if defined GBUFFER_TERRAIN || defined GBUFFER_HAND || defined GBUFFER_ENTITIES
    varying float isEmissiveEntity;
#endif

#ifdef FOLIAGE_V
    varying float isFoliage;
#endif

#if defined SHADOW_CASTING && !defined NETHER
    varying vec3 shadowPos;
    varying float shadowDiffuse;
#endif

#if defined MATERIAL_GLOSS && !defined NETHER
    varying vec3 flatNormal;
    varying vec3 viewPositionNormalized;
    varying vec2 lmcoordAlt;
    varying float glossFactor;
    varying float glossPower;
    varying float lumaFactor;
    varying float lumaPower;
#endif

attribute vec4 mc_Entity;

#if WAVING == 1 || defined PLAYER_INTERACTIVE_FOLIAGE
    attribute vec2 mc_midTexCoord;
#endif

/* Utility functions */

#if AA_TYPE > 0
    #include "/src/taa_offset.glsl"
#endif

#include "/lib/basic_utils.glsl"

#if defined SHADOW_CASTING && !defined NETHER
    #include "/lib/shadow_vertex.glsl"
#endif

#if WAVING == 1
    #include "/lib/vector_utils.glsl"
#endif

#include "/lib/luma.glsl"

// MAIN FUNCTION ------------------

void main() {
    vec2 eyeBrightSmoothFloat = vec2(eyeBrightnessSmooth);
    vec3 zenithSkyColor;
    float visibleSky;

    #include "/src/basiccoords_vertex.glsl"
    #include "/src/position_vertex.glsl"

    #ifdef PROCEDURAL_TUFT_GRASS
        grassPlayerPosition = position.xyz;
        grassSourceNormal = normalize(
            mat3(gbufferModelViewInverse) * (gl_NormalMatrix * gl_Normal)
        );
        grassEntityId = mc_Entity.x;
    #endif
    #ifdef GBUFFER_WEATHER
        #include "/src/weather_vertex.glsl"
    #endif
    #include "/src/hi_sky.glsl"
    #include "/src/light_vertex.glsl"
    #ifdef GBUFFER_TERRAIN
        surfaceSkyExposure = visibleSky;
    #endif
    #include "/src/fog_vertex.glsl"

    // Glowing blocks
    #if defined GBUFFER_TERRAIN || defined GBUFFER_HAND || defined GBUFFER_ENTITIES
        isEmissiveEntity = 0.0;
        if(mc_Entity.x == ENTITY_NO_SHADOW_FIRE || mc_Entity.x == ENTITY_EMMISIVE || mc_Entity.x == ENTITY_S_EMMISIVE) {
            isEmissiveEntity = 1.0;
        }
    #endif

    #if defined SHADOW_CASTING && !defined NETHER
        #include "/src/shadow_src_vertex.glsl"
    #endif

    #if defined FOLIAGE_V && !defined NETHER
        #ifdef SHADOW_CASTING
            if (isFoliage > .2) {
                directLightStrength =
                    mix(
                        directLightStrength,
                        farDirectLightStrength,
                        clamp((gl_Position.z / SHADOW_LIMIT) * 2.0 - 0.5, 0.0, 1.0)
                    );
            }
        #endif
    #endif

    #if defined MATERIAL_GLOSS && !defined NETHER
        lumaFactor = 1.0;
        lumaPower = 2.0;
        glossPower = 6.0;
        glossFactor = 1.05;

        if(mc_Entity.x == ENTITY_SAND) {  // Sand-like block
            lumaPower = 4.0;
        } else if(mc_Entity.x == ENTITY_METAL) {  // Metal-like block
            lumaFactor = 1.35;
            lumaPower = -1.0;  // Metallic
            glossPower = 100.0;
        } else if(mc_Entity.x == ENTITY_FABRIC) {  // Fabric-like blocks
            glossPower = 3.0;
            glossFactor = 0.1;
        }

        flatNormal = normal;
        viewPositionNormalized = normalize(viewPosition.xyz);

        lmcoordAlt = lmcoord;
    #endif

    #if defined GBUFFER_ENTITY_GLOW
        gl_Position.z *= 0.01;
    #endif

    #if defined SHADOW_CASTING && SHADOW_LOCK > 0 && !defined NETHER
        vNormal = shadowWorldNormal;
        vBias = bias;
    #endif

    #ifdef SUPPRESS_REPLACED_VANILLA_GRASS
      #if GRASS_MODE != 0
        // The procedural grass-block surface replaces this crossed vanilla
        // model. Collapse it before rasterization so it never enters the costly
        // cutout geometry program merely to be discarded there.
        if (abs(mc_Entity.x - ENTITY_VANILLA_GRASS) < 0.25) {
            gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
        }
      #endif
    #endif
}
