uniform sampler2D noisetex;

uniform mat4 gbufferModelView;
uniform mat4 gbufferModelViewInverse;
uniform vec3 cameraPosition;
uniform float frameTimeCounter;
uniform float wetnessCustom;


// Dynamic light uniforms
uniform int heldBlockLightValue;
uniform int heldBlockLightValue2;
uniform int heldItemId;
uniform int heldItemId2;

uniform vec2 taaOffset;

#ifndef MC_GL_VENDOR_INTEL
	#define attribute in
#endif

attribute vec4 mc_Entity;
attribute vec4 mc_midTexCoord;
attribute vec4 at_tangent;

out vec4 vs_tint;
out vec2 vs_texcoord;
out vec3 vs_minecraftPos;
out vec3 vs_viewPos;

flat out mat3 vs_tbnMatrix;
flat out uint vs_materialIDs;

out vec2 vs_lightmap;
out vec2 originalLightmap; // Store original lightmap for color calculation
out float vertexDistance;  // Distance for dynamic light calculation
flat out int itemId1;      // Pass item IDs to fragment shader
flat out int itemId2;

// Snow world - проверка блока сверху
out float snowBlockAbove; // 0.0 = нет блока сверху, 1.0 = есть блок

#include "/lib/Head/Common.inc"
#include "/lib/Lighting/HandLightnoVoxel.glsl"

#if defined PARALLAX || ANISOTROPIC_FILTER > 0
	out vec2 vs_tileCoord;
	flat out vec2 vs_tileOffset;
	flat out vec2 vs_tileScale;
#endif

#define PLANTS_WAVE_EFFECTS
//#define PLANTS_TOUCH_EFFECTS

