// BVLE Voxels - Toping Vertex Shader (Phase 4.2)
// Instanced vertex pulling: reads mesh vertices from t4, instance positions from t5.
// Push constants carry per-draw-group offsets.

#include "voxelCommon.hlsli"

// Toping mesh vertex (must match C++ TopingVertex, 24 bytes)
struct TopingVtx {
    float3 position; // local to voxel [0,1]^3
    float3 normal;
};

// Toping instance (just the world position, 12 bytes)
struct TopingInst {
    float3 worldPos;
};

StructuredBuffer<TopingVtx>  topingVertices  : register(t4);
StructuredBuffer<TopingInst> topingInstances : register(t5);

// Push constants — repurposed fields for toping draws:
//   chunkIndex → vertexOffset (into t4)
//   quadOffset → instanceOffset (into t5)
//   flags      → materialID
struct TopingPush {
    uint vertexOffset;
    uint instanceOffset;
    uint materialID;
    uint pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7, pad8;
};
[[vk::push_constant]] ConstantBuffer<TopingPush> push : register(b999);

struct VSOutput {
    float4 position : SV_POSITION;
    float3 worldPos : WORLDPOS;
    float3 normal   : NORMAL;
    float  localHeight : LOCALHEIGHT;  // height above voxel face (0=base, 1=tip)
    nointerpolation uint materialID : MATERIALID;
};

[RootSignature(VOXEL_ROOTSIG)]
VSOutput main(uint vertexID : SV_VertexID, uint instanceID : SV_InstanceID) {
    TopingVtx vtx   = topingVertices[push.vertexOffset + vertexID];
    TopingInst inst  = topingInstances[push.instanceOffset + instanceID];

    float3 worldPos = inst.worldPos + vtx.position;

    // ── Wind animation (vegetation only) ────────────────────────
    // Height above the voxel face (y=1 in local space) drives amplitude.
    // Quadratic scaling: base stays anchored, tips sway the most.
    if (push.materialID != 3u) { // not stone
        float localHeight = vtx.position.y - 1.0;
        if (localHeight > 0.0) {
            float heightFactor = localHeight * localHeight; // quadratic
            float phase = worldPos.x * 1.8 + worldPos.z * 1.3 + windTime * 3.5;
            float phase2 = worldPos.x * 0.7 - worldPos.z * 2.1 + windTime * 2.7;
            float swayX = sin(phase) * 0.11 * heightFactor;
            float swayZ = cos(phase2) * 0.08 * heightFactor;
            float swayY = -abs(sin(phase * 0.7)) * 0.02 * heightFactor; // slight droop
            worldPos.x += swayX;
            worldPos.y += swayY;
            worldPos.z += swayZ;
        }
    }

    VSOutput output;
    output.position   = mul(viewProjection, float4(worldPos, 1.0));
    output.worldPos   = worldPos;
    output.normal     = vtx.normal;
    output.localHeight = saturate((vtx.position.y - 1.0) * 5.0); // normalized: 0=base, 1=tip (blades ~0.06-0.24 tall)
    output.materialID  = push.materialID;
    return output;
}
