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

/*-------------------------------------------------------------------------*/

/* 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;

/*-------------------------------------------------------------------------*/

/* Vertex */
GLfloat colors4[DC];
GLfloat texCoords4[DC];
GLfloat vertices4[DC];

/* Buffer */
GLfloat w_colors[DC];
GLfloat w_texCoords[DC];
GLfloat w_vertices[DC];

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

/*-------------------------------------------------------------------------*/

/* Texture Loader */
void 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 */
	read_png(northPNG, &nor);
	read_png(eastPNG, &eas);
	read_png(southPNG, &sou);
	read_png(westPNG, &wes);
	read_png(topPNG, &top);
	read_png(bottomPNG, &bot);
	
	/* Load Textures */
	printf(" PNG TEXTURES BOX: \n");
	#endif
}

/*-------------------------------------------------------------------------*/ 

/* Mipmaps Image */
void 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 */
char initBox() 
{
	#if SLOW_COMPUTER
        /* Generate Textures */
        glGenTextures(SS_MAX_SIDES, w_texID);

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

        /* Polygon Mode */
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 
	glBegin(GL_QUADS);

        /* Texture Size */
        float SIZE = 50.0f;
 
         /* Top */
        glColor4f(0.01f, 0.01f, 0.01f, 0.7f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-SIZE, SIZE, -SIZE);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( SIZE, SIZE, -SIZE);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( SIZE, SIZE,  SIZE);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-SIZE, SIZE,  SIZE);

        /* Bottom */
        glColor4f(0.01f, 0.01f, 0.01f, 0.7f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f( SIZE,-SIZE, -SIZE);
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-SIZE,-SIZE, -SIZE);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-SIZE,-SIZE,  SIZE);
        glTexCoord2f(0.0f, 1.0f); glVertex3f( SIZE,-SIZE,  SIZE);
 
        /* Left */
        glColor4f(0.30f, 0.50f, 0.70f, 0.7f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-SIZE,-SIZE,-SIZE);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-SIZE, SIZE,-SIZE);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-SIZE, SIZE, SIZE);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-SIZE,-SIZE, SIZE);
        
        /* Back */
        glColor4f(0.30f, 0.50f, 0.70f, 0.7f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-SIZE,-SIZE,-SIZE);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( SIZE,-SIZE,-SIZE);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( SIZE, SIZE,-SIZE);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-SIZE, SIZE,-SIZE);
        
        /* Right */
        glColor4f(0.30f, 0.50f, 0.70f, 0.7f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( SIZE,-SIZE, SIZE);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( SIZE, SIZE, SIZE);
        glTexCoord2f(0.0f, 1.0f); glVertex3f( SIZE, SIZE,-SIZE);
        glTexCoord2f(0.0f, 0.0f); glVertex3f( SIZE,-SIZE,-SIZE);

        /* Front */
        glColor4f(0.30f, 0.50f, 0.70f, 0.7f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f( SIZE,-SIZE, SIZE);
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-SIZE,-SIZE, SIZE);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-SIZE, SIZE, SIZE);
        glTexCoord2f(0.0f, 1.0f); glVertex3f( SIZE, SIZE, SIZE);

        glEnd();

        /*-----------------------------------------------------------------*/
        
        /* 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 vertexBox() 
{
        /* Active Texture */
	/*glActiveTextureARB(GL_TEXTURE5);*/
	/*glClientActiveTextureARB(GL_TEXTURE5);*/

        /* Attrib Array */
	glEnableVertexAttribArray(0);
    	glEnableVertexAttribArray(1);
	glEnableVertexAttribArray(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 */

        glVertexAttribPointer((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;

        glVertexAttribPointer((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;

        glVertexAttribPointer((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 */
        glDisableVertexAttribArray(2);
        glDisableVertexAttribArray(1);
        glDisableVertexAttribArray(0);

        /* Active Texture */
	/*glActiveTextureARB(GL_TEXTURE0);*/
	/*glClientActiveTextureARB(GL_TEXTURE0);*/
}

/*-------------------------------------------------------------------------*/ 

/* Render Objects */
void 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 render(float x, float y, float z, unsigned int s_basicProgram)
{
        /* PushMatrix */
        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 */
        Uniform4x4(f.s_basicProgram, "modelview_matrix", 0, modelviewMatrix);
        Uniform4x4(f.s_basicProgram, "projection_matrix", 1, projectionMatrix); 

        /*-----------------------------------------------------------------*/

        /* Depth Test */
        glDisable(GL_DEPTH_TEST);

        /* Render Objects */
        #if VERTEX_BOX
        vertexBox(); 
	#else
	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();
}

/*-------------------------------------------------------------------------*/