void main() {
	vs_tint = gl_Color;
	vs_texcoord = gl_MultiTexCoord0.xy;

	vec2 baseLightmap = saturate(gl_MultiTexCoord1.xy * rcp(240.0));
	originalLightmap = baseLightmap; // Store original for color tinting

	#if defined PARALLAX || ANISOTROPIC_FILTER > 0
		vec2 midCoord = (gl_TextureMatrix[0] * mc_midTexCoord).xy;
		vec2 minMidCoord = vs_texcoord - midCoord;
		vs_tileOffset = min(vs_texcoord, midCoord - minMidCoord);
		vs_tileScale = abs(minMidCoord) * 2.0;
		vs_tileCoord = sign(minMidCoord) * 0.5 + 0.5;
	#endif

	vec4 position = gbufferModelViewInverse * gl_ModelViewMatrix * gl_Vertex;

    vs_tbnMatrix[2] = normalize(gl_NormalMatrix * gl_Normal);
	#if defined MC_NORMAL_MAP || defined RAIN_SPLASH_EFFECT
		vs_tbnMatrix[0] = normalize(gl_NormalMatrix * at_tangent.xyz);
		vs_tbnMatrix[1] = cross(vs_tbnMatrix[0], vs_tbnMatrix[2]) * sign(at_tangent.w);
	#endif

	vs_materialIDs = uint(max0(mc_Entity.x - 1e4));

	#ifdef MOD_BLOCK_SUPPORT
	#endif

	#ifdef PLANTS_TOUCH_EFFECTS
		if (vs_materialIDs == 1u || vs_materialIDs == 2u) {
			if (length((position.xyz + vec3(0.0, 2.0, 0.0))) < 2.0) position.xz *= 1.0 + max0(5.0 / max(length((position.xyz + vec3(0.0, 2.0, 0.0)) * vec3(8.0, 2.0, 8.0) - vec3(0.0, 2.0, 0.0)), 2.0) - 0.625);
		}
		if (vs_materialIDs == 4u || vs_materialIDs == 5u) {
			if (length(position.xyz) < 2.0) position.xz *= 1.0 + max0(5.0 / max(length(position.xyz * vec3(8.0, 2.0, 8.0)), 2.0) - 0.625);
		}
	#endif

	position.xyz += cameraPosition.xyz;

	// === SNOW WORLD: Проверка блока сверху ===
	// Проверяем нормаль - если смотрит вверх, проверяем skylight
	vec3 worldNormal = normalize(gl_NormalMatrix * gl_Normal);
	if (worldNormal.y > 0.9) {
		// Это верхняя грань
		// Если skylight максимальный (15/15 = 1.0), значит блока сверху нет
		snowBlockAbove = baseLightmap.y < 0.99 ? 1.0 : 0.0;
	} else {
		snowBlockAbove = 1.0; // Для боковых граней - считаем что сверху есть блок
	}

	#ifdef PLANTS_WAVE_EFFECTS
		float tick = frameTimeCounter * PI;

		float grassWeight = step(gl_MultiTexCoord0.y, mc_midTexCoord.y);
		const float lightWeight = pow4(saturate(baseLightmap.y * 1.5 - 0.5));

		if (vs_materialIDs == 5u) {
			grassWeight *= 0.8;
		} else if (vs_materialIDs == 4u) {
			grassWeight = grassWeight * 0.8 + 0.8;
		}

		// Grass (включая tall_grass upper/lower = 4/5, short_grass = 34222)
		if (vs_materialIDs > 0u && vs_materialIDs < 6u || vs_materialIDs == 34222u) {
			vec2 noise = texture(noisetex, position.xz * rcp(256.0) + sin(tick * 7e-4) * 2.0 - 1.0).xy * 1.3 - 0.3;
			vec2 wave = sin(dot(position.xz, vec2(1.0)) + tick) * fma(wetnessCustom, 0.12, 0.06) * noise - cossin(PI * 0.2) * position.y * 0.0015;
			position.xz += wave * grassWeight * lightWeight;
		}

		// Leaves — многочастотная турбулентность (реалистичное шелестение листвы)
		if (vs_materialIDs == 7u) {
			// Две частоты шума: медленная (общий порыв ветра) + быстрая (дрожание листиков)
			vec2 noiseSlowXZ  = texture(noisetex, position.xz * rcp(256.0) + sin(tick * 7e-4) * 2.0 - 1.0).xy * 1.3 - 0.3;
			vec2 noiseFastXZ  = texture(noisetex, position.xz * rcp(64.0)  + tick * 0.0013).xy * 2.0 - 1.0;
			float noiseY      = texture(noisetex, position.xz * rcp(128.0) + tick * 0.0008).z * 2.0 - 1.0;

			float windStr = fma(wetnessCustom, 0.14, 0.07);

			// Медленный глобальный изгиб кроны
			vec3 slowWave = sin(dot(position.xyz, vec3(1.0)) + tick * 0.8)
			              * vec3(noiseSlowXZ.x, noiseSlowXZ.x * noiseSlowXZ.y * 0.4, noiseSlowXZ.y)
			              * windStr;

			// Быстрое индивидуальное дрожание каждой ветки
			vec3 fastWave = sin(dot(position.xyz, vec3(2.3, 1.7, 2.1)) + tick * 2.2)
			              * vec3(noiseFastXZ.x, noiseY * 0.25, noiseFastXZ.y)
			              * windStr * 0.45;

			position.xyz += (slowWave + fastWave) * lightWeight;
		}
	#endif

	if (vs_materialIDs > 0u) { vs_materialIDs = max(vs_materialIDs, 6u); }
	#ifdef GENERAL_GRASS_FIX
	else if (abs(gl_Normal.x) > 0.01 && abs(gl_Normal.x) < 0.99 ||
			 abs(gl_Normal.y) > 0.01 && abs(gl_Normal.y) < 0.99 ||
			 abs(gl_Normal.z) > 0.01 && abs(gl_Normal.z) < 0.99
			) vs_materialIDs = 6u;
	#endif

	vs_minecraftPos = position.xyz;

	// Pass item IDs to fragment shader
	itemId1 = heldItemId;
	itemId2 = heldItemId2;

	// Calculate distance for dynamic lighting
	vec4 viewPosition = gl_ModelViewMatrix * gl_Vertex;
	vec4 playerPos = gbufferModelViewInverse * viewPosition;
	vertexDistance = length(playerPos.xyz);
	
	// Apply dynamic lighting to vs_lightmap
	vs_lightmap = adjustLightmapWithDynamicLight(baseLightmap, vertexDistance, heldBlockLightValue, heldBlockLightValue2);

	position.xyz -= cameraPosition;
	// ВАЖНО: tcs → tes → geom всегда активны в пайплайне.
	// Vert всегда передаёт player-relative world position (w=0) —
	// финальную проекцию делает geom через toClipSpace3Geom().
	// Если SHADER_GRASS выключен — geom делает pass-through и сам проецирует.
	gl_Position = vec4(position.xyz, 0.0);

	vs_viewPos = mat3(gl_ModelViewMatrix) * gl_Vertex.xyz + gl_ModelViewMatrix[3].xyz;
}