#include "VertexBufferObject.h"

VertexBufferObject::VertexBufferObject(	GLenum triangulationType,
										const void* vertices, __int64 sizeVertices, 
										const void* normals, __int64 sizeNormals, 
										const void* texCoords, __int64 sizeTexCoords, 
										const void* colors, __int64 sizeColors)
{
	hasNormalsFlag = false;
	hasTexCoordsFlag = false;
	hasColorsFlag = false;

	// create vertex buffer and get a handler from opengl
	glGenBuffersARB(1, &handler);

	this->triangulationType = (int) triangulationType;
	this->sizeVertices = sizeVertices;

	if(normals != NULL)
	{
		hasNormalsFlag = true;
		this->sizeNormals = sizeNormals;
	}

	if(texCoords != NULL)
	{
		hasTexCoordsFlag = true;
		this->sizeTexCoords = sizeTexCoords;
	}
	if(colors != NULL)
	{
		hasColorsFlag = true;
		this->sizeColors = sizeColors;
	}

	// Array Buffer (not Index Buffer)
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, handler);

	// reserve memory
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeVertices + sizeNormals + sizeTexCoords + sizeColors, NULL, GL_STATIC_DRAW_ARB);

	// copy vertex data to buffer
	if (sizeVertices != 0)
		glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeVertices, vertices);

	// copy vertex normals to buffer
	if (sizeNormals != 0)
		glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeVertices, sizeNormals, normals);	

	// copy texture coordinates to buffer
	if (sizeTexCoords != 0)
		glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeVertices + sizeNormals, sizeTexCoords, texCoords);	

	// copy color data to buffer
	if (sizeColors != 0)
		glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeVertices + sizeNormals + sizeTexCoords, sizeColors, colors);		  
}

VertexBufferObject::~VertexBufferObject()
{
	glDeleteBuffersARB(1, &handler);
}

void VertexBufferObject::drawVBO()
{
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, handler);

	// enable vertex arrays
	if (hasNormalsFlag)
		glEnableClientState(GL_NORMAL_ARRAY);
	if (hasTexCoordsFlag)
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	if (hasColorsFlag)
		glEnableClientState(GL_COLOR_ARRAY);
		glEnableClientState(GL_VERTEX_ARRAY);

	// set array offsets
	if (hasNormalsFlag)
		glNormalPointer(GL_FLOAT, 0, (void*)sizeVertices);
	if (hasTexCoordsFlag)
		glTexCoordPointer(2, GL_FLOAT, 0, (void*)(sizeVertices + sizeNormals) );
	if (hasColorsFlag)
		glColorPointer(3, GL_FLOAT, 0, (void*)(sizeVertices + sizeNormals + sizeTexCoords));
	glVertexPointer(3, GL_FLOAT, 0, 0);

	// draw
	glDrawArrays(triangulationType, 0, sizeVertices / sizeof(GLfloat) / 3);

	// disable vertex arrays (inverse order)
	glDisableClientState(GL_VERTEX_ARRAY);  
	if (hasColorsFlag)
		glDisableClientState(GL_COLOR_ARRAY);
	if (hasTexCoordsFlag)
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	if (hasNormalsFlag)
		glDisableClientState(GL_NORMAL_ARRAY);

	// turn off VBO operations
	glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}