//#include "../Engine/Graphics/Direct3D12/Shaders/Common.hlsli"
#include "D:\AllWX\AllC\XEngine\Engine\Graphics\Direct3D12\Shaders\Common.hlsli"

struct VertexOut
{
    float4 HomogeneousPosition : SV_Position;
    float3 WorldPosition : POSITIONT;
    float3 WorldNormal : NORMAL;
    float3 WorldTangent : TANGENT;
    float2 uv : TEXTURE;
};

struct PixelOut
{
    float4 Color : SV_TARGET0;
};

#define ElementsTypeStaticNormal                                0x01
#define ElementsTypeStaticNormalTexture                         0x03
#define ElementsTypeStaticColor                                 0x04
#define ElementsTypeSkeletal                                    0x08
#define ElementsTypeSkeletalColor                               ElementsTypeSkeletal | ElementsTypeStaticColor
#define ElementsTypeSkeletalNormal                              ElementsTypeSkeletal | ElementsTypeStaticNormal
#define ElementsTypeSkeletalNormalColor                         ElementsTypeSkeletalNormal | ElementsTypeSkeletalColor
#define ElementsTypeSkeletalNormalTexture                       ElementsTypeSkeletal | ElementsTypeStaticNormalTexture
#define ElementsTypeSkeletalNormalTextureColor                  ElementsTypeSkeletalNormalTexture | ElementsTypeStaticColor

struct VertexElement
{
#if   ELEMENTS_TYPE == ElementsTypeStaticNormal
    uint            ColorTSign;
    uint16_t2       Normal;
#elif ELEMENTS_TYPE == ElementsTypeStaticNormalTexture
    uint            ColorTSign;
    uint16_t2       Normal;
    uint16_t2       Tangent;
    float2          UV;
#elif ELEMENTS_TYPE == ElementsTypeStaticColor
#elif ELEMENTS_TYPE == ElementsTypeSkeletal
#elif ELEMENTS_TYPE == ElementsTypeSkeletalColor
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormal
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormalColor
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormalTexture
#elif ELEMENTS_TYPE == ElementsTypeSkeletalNormalTextureColor
    
#endif
};


const static float InvIntervals = 2.f / ((1 << 16) - 1);

ConstantBuffer<GlobalShaderData> GlobalData : register(b0, space0);
ConstantBuffer<PerObjectData> PerObjectBuffer : register(b1, space0);
StructuredBuffer<float3> VertexPositions : register(t0, space0);
StructuredBuffer<VertexElement> Elements : register(t1, space0);

StructuredBuffer<DirectionalLightParameters> DirectionLights : register(t3, space0);

VertexOut TestShaderVS(in uint VertexIdx : SV_VertexID)
{
    VertexOut vsOut;
    float4x4 IdentityMatrix =
    {
        1.0f, 0.0f, 0.0f, 0.0f,
         0.0f, 1.0f, 0.0f, 0.0f,
         0.0f, 0.0f, 1.0f, 0.0f,
         0.0f, 0.0f, 0.0f, 1.0f
    };
    
    float4 position = float4(VertexPositions[VertexIdx], 1.f);
    float4 worldPosition = mul(PerObjectBuffer.World, position);
    
#if ELEMENTS_TYPE == ElementsTypeStaticNormal
    VertexElement element = Elements[VertexIdx];
    float2 nXY = element.Normal * InvIntervals - 1.f;
    uint signs = (element.ColorTSign >> 24) & 0xff;
    
    float nSign = float(signs & 0x02) - 1;
    float3 normal = float3(nXY.x, nXY.y, sqrt(saturate(1.f - dot(normal.xy, normal.xy))) * nSign);
    
    vsOut.HomogeneousPosition = mul(PerObjectBuffer.WorldViewProjection, position);
    vsOut.WorldPosition = worldPosition.xyz;
    vsOut.WorldNormal = 0;
    vsOut.WorldTangent = 0.f;
    vsOut.uv = 0.f;
#elif ELEMENTS_TYPE == ElementsTypeStaticNormalTexture
    VertexElement element = Elements[VertexIdx];
    float2 nXY = element.Normal * InvIntervals - 1.f;
    uint signs = (element.ColorTSign >> 24) & 0xff;
    
    float nSign = float(signs & 0x02) - 1;
    float3 normal = float3(nXY.x, nXY.y, sqrt(saturate(1.f - dot(normal.xy, normal.xy))) * nSign);
    
    vsOut.HomogeneousPosition = mul(PerObjectBuffer.WorldViewProjection, position);
    vsOut.WorldPosition = worldPosition.xyz;
    vsOut.WorldNormal = mul(float4(normal, 0.f), PerObjectBuffer.InvWorld).xyz;
    vsOut.WorldNormal = mul(PerObjectBuffer.World, float4(normal, 0.f)).xyz;
    //vsOut.WorldNormal = sqrt(saturate(1.f - dot(normal.xy, normal.xy))) * nSign;
    vsOut.WorldTangent = 0.f;
    vsOut.uv = 0.f;
#else
#undef ELEMENTS_TYPE
    vsOut.HomogeneousPosition = mul(PerObjectBuffer.WorldViewProjection, position);
    vsOut.WorldPosition = worldPosition.xyz;
    vsOut.WorldNormal = 0.f;
    vsOut.WorldTangent = 0.f;
    vsOut.uv = 0.f;
#endif

    return vsOut;
}

[earlydepthstencil]
PixelOut TestShaderPS(in VertexOut psIn)
{
    PixelOut psOut;
    psOut.Color = float4(psIn.WorldNormal, 1);
    float4x4 IdentityMatrix =
    {
        1.0f, 0.0f, 0.0f, 0.0f,
         0.0f, 1.0f, 0.0f, 0.0f,
         0.0f, 0.0f, 1.0f, 0.0f,
         0.0f, 0.0f, 0.0f, 1.0f
    };
    float3 normal = normalize(psIn.WorldNormal);
    float3 viewDir = normalize(GlobalData.CameraPosition - psIn.WorldPosition);
    
    float3 color = 0;
    
    for (uint i = 0; i < GlobalData.NumIdrectionalLights; ++i)
    {
        DirectionalLightParameters light = DirectionLights[i];
        
        float3 lr = normalize(light.Direction);
        float3 lightDirection = mul(IdentityMatrix, float4(lr, 0)).xyz;
    
        //float3 lightDirection = normalize(float3(0, 1, 0));
        float diffuse = max(dot(normal, -lightDirection), 0.f);
        float3 h = (viewDir + lightDirection);
        float specular = pow(max(dot(normal, h), 0.f), 16) * 0.5f;
     
        
        //float3 lightColor = float3(1, 1, 1);
        float3 lightColor = light.Color * light.Intensity;
        //color = dot(normal, -lr);
        color = normal;
    }
    
    
    float3 ambient = 10 / 255.f;
    psOut.Color = saturate(float4(color + ambient, 1.f));
    
    return psOut;
}