#include "VertexBuffer.hpp"

#include "FVF.hpp"

#include <malloc.h>

namespace swShader
{
	VertexBuffer::VertexBuffer(unsigned int flags, int n)
	{
		position[0] = 0;
		position[1] = 0;
		blendWeight = 0;
		blendIndices = 0;
		normal[0] = 0;
		normal[1] = 0;
		pSize = 0;
		texCoord[0] = 0;
		texCoord[1] = 0;
		texCoord[2] = 0;
		texCoord[3] = 0;
		texCoord[4] = 0;
		texCoord[5] = 0;
		texCoord[6] = 0;
		texCoord[7] = 0;
		tangent = 0;
		binormal = 0;
		tessFactor = 0;
		positiont = 0;
		color[0] = 0;
		color[1] = 0;
		fog = 0;
		depth = 0;
		sample = 0;

		allocate(flags, n);
	}

	VertexBuffer::~VertexBuffer()
	{
		_aligned_free(position[0]);
		_aligned_free(position[1]);
		_aligned_free(blendWeight);
		_aligned_free(blendIndices);
		_aligned_free(normal[0]);
		_aligned_free(normal[1]);
		_aligned_free(pSize);
		_aligned_free(texCoord[0]);
		_aligned_free(texCoord[1]);
		_aligned_free(texCoord[2]);
		_aligned_free(texCoord[3]);
		_aligned_free(texCoord[4]);
		_aligned_free(texCoord[5]);
		_aligned_free(texCoord[6]);
		_aligned_free(texCoord[7]);
		_aligned_free(tangent);
		_aligned_free(binormal);
		_aligned_free(tessFactor);
		_aligned_free(positiont);
		_aligned_free(color[0]);
		_aligned_free(color[1]);
		_aligned_free(fog);
		_aligned_free(depth);
		_aligned_free(sample);
	}

	void VertexBuffer::allocate(unsigned int flags, int n)
	{
		this->flags = flags;
		numVertices = n;

		int x = fourfold(n);
		padding = x - n;

		position[0] = (float4*)_aligned_malloc(x * sizeof(float4), 16);

		if(hasNormal())
		{
			normal[0] = (float4*)_aligned_malloc(x * sizeof(float4), 16);
		}

		if(hasDiffuse())
		{
			color[0] = (Color<byte>*)_aligned_malloc(x * sizeof(Color<byte>), 16);
		}

		if(hasSpecular())
		{
			color[1] = (Color<byte>*)_aligned_malloc(x * sizeof(Color<byte>), 16);
		}

		for(int t = 0; t < numTexCoords(); t++)
		{
			texCoord[t] = (float4*)_aligned_malloc(x * sizeof(float4), 16);
		}
	}

	void VertexBuffer::realloc(int n)
	{
		numVertices = n;

		int x = fourfold(n);
		padding = x - n;

		position[0] = (float4*)_aligned_realloc(position[0], x * sizeof(float4), 16);

		if(hasNormal())
		{
			normal[0] = (float4*)_aligned_realloc(normal[0], x * sizeof(float4), 16);
		}

		if(hasDiffuse())
		{
			color[0] = (Color<byte>*)_aligned_realloc(color[0], x * sizeof(Color<byte>), 16);
		}

		if(hasSpecular())
		{
			color[1] = (Color<byte>*)_aligned_realloc(color[1], x * sizeof(Color<byte>), 16);
		}

		for(int t = 0; t < numTexCoords(); t++)
		{
			texCoord[t] = (float4*)_aligned_realloc(texCoord[t], x * sizeof(float4), 16);
		}
	}

	bool VertexBuffer::hasRHW() const
	{
		return (flags & FVF_RHW) != 0;
	}

	bool VertexBuffer::hasNormal() const
	{
		return (flags & FVF_NORMAL) != 0;
	}

	bool VertexBuffer::hasDiffuse() const
	{
		return (flags & FVF_DIFFUSE) != 0;
	}

	bool VertexBuffer::hasSpecular() const
	{
		return (flags & FVF_SPECULAR) != 0;
	}

	int VertexBuffer::numTexCoords() const
	{
		return (flags & FVF_TEX_MASK) >> FVF_TEX_SHIFT;
	}

	int VertexBuffer::fourfold(int n)
	{
		return (n + 3) & 0xFFFFFFFC;
	}

	int VertexBuffer::size() const
	{
		return numVertices;
	}
};