#include "mesh.h"
#include <GL/glew.h>
#include <iostream>
#include "m3dme.h"
#include "m3derror.h"
#include "openglstate.h"

namespace M3D
{

uint32_t Mesh::_vertex_count_max_ = 0;
uint32_t Mesh::_index_count_max_ = 0;

void Mesh::set_limits ( uint32_t vcm, uint32_t icm )
{
	_vertex_count_max_ = vcm;
	_index_count_max_ = icm;
}
Mesh::Mesh() :
		_vertex_count_ ( 0 ),
		_index_count_ ( 0 ),
		_mesh_name_ ( "" ),
		_source_file_ ( "" ),
		_primitive_type_ ( 0 ),
		_vao_id_ ( 0 )
{}


Mesh::~Mesh()
{
	//	if(glIsVertexArray(_vao_id_))glDeleteVertexArrays(1, &_vao_id_);
	if ( glIsBuffer ( _vbo_id_ ) ) glDeleteBuffers ( 1, &_vbo_id_ );
	if ( glIsBuffer ( _ibo_id_ ) ) glDeleteBuffers ( 1, &_ibo_id_ );
}

void Mesh::load ( int programID, const std::string &base_dir, const std::string &source_file )
{
	M3DME mesh;
	mesh.load ( base_dir + source_file );
	_position_loc_ = 0;
	_normal_loc_ = 1;
	_texture_loc_ = 2;
	_source_file_ = base_dir + source_file;
	_vertex_count_ = mesh.get_header()->vertex_data_size / sizeof ( M3DME_Vertex_Data );
	_index_count_ = mesh.get_header()->index_data_size / sizeof ( M3DME_Index_Data );
	_primitive_type_ = mesh.get_header()->primitive_type;

	const char *vertex_data_pos = ( char* ) mesh.get_vertex_data();
	const char *index_data_pos = ( char* ) mesh.get_index_data();

	//Создадим вершинный массив
//	glGenVertexArrays ( 1, &_vao_id_ );
//	glBindVertexArray ( _vao_id_ );

	//Загрузим вершинные и индексные данные как статические
	glGenBuffers ( 1, &_vbo_id_ );
	glBindBuffer ( GL_ARRAY_BUFFER, _vbo_id_ );
	glBufferData ( GL_ARRAY_BUFFER, mesh.get_header()->vertex_data_size, vertex_data_pos, GL_STATIC_DRAW );

	glBindAttribLocation(programID, _position_loc_, "Position");
	glEnableVertexAttribArray(_position_loc_);
	glVertexAttribPointer(_position_loc_, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), 0);
	
	glBindAttribLocation(programID, _position_loc_, "Normal");
	glEnableVertexAttribArray(_normal_loc_);
	glVertexAttribPointer(_normal_loc_, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), reinterpret_cast<GLvoid*>(5*sizeof(float)));

	glBindAttribLocation(programID, _texture_loc_, "Texture");
	glEnableVertexAttribArray(_texture_loc_);
	glVertexAttribPointer(_texture_loc_, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), reinterpret_cast<GLvoid*>(3*sizeof(float)));
	
	glGenBuffers ( 1, &_ibo_id_ );
	glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, _ibo_id_ );
	glBufferData ( GL_ELEMENT_ARRAY_BUFFER, mesh.get_header()->index_data_size, index_data_pos, GL_STATIC_DRAW );
//	glBindVertexArray ( 0 );
}

void Mesh::draw ( uint32_t frame_num, OpenGLState *gl_state )
{
//	gl_state->bind_vertex_array ( _vao_id_ );
//	glBindVertexArray ( _vao_id_ );
	int programID = gl_state->get_current_program();
	glBindBuffer ( GL_ARRAY_BUFFER, _vbo_id_ );

	glBindAttribLocation(programID, _position_loc_, "Position");
	glEnableVertexAttribArray(_position_loc_);
	glVertexAttribPointer(_position_loc_, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), 0);
	
	glBindAttribLocation(programID, _position_loc_, "Normal");
	glEnableVertexAttribArray(_normal_loc_);
	glVertexAttribPointer(_normal_loc_, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), reinterpret_cast<GLvoid*>(5*sizeof(float)));

	glBindAttribLocation(programID, _texture_loc_, "Texture");
	glEnableVertexAttribArray(_texture_loc_);
	glVertexAttribPointer(_texture_loc_, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), reinterpret_cast<GLvoid*>(3*sizeof(float)));

	glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, _ibo_id_ );
	glDrawElements ( GL_TRIANGLES, _index_count_,GL_UNSIGNED_INT, 0 );
	glDisableVertexAttribArray(_position_loc_);
	glDisableVertexAttribArray(_normal_loc_);
	glDisableVertexAttribArray(_texture_loc_);
}
void Mesh::link_model ( Model * obj )
{
	_associated_models_.insert ( obj );
}

void Mesh::unlink_model ( Model * obj )
{
	_associated_models_.erase ( obj );
}
}
