Shader "Unlit/RenderPrimitivesIndirectShader"
{
    Properties
    {
        _BaseColor("Base Color", Color) = (0.9622641, 0.6245805, 0.09441077, 1)
    }
    SubShader
    {
        Pass
        {
            ZWrite On
            ZTest LEqual
            
            HLSLPROGRAM

            #pragma vertex vert
            #pragma geometry geom
            #pragma fragment frag
            #define ATTRIBUTES_NEED_NORMAL
            #define ATTRIBUTES_NEED_TANGENT
            #define VARYINGS_NEED_TANGENT_TO_WORLD
            
            #pragma multi_compile_instancing
            #pragma multi_compile _ DOTS_INSTANCING_ON

            #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassRenderers.hlsl"
            #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl"
            #define UNITY_INDIRECT_DRAW_ARGS IndirectDrawIndexedArgs
            #include "UnityIndirect.cginc"

            StructuredBuffer<int> _Triangles;
            StructuredBuffer<float3> _Positions;
            uniform uint _BaseVertexIndex;
            uniform float _NumInstances;
            float4 _BaseColor;

            struct VertexToGeometry
            {
                float4 position : POSITION;
                float3 positionOS : TEXCOORD0;
            };

            struct GeometryToFragment
            {
                float4 position : POSITION;
                float3 normal : NORMAL;
            };

            //check it also: https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Graphics.RenderPrimitivesIndirect.html
            VertexToGeometry vert(AttributesMesh v, uint vertexID: SV_VertexID, uint svInstanceID : SV_InstanceID)
            {
                VertexToGeometry vtg;
                uint cmdID = GetCommandID(0);
                uint instanceID = GetIndirectInstanceID(svInstanceID);
                float3 pos = _Positions[_Triangles[GetIndirectVertexID(vertexID)] + _BaseVertexIndex];
                v.positionOS = (v.positionOS + pos + 1e-3 - float3(_NumInstances, 0, 0) + float4(1 + instanceID * 2, 1 + cmdID * 2, 0, 0));
                vtg.position = TransformObjectToHClip(v.positionOS);
                vtg.positionOS = TransformObjectToWorld(v.positionOS);
                return vtg;
            }

            [maxvertexcount(3)]
            void geom(triangle VertexToGeometry i[3], inout TriangleStream<GeometryToFragment> Stream)
            {                
                float3 Normal = normalize((cross(i[1].positionOS.xyz - i[0].positionOS.xyz, i[2].positionOS.xyz - i[0].positionOS.xyz)));
                [unroll]
                for (int j = 0; j < 3; j++)
                {
                    GeometryToFragment Output;

                    Output.position = i[j].position;
                    Output.normal = Normal;

                    Stream.Append(Output);
                }

                //Stream.RestartStrip();
            }
            
            float4 frag(GeometryToFragment input) : SV_Target
            {
                DirectionalLightData DirectionalLightData = _DirectionalLightDatas[0];

                float3 finalColor = SRGBToLinear(_BaseColor);
                finalColor *= DirectionalLightData.color;
                finalColor *= GetCurrentExposureMultiplier();
                finalColor *= saturate(dot(input.normal, -DirectionalLightData.forward));
                finalColor /= PI;
                
                return float4(finalColor, 1.0f);
            }
            
            ENDHLSL
        }
        Pass
        {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }

            ZWrite On
            ZTest LEqual

            HLSLPROGRAM

            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster
            
            #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassRenderers.hlsl"
            #define UNITY_INDIRECT_DRAW_ARGS IndirectDrawIndexedArgs
            #include "UnityIndirect.cginc"
            
            StructuredBuffer<int> _Triangles;
            StructuredBuffer<float3> _Positions;
            uniform uint _BaseVertexIndex;
            uniform float _NumInstances;

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            v2f vertShadowCaster(AttributesMesh v, uint vertexID: SV_VertexID, uint svInstanceID : SV_InstanceID)
            {
                InitIndirectDrawArgs(0);
                v2f o;
                uint cmdID = GetCommandID(0);
                uint instanceID = GetIndirectInstanceID(svInstanceID);
                float3 pos = _Positions[_Triangles[GetIndirectVertexID(vertexID)] + _BaseVertexIndex];
                o.pos = TransformObjectToHClip(v.positionOS + pos + 1e-3 - float3(_NumInstances, 0, 0) + float3(1 + 2 * instanceID, 1 + cmdID * 2, 0)); 
                return o;
            }

            float4 fragShadowCaster(v2f i) : SV_Target
            {       
                return 0;
            }
           
            ENDHLSL
        }

        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode" = "DepthOnly" }

            ZWrite On
            ZTest LEqual

            HLSLPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            
            #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassRenderers.hlsl"
            #define UNITY_INDIRECT_DRAW_ARGS IndirectDrawIndexedArgs
            #include "UnityIndirect.cginc"
            
            StructuredBuffer<int> _Triangles;
            StructuredBuffer<float3> _Positions;
            uniform uint _BaseVertexIndex;
            uniform float _NumInstances;

            struct v2f
            {
                float4 pos : SV_POSITION;
            };
            v2f vert(AttributesMesh v, uint vertexID: SV_VertexID, uint svInstanceID : SV_InstanceID)
            {                
                InitIndirectDrawArgs(0);
                v2f o;
                uint cmdID = GetCommandID(0);
                uint instanceID = GetIndirectInstanceID(svInstanceID);
                float3 pos = _Positions[_Triangles[GetIndirectVertexID(vertexID)] + _BaseVertexIndex];
                o.pos = TransformObjectToHClip(v.positionOS + pos + 1e-3 - float3(_NumInstances, 0, 0) + float3(1 + 2 * instanceID, 1 + cmdID * 2, 0)); 
                return o;
            }

            float4 frag(v2f i) : SV_Target
            {       
                return 0;
            }
           
            ENDHLSL
        }

        //HTraceWSGI
        Pass
        {   
            Name "HTrace Voxelization"
            Tags { "LightMode" = "HTraceVoxelization" }
            
            Cull Off
            ZClip Off
            ZWrite Off
            Conservative False

            HLSLPROGRAM

            #pragma require geometry
            #pragma require randomwrite

            #pragma multi_compile_instancing
            #pragma multi_compile _ DOTS_INSTANCING_ON
            #pragma multi_compile CONSTANT_VOXELIZATION PARTIAL_VOXELIZATION DYNAMIC_VOXELIZATION
            
                         #include "../../../../HTraceWSGI/Resources/HTraceWSGI/Includes/VoxelizationStages.hlsl"
            #define UNITY_INDIRECT_DRAW_ARGS IndirectDrawIndexedArgs
            #include "UnityIndirect.cginc"

            #pragma vertex VertCustom
            #pragma geometry VoxelizationGeom
            #pragma fragment VoxelizationFrag
            
            StructuredBuffer<int> _Triangles;
            StructuredBuffer<float3> _Positions;
            uniform uint _StartIndex;
            uniform uint _BaseVertexIndex;
            uniform float _NumInstances;

            // --- Vertex Stage ---
            VertexToGeometry VertCustom(AttributesMesh inputMesh, uint vertexID: SV_VertexID, uint svInstanceID : SV_InstanceID)
            {
                VertexToGeometry Output = VoxelizationVert(inputMesh);

                uint cmdID = GetCommandID(0);
                uint instanceID = GetIndirectInstanceID(svInstanceID);
                float3 pos = _Positions[_Triangles[GetIndirectVertexID(vertexID)] + _BaseVertexIndex];
                Output.PositionCS = TransformObjectToHClip(inputMesh.positionOS + pos + 1e-3 - float3(_NumInstances, 0, 0) + float3(1 + 2 * instanceID, 1 + cmdID * 2, 0));
                
                #ifdef UNITY_REVERSED_Z
                Output.PositionCS.z = mad(Output.PositionCS.z, -2.0, 1.0);
                #endif
                
                return Output;
            }

            ENDHLSL
        }
    }
}

