/*********************************************************************
*                                                                    *          
*                              FLY                                   *
*                           --E#Y#E--				     *
*                         ===MUSCLE===                               *
*                                                                    *
*********************************************************************/
#include "flybox.h"

/* Class */
UNIFORM uniform4;
TARGA targa4;
PNG png4;
FLYBOX box4;

//---------------------------------------------------------------------------

/* Buffer */
GLuint vbos4[MAX_BUFFERS];

/* Shader Program */
struct s_Shader
{
        unsigned int s_basicProgram;
}f;

/* Texture */
GLubyte* w_images[SS_MAX_SIDES];
GLuint w_texID[SS_MAX_SIDES];
GLuint cubeMapTexAD;

const GLint countH = 4;

//---------------------------------------------------------------------------

/* Vector */
vector<GLfloat> colors4;
vector<GLfloat> texCoords4;
vector<GLfloat> vertices4;

/* Buffer */
vector<M_Color> w_colors;
vector<M_Textur> w_texCoords;
vector<M_Vertex> w_vertices;

/* Texture */
GLubyte *nor;
GLubyte *eas;
GLubyte *sou;
GLubyte *wes;
GLubyte *top;
GLubyte *bot;

//---------------------------------------------------------------------------

/* Texture Loader */
void FLYBOX::textureLoader()
{     
	#if PNG_TEXTURE 
        /* Textures PNG */
        const char northPNG[] = "PIXEL/FLYBOX/bk.png";
        const char eastPNG[] = "PIXEL/FLYBOX/rt.png";
        const char southPNG[] = "PIXEL/FLYBOX/ft.png";
        const char westPNG[] = "PIXEL/FLYBOX/lt.png";
        const char topPNG[] = "PIXEL/FLYBOX/up.png";
        const char bottomPNG[] = "PIXEL/FLYBOX/dn.png";
	
	/* Load PNG */
	png4.read_png(northPNG, &nor);
	png4.read_png(eastPNG, &eas);
	png4.read_png(southPNG, &sou);
	png4.read_png(westPNG, &wes);
	png4.read_png(topPNG, &top);
	png4.read_png(bottomPNG, &bot);
	
	/* Load Textures */
	std::cerr << " PNG TEXTURES BOX: " << std::endl;
	#endif

	#if TARGA_TEXTURE
        /* Textures TGA */
        const char northTGA[] = "PIXEL/FLYBOX/bk.tga";
        const char eastTGA[] = "PIXEL/FLYBOX/rt.tga";
        const char southTGA[] = "PIXEL/FLYBOX/ft.tga";
        const char westTGA[] = "PIXEL/FLYBOX/lt.tga";
        const char topTGA[] = "PIXEL/FLYBOX/up.tga";
        const char bottomTGA[] = "PIXEL/FLYBOX/dn.tga";
	
	/* Load TGA */
	targa4.readTarga(northTGA, &nor);
	targa4.readTarga(eastTGA, &eas);
	targa4.readTarga(southTGA, &sou);
	targa4.readTarga(westTGA, &wes);
	targa4.readTarga(topTGA, &top);
	targa4.readTarga(bottomTGA, &bot);
	
	/* Load Textures */
	std::cerr << " TARGA TEXTURES BOX: " << std::endl;
	#endif	
}

//--------------------------------------------------------------------------

/* Mipmaps Image */
void FLYBOX::MipmapsImage2(const GLint count, int side3, GLubyte *pixel)
{
        /* Generate Textures */
        //glGenTextures(side3, w_texID);
        //glActiveTexture(GL_TEXTURE0);
        //glBindTexture(GL_TEXTURE_2D, w_texID[side3]);
        
        /* Enable Texture */
	glEnable(GL_TEXTURE_2D);
        
        /* Generate MipMaps */
        glGenerateMipmap(GL_TEXTURE_2D);
        
        /* Filtering Mode */
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
        
        /* Image Data */
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 128, 128, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 
        glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8,  64,  64, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 
        glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8,  32,  32, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 
        glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA8,  16,  16, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 
        glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA8,   8,   8, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 
        glTexImage2D(GL_TEXTURE_2D, 5, GL_RGBA8,   4,   4, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 
        glTexImage2D(GL_TEXTURE_2D, 6, GL_RGBA8,   2,   2, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 
        glTexImage2D(GL_TEXTURE_2D, 7, GL_RGBA8,   1,   1, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixel); 

        /* Filtering Mode */
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

        /* Mipmaps Data */
        gluBuild2DMipmaps(GL_TEXTURE_2D, 
                          GL_RGBA8,             // internal format
                          128,                  // width
                          128,                  // height
                          GL_BGRA,              // format
                          GL_UNSIGNED_BYTE,     // type
                          pixel                 // data
        );

        /* Cube Map */
        glGenTextures(1, &cubeMapTexAD);
        glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexAD);
        
        /* Filtering Mode */
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 
	
	/* Delete Texture */
	//glDeleteTextures(side3, w_texID);
}

//---------------------------------------------------------------------------

/* Init Skybox */
bool FLYBOX::initBox() 
{
	#if SLOW_COMPUTER
        /* Generate Textures */
        glGenTextures(SS_MAX_SIDES, w_texID);

	/* Mipmaps */
	//box4.MipmapsImage2(countH, 1, top);
	//box4.MipmapsImage2(countH, 2, bot);
	//box4.MipmapsImage2(countH, 3, nor);
	//box4.MipmapsImage2(countH, 4, eas);
	//box4.MipmapsImage2(countH, 5, sou);
	box4.MipmapsImage2(countH, 1, wes);
	#endif
        
        //-------------------------------------------------------------------

        /* Texture Size */
        float SIZE = 50.0f;
        
        /* Top */
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));	
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));
        w_vertices.push_back(M_Vertex(-SIZE, SIZE, -SIZE));
        w_vertices.push_back(M_Vertex( SIZE, SIZE, -SIZE));
        w_vertices.push_back(M_Vertex( SIZE, SIZE,  SIZE));
        w_vertices.push_back(M_Vertex(-SIZE, SIZE,  SIZE));
        w_texCoords.push_back(M_Textur(0.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 1.0f));
        
        /* Bottom */
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));
        w_colors.push_back(M_Color(0.01f, 0.01f, 0.01f, 0.7f));
        w_vertices.push_back(M_Vertex( SIZE,-SIZE, -SIZE));
        w_vertices.push_back(M_Vertex(-SIZE,-SIZE, -SIZE));
        w_vertices.push_back(M_Vertex(-SIZE,-SIZE,  SIZE));
        w_vertices.push_back(M_Vertex( SIZE,-SIZE,  SIZE));
        w_texCoords.push_back(M_Textur(0.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 1.0f));
        
        /* Left */
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_vertices.push_back(M_Vertex(-SIZE,-SIZE,-SIZE));
        w_vertices.push_back(M_Vertex(-SIZE, SIZE,-SIZE));
        w_vertices.push_back(M_Vertex(-SIZE, SIZE, SIZE));
        w_vertices.push_back(M_Vertex(-SIZE,-SIZE, SIZE));
        w_texCoords.push_back(M_Textur(1.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 0.0f));

        /* Back */
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_vertices.push_back(M_Vertex(-SIZE,-SIZE,-SIZE));
        w_vertices.push_back(M_Vertex( SIZE,-SIZE,-SIZE));
        w_vertices.push_back(M_Vertex( SIZE, SIZE,-SIZE));
        w_vertices.push_back(M_Vertex(-SIZE, SIZE,-SIZE));
        w_texCoords.push_back(M_Textur(0.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 1.0f));

        /* Right */
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_vertices.push_back(M_Vertex( SIZE,-SIZE, SIZE));
        w_vertices.push_back(M_Vertex( SIZE, SIZE, SIZE));
        w_vertices.push_back(M_Vertex( SIZE, SIZE,-SIZE));
        w_vertices.push_back(M_Vertex( SIZE,-SIZE,-SIZE));
        w_texCoords.push_back(M_Textur(1.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 0.0f));

        /* Front */
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_colors.push_back(M_Color(0.30f, 0.50f, 0.70f, 0.7f));
        w_vertices.push_back(M_Vertex( SIZE,-SIZE, SIZE));
        w_vertices.push_back(M_Vertex(-SIZE,-SIZE, SIZE));
        w_vertices.push_back(M_Vertex(-SIZE, SIZE, SIZE));
        w_vertices.push_back(M_Vertex( SIZE, SIZE, SIZE));
        w_texCoords.push_back(M_Textur(0.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 0.0f));
        w_texCoords.push_back(M_Textur(1.0f, 1.0f));
        w_texCoords.push_back(M_Textur(0.0f, 1.0f));

        //-------------------------------------------------------------------

        /* Create Color Buffer */
        glGenBuffers(MAX_BUFFERS, &vbos4[0]); // Generate a buffer for the color
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[COLOR_BUFFER]); // Bind the color buffer
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * DC, &w_colors[0], GL_STATIC_DRAW);
  
        /* Create Texture Buffer */ 
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[NORMAL_BUFFER]); // Bind the tex coord buffer
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 2 * DC, &w_texCoords[0], GL_STATIC_DRAW); 
  
        /* Create Vertex Buffer */ 
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[VERTEX_BUFFER]); // Bind the vertex buffer
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * DC, &w_vertices[0], GL_STATIC_DRAW);

        return true;
}

//--------------------------------------------------------------------------

/* Render Objects */
void FLYBOX::vertexBox() 
{ 
        /* Active Texture */
	//glActiveTextureARB(GL_TEXTURE5_ARB);
	//glClientActiveTextureARB(GL_TEXTURE5_ARB); 
 
        /* Attrib Array */
	glEnableVertexAttribArrayARB(0); 
    	glEnableVertexAttribArrayARB(1);
	glEnableVertexAttribArrayARB(2);
         
	//-------------------------------------------------------------------

        /* Bind Color Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[COLOR_BUFFER]);

        /* Color */
        const GLint csize = 3;                      // ( R, G, B, A)
        const GLenum ctype = GL_FLOAT;              // the data is 8bit unsigned values
        const GLboolean cnormalize = false;         // normalize the data (convert from 0-255 to 0-1)
        const GLsizei cstride = 0;                  // 0 = move forward size * sizeof(type)
        const GLbyte coffset = 0;                   // start at the beginning of the buffer

        glVertexAttribPointerARB((GLuint)2, csize, ctype, cnormalize, cstride, &colors4[coffset]);
	
	//-------------------------------------------------------------------

        /* Bind Vertex Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[VERTEX_BUFFER]);

        /* Vertex */
        const GLint vsize = 3;			    // ( X, Y, Z, W )
        const GLenum vtype = GL_FLOAT;
        const GLboolean vnormalize = false;
        const GLsizei vstride = 0;
        const GLbyte voffset = 0;

        glVertexAttribPointerARB((GLuint)0, vsize, vtype, vnormalize, vstride, &vertices4[voffset]);
        
        //-------------------------------------------------------------------
        
        /* Bind Normal Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[NORMAL_BUFFER]);

        /* Texture */
        const GLint tsize = 2;			    // ( S, T, P, Q )
        const GLenum ttype = GL_FLOAT;
        const GLboolean tnormalize = false;
        const GLsizei tstride = 0;
        const GLbyte toffset = 0;

        glVertexAttribPointerARB((GLuint)1, tsize, ttype, tnormalize, tstride, &texCoords4[toffset]);

        //-------------------------------------------------------------------

        int i = 0;

        for(i = 0; i < 6; ++i)
        {
                glBindTexture(GL_TEXTURE_2D, w_texID[i]);
                glDrawArrays(GL_QUADS, i * 4, countH);
        }
	
	//-------------------------------------------------------------------

        /* Disable Array */
        glDisableVertexAttribArrayARB(2);
        glDisableVertexAttribArrayARB(1);
        glDisableVertexAttribArrayARB(0);
        
	/* Active Texture 0 */
	//glActiveTextureARB(GL_TEXTURE0_ARB);
	//glClientActiveTextureARB(GL_TEXTURE0_ARB);
}

//--------------------------------------------------------------------------

/* Render Objects */
void FLYBOX::renderBox() 
{  
	/* Vertex Array */
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);	
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
         
	//-------------------------------------------------------------------

        /* Bind Color Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[COLOR_BUFFER]);

        /* Color */
        const GLint csize = 4;                      // ( R, G, B, A)
        const GLenum ctype = GL_FLOAT;              // the data is 8bit unsigned values
        const GLsizei cstride = 0;                  // 0 = move forward size * sizeof(type)
        const GLbyte coffset = 0;                   // start at the beginning of the buffer

        glColorPointer(csize, ctype, cstride, &colors4[coffset]);
	
	//-------------------------------------------------------------------

        /* Bind Vertex Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[VERTEX_BUFFER]);

        /* Vertex */
        const GLint vsize = 3;			    // ( X, Y, Z, W )
        const GLenum vtype = GL_FLOAT;
        const GLsizei vstride = 0;
        const GLbyte voffset = 0;

        glVertexPointer(vsize, vtype, vstride, &vertices4[voffset]);
        
        //-------------------------------------------------------------------
        
        /* Bind Normal Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos4[NORMAL_BUFFER]);

        /* Texture */
        const GLint tsize = 2;			    // ( S, T, P, Q )
        const GLenum ttype = GL_FLOAT;
        const GLsizei tstride = 0;
        const GLbyte toffset = 0;

        glTexCoordPointer(tsize, ttype, tstride, &texCoords4[toffset]);

        //-------------------------------------------------------------------
        
        int i = 0;
        
        for(i = 0; i < 6; ++i)
        {
                glBindTexture(GL_TEXTURE_2D, w_texID[i]);
                glDrawArrays(GL_QUADS, i * 4, countH);
        }
        
	//-------------------------------------------------------------------
        
	/* Disable Client State */
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);
}

//---------------------------------------------------------------------------

/* Render Skybox */
void FLYBOX::render(float x, float y, float z, unsigned int s_basicProgram)
{
        /* PushMatrix */
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glPushMatrix();
        glTranslatef(x, y, z);

        //-------------------------------------------------------------------

        /* Matrix */
        static float modelviewMatrix[ID];
        static float projectionMatrix[ID];
        
        /* Passing Data */
        glGetFloatv(GL_MODELVIEW_MATRIX, modelviewMatrix);
        glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);
        
        /* Matrix */
        uniform4.Uniform4x4(f.s_basicProgram, "modelview_matrix", 0, modelviewMatrix);
        uniform4.Uniform4x4(f.s_basicProgram, "projection_matrix", 1, projectionMatrix);

        //-------------------------------------------------------------------

        /* Depth Test */
        glDisable(GL_DEPTH_TEST);
        
        /* Render Objects */
        #if VERTEX_BOX
        box4.vertexBox(); 
	#else
	box4.renderBox(); 
	#endif

        //-------------------------------------------------------------------
	
	/* Delete Buffer */
        glDeleteBuffers(MAX_BUFFERS, &vbos4[0]);
        /* Depth Test */
        glEnable(GL_DEPTH_TEST);
        /* PopMatrix */
        glPopMatrix();
	
	/* Delete Texture */
	//glDeleteTextures(side3, w_texID);
	
	/* Disable Texture */
	glDisable(GL_TEXTURE_2D);
	glFlush();
}

//---------------------------------------------------------------------------


