#include "Batch.h"

inline LD29Vertex MakeLD29Vertex(float x, float y, float z, unsigned int color, float u, float v, float nx, float ny, float nz)
{
	LD29Vertex vert;
	vert.x = x;
	vert.y = y;
	vert.z = z;
	vert.color = color;
	vert.u = u;
	vert.v = v;
	vert.nx = nx;
	vert.ny = ny;
	vert.nz = nz;
	return vert;
}

Batch::Batch()
{
	vertexCount = 0;
	glGenVertexArrays(1, &vertexArray);
	Wumbo::GL::BindVertexArray(vertexArray);
	glGenBuffers(1, &vertexBuffer);
	Wumbo::GL::BindVertexArray(0);
	memset(&vertices,1,sizeof(vertices));
	vertexCount = 3*MAX_TRIANGLE_COUNT;
	compile();
}
void Batch::clear()
{
	vertexCount = 0;
}
void Batch::addVertex(float x, float y, float z, unsigned int color, float u, float v, float nx, float ny, float nz)
{
	if (vertexCount == 3*MAX_TRIANGLE_COUNT)
	{
		printf("ERROR: Batch doesn't support more than %i triangles!\n",3*MAX_TRIANGLE_COUNT);
		return;
	}
	// I GUESS OPENGL TAKES ABGR instead of ARGB so this should switch them
	vertices[vertexCount] = MakeLD29Vertex(x,y,z,(color & 0xFF00FF00) | ((color & 0x00FF0000) >> 16) | ((color & 0x000000FF) << 16),u,v,nx,ny,nz);
	vertexCount++;
}
void Batch::compile()
{
	glGenVertexArrays(1, &vertexArray);
	Wumbo::GL::BindVertexArray(vertexArray);
	glGenBuffers(1, &vertexBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(LD29Vertex)*vertexCount, vertices, GL_DYNAMIC_DRAW);
	
	glEnableVertexAttribArray(Wumbo::WumboVertexAttribPosition);
	glVertexAttribPointer(Wumbo::WumboVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(LD29Vertex), (char*)(0));
	glEnableVertexAttribArray(Wumbo::WumboVertexAttribColor);
	glVertexAttribPointer(Wumbo::WumboVertexAttribColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(LD29Vertex), (char*)(12));
	glEnableVertexAttribArray(Wumbo::WumboVertexAttribTexCoord0);
	glVertexAttribPointer(Wumbo::WumboVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(LD29Vertex), (char*)(16));
	glEnableVertexAttribArray(Wumbo::WumboVertexAttribNormal);
	glVertexAttribPointer(Wumbo::WumboVertexAttribNormal, 3, GL_FLOAT, GL_TRUE, sizeof(LD29Vertex), (char*)(24));
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	Wumbo::GL::BindVertexArray(0);
}
void Batch::draw(int count)
{
	Wumbo::GL::BindVertexArray(vertexArray);
	glDrawArrays(GL_TRIANGLES,0,(3*count)>=0?((3*count)>vertexCount?vertexCount:(3*count)):vertexCount);
	Wumbo::GL::BindVertexArray(0);
}
void Batch::begin()
{
	vertexCount = 0;
}
void Batch::finish()
{
	Wumbo::GL::BindVertexArray(vertexArray);
	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
	glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(LD29Vertex)*vertexCount,vertices); 
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	Wumbo::GL::BindVertexArray(0);
}
void Batch::addFloor(float x1, float y1, float z1, float x2, float y2, float z2, unsigned int color)
{
	addVertex(x1,y2,z2,color,1,1,0,1,0);
	addVertex(x2,y2,z1,color,0,0,0,1,0);
	addVertex(x1,y2,z1,color,1,0,0,1,0);
	addVertex(x1,y2,z2,color,1,1,0,1,0);
	addVertex(x2,y2,z2,color,0,1,0,1,0);
	addVertex(x2,y2,z1,color,0,0,0,1,0);
}
void Batch::addTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, unsigned int color, float nx, float ny, float nz)
{
	addVertex(x1,y1,z1,color,0,0,nx,ny,nz);
	addVertex(x2,y2,z2,color,0,0,nx,ny,nz);
	addVertex(x3,y3,z3,color,0,0,nx,ny,nz);
}
void Batch::addUVTile(float x1, float y1, float z1, float x2, float y2, float z2, unsigned int color, float u, float v, float w, float h)
{
	v *= -1;
	h *= -1;
	addVertex(x1,y1,z1,color,u,v,1,1,0);
	addVertex(x1,y2,z1,color,u,v+h,1,1,0);
	addVertex(x2,y1,z1,color,u+w,v,1,1,0);
	addVertex(x2,y1,z1,color,u+w,v,1,1,0);
	addVertex(x1,y2,z1,color,u,v+h,1,1,0);
	addVertex(x2,y2,z1,color,u+w,v+h,1,1,0);
}
void Batch::addCube(float x1, float y1, float z1, float x2, float y2, float z2, unsigned int color, bool left, bool right, bool up, bool down, bool top, bool bottom)
{
	if (up)
	{
		addVertex(x1,y1,z1,color,1,0,0,0,-1);
		addVertex(x1,y2,z1,color,1,1,0,0,-1);
		addVertex(x2,y1,z1,color,0,0,0,0,-1);
		addVertex(x2,y1,z1,color,0,0,0,0,-1);
		addVertex(x1,y2,z1,color,1,1,0,0,-1);
		addVertex(x2,y2,z1,color,0,1,0,0,-1);
	}
	if (down)
	{
		addVertex(x1,y1,z2,color,0,0,0,0,1);
		addVertex(x2,y1,z2,color,1,0,0,0,1);
		addVertex(x1,y2,z2,color,0,1,0,0,1);
		addVertex(x2,y1,z2,color,1,0,0,0,1);
		addVertex(x2,y2,z2,color,1,1,0,0,1);
		addVertex(x1,y2,z2,color,0,1,0,0,1);
	}
	if (left)
	{
		addVertex(x1,y1,z1,color,0,0,-1,0,0);
		addVertex(x1,y2,z2,color,1,1,-1,0,0);
		addVertex(x1,y2,z1,color,0,1,-1,0,0);
		addVertex(x1,y1,z1,color,0,0,-1,0,0);
		addVertex(x1,y1,z2,color,1,0,-1,0,0);
		addVertex(x1,y2,z2,color,1,1,-1,0,0);
	}
	if (right)
	{
		addVertex(x2,y2,z1,color,1,1,1,0,0);
		addVertex(x2,y2,z2,color,0,1,1,0,0);
		addVertex(x2,y1,z1,color,1,0,1,0,0);
		addVertex(x2,y2,z2,color,0,1,1,0,0);
		addVertex(x2,y1,z2,color,0,0,1,0,0);
		addVertex(x2,y1,z1,color,1,0,1,0,0);
	}
	if (top)
	{
		addVertex(x1,y2,z2,color,1,1,1,0,0);
		addVertex(x2,y2,z1,color,0,0,1,0,0);
		addVertex(x1,y2,z1,color,1,0,1,0,0);
		addVertex(x1,y2,z2,color,1,1,1,0,0);
		addVertex(x2,y2,z2,color,0,1,1,0,0);
		addVertex(x2,y2,z1,color,0,0,1,0,0);
	}
	if (bottom)
	{
		addVertex(x1,y1,z1,color,0,0,-1,0,0);
		addVertex(x2,y1,z1,color,1,0,-1,0,0);
		addVertex(x1,y1,z2,color,0,1,-1,0,0);
		addVertex(x2,y1,z1,color,1,0,-1,0,0);
		addVertex(x2,y1,z2,color,1,1,-1,0,0);
		addVertex(x1,y1,z2,color,0,1,-1,0,0);
	}
}