cbuffer MatrixBuffer : register(vs, cb0)
{
    matrix worldMatrix;
    matrix viewMatrix;
    matrix projectionMatrix;
};
	
cbuffer CameraBuffer : register(vs, cb1)
{
    float3 cameraPosition;
	float CameraBuffer_padding;
};

cbuffer SkeletonInfoBuffer : register(vs, cb2)
{
	matrix mWorldMatrixArray[128];
}

struct VertexInputType
{
    float4 position : POSITION;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;
	float3 tangent : TANGENT;
	int bones[4] : BONES;
	float weights[3] : WEIGHTS;
	uint materialId : MATERIALID;
};

struct PixelInputType
{
    float4 position : SV_POSITION;
	float4 worldPosition : POSITION1;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;
    float3 tangent : TANGENT;
    float3 binormal : BINORMAL;
	float3 viewDirection : TEXCOORD1;
};

PixelInputType LightVertexShader(VertexInputType input)
{
    PixelInputType output;
    float4 worldPosition;

    // Change the position vector to be 4 units for proper matrix calculations.
	input.position.w = 1.0f;
	output.worldPosition = 0.0f;
	output.normal = 0.0f;
	output.tangent = 0.0f;

    // cast the vectors to arrays for use in the for loop below
    float BlendWeightsArray[3] = (float[3])input.weights;
    
	float LastWeight = 0.0f;
    // calculate the pos/normal using the "normal" weights 
    // and accumulate the weights to calculate the last weight
	matrix transformMatrix = 0.0f;
	[unroll]
    for (int iBone = 0; iBone < 3; iBone++)
    {
		int matrixIndex = input.bones[iBone]+1;
        LastWeight += input.weights[iBone];
        
        transformMatrix += mWorldMatrixArray[matrixIndex] * input.weights[iBone];
        output.normal += mul(input.normal, mWorldMatrixArray[matrixIndex]) * input.weights[iBone];
		output.tangent += mul(input.tangent, mWorldMatrixArray[matrixIndex]) * input.weights[iBone];
    }
    LastWeight = 1.0f - LastWeight; 

	int matrixIndex = input.bones[3]+1;
    transformMatrix +=  mWorldMatrixArray[matrixIndex] * LastWeight;
    output.normal += mul(input.normal, mWorldMatrixArray[matrixIndex]) * LastWeight;
	output.tangent += mul(input.tangent, mWorldMatrixArray[matrixIndex]) * LastWeight;
	
	output.worldPosition = mul(input.position, transformMatrix);
	
/*	output.worldPosition = input.position;
	output.normal = input.normal;
	output.tangent = input.tangent;*/

    // Calculate the position of the vertex against the world, view, and projection matrices.
    output.worldPosition = mul(output.worldPosition, worldMatrix);
    output.position = mul(output.worldPosition, viewMatrix);
    output.position = mul(output.position, projectionMatrix);
	output.worldPosition = output.worldPosition / output.worldPosition.w;	

    // Store the texture coordinates for the pixel shader.
    output.tex = input.tex;
	
    // Calculate the normal vector against the world matrix only.
    output.normal = mul(output.normal, (float3x3)worldMatrix);
    output.normal = normalize(output.normal);
	
	// Calculate the tangent vector against the world matrix only and then normalize the final value.
    output.tangent = mul(output.tangent, (float3x3)worldMatrix);
    output.tangent = normalize(output.tangent);

    //output.binormal = mul(b, (float3x3)worldMatrix);
	output.binormal = cross(input.normal, input.tangent);
//	output.binormal = mul(output.binormal, (float3x3)worldMatrix); // TODO: Check if it is needed
    output.binormal = normalize(output.binormal);
	
    // Determine the viewing direction based on the position of the camera and the position of the vertex in the world.
    output.viewDirection = cameraPosition.xyz - output.worldPosition.xyz;
	
    // Normalize the viewing direction vector.
    output.viewDirection = normalize(output.viewDirection);
	
    return output;
}