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

/*-------------------------------------------------------------------------*/
        
/* Buffer */
GLuint vbos5[MAX_BUFFERS];

/* Shader Program */
struct t_Shader
{
          unsigned int fontProgram;
}t;

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

/* Buffer */
GLuint w_texCoords5[EV];
GLuint w_vertices5[EV];
GLuint m_textureID;

/* Texture Name */
const char* m_textureName;                
float m_fontSize;
int m_Width;
int m_Height;

/* Texture */
GLubyte *mono5;

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

/* TMFont */
char TMFont(const char* textureName, int screenWidth, int screenHeight, float fontSize)
{       
        /* Font Version */
        static const GLchar font_vert[] = "GLSL/font.vert";
        static const GLchar font_frag[] = "GLSL/font.frag";

	/* Create GLSL Shaders / Compile Shaders */
        createShader(font_vert, font_frag);  
        createProgram(t.fontProgram);
    
        /*-----------------------------------------------------------------*/
                
        /* TMFont */
        m_textureName = textureName;
        m_Width = screenWidth;
        m_Height = screenHeight;
        m_fontSize = fontSize;
    
        /*-----------------------------------------------------------------*/
   
        #if PNG_TEXTURE
        m_textureName = "FONT/mono.png";
	read_png(m_textureName, &mono5);
	#endif
	
	return TRUE;
}

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

/* Mipmaps Image */
void MipmapsImage(const GLint count, int side3, GLubyte *pixel)
{
        /* Generate Textures */
        /*glBindTexture(GL_TEXTURE_2D, m_textureID);*/
        
        /* Enable Texture */
	glEnable(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); 

        /* Mipmaps Data */
        /*gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA8, 256, 256, GL_BGRA, GL_UNSIGNED_BYTE, pixel);*/
}

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

/* Font Initialize */
char initFont()
{        
        /* Initialize the Font */
        if(!TMFont("FONT/mono.png", m_Width, m_Height, 25.0f)) 
        {
                printf(" COULD NOT INITIALIZE THE FONT \n");       
                return FALSE;
        }
        
        /*------------------------------------------------------------------*/

        #if TM_FONT
        /* Generate Textures */
        /*glGenTextures(1, &m_textureID);*/
        
        /* Mipmaps */
        const GLint countE = 8;
        MipmapsImage(countE, 1, mono5);
        #endif
        
        /*-----------------------------------------------------------------*/

        /* Buffer */
        /*float texCoords[EV];*/
        /*float vertices[EV];*/

        /* Polygon Mode */
	/*glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);*/ 
	/*glBegin(GL_QUADS);*/
        /*glTexCoord2f(0.0f, 0.0f); glVertex2f(       0.0f,       0.0f);*/
        /*glTexCoord2f(0.0f, 0.0f); glVertex2f( m_fontSize,       0.0f);*/
        /*glTexCoord2f(0.0f, 0.0f); glVertex2f( m_fontSize, m_fontSize);*/
        /*glTexCoord2f(0.0f, 0.0f); glVertex2f(       0.0f, m_fontSize);*/
        /*glEnd();*/
        
        /*-----------------------------------------------------------------*/

        /* Vertex Font */
        float vertices[] = { 
            0.0f,        0.0f, 
            m_fontSize,  0.0f, 
            m_fontSize,  m_fontSize,
            0.0f,        m_fontSize
        };

        /* Vertex Buffer */
        glGenBuffers(MAX_BUFFERS, &vbos5[0]); /* Generate a buffer for the color */
        glBindBuffer(GL_ARRAY_BUFFER, vbos5[VERTEX_BUFFER]); /* Bind the vertex buffer */
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * EV, &vertices[0], GL_STATIC_DRAW);

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

        /* Just initialize with something for now, the tex coords are updated */
        /* for each character printed */ 
        float texCoords[] = {
            0.0f, 0.0f,
            0.0f, 0.0f, 
            0.0f, 0.0f,
            0.0f, 0.0f
        };

        /* Texture Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos5[NORMAL_BUFFER]); /* Bind the vertex buffer */
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * EV, &texCoords[0], GL_DYNAMIC_DRAW);

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

	/* Init */
	Location(t.fontProgram,0, "f_Vertex");
	Location(t.fontProgram,1, "f_TexCoord");
	
	linkProgram(t.fontProgram);
        Uniform(t.fontProgram, "texture3", 0);

        return TRUE;
}

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

/* Print Font */
void printString(const char* str, float mx, float my) 
{
        static float modelview1[ID];
        static float projection1[ID];
        
        /* Font Program */
        bindShader(t.fontProgram);         /* Enable our shader */    
        /* Set Ortho */
        setOrthoMode();
        float texCoords[EV];

        /* Disable Cull Face */
        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);
        
        /* Bind Texture */
        glBindTexture(GL_TEXTURE_2D, m_textureID);
      
        /* Enable Array */
	glEnableVertexAttribArray(0); 
    	glEnableVertexAttribArray(1);
    	
    	/* Vertex Array */
	/*glEnableClientState(GL_VERTEX_ARRAY);*/
	/*glEnableClientState(GL_TEXTURE_COORD_ARRAY);*/
        
        /* !!! UNSTABLE !!! */
        long unsigned int i;
        /*size_t i;*/
        
        glTranslatef(mx, my, 0.0); /* Position our text */
        for(i = 0; i < sizeof(str); ++i)
        {
                /* Variables */
                const float oneOverSixteen = 1.0f / 16.0f;
                int ch = (int)(str[i]);
                float xPos = (float)(ch % 16) * oneOverSixteen;
                float yPos = (float)(ch / 16) * oneOverSixteen;

                /* 8 Array */
                texCoords[0] = xPos;
                texCoords[1] = 1.0f - yPos - oneOverSixteen;
                texCoords[2] = xPos + oneOverSixteen;
                texCoords[3] = 1.0f - yPos - oneOverSixteen;
                texCoords[4] = xPos + oneOverSixteen;
                texCoords[5] = 1.0f - yPos - 0.001f;
                texCoords[6] = xPos;
                texCoords[7] = 1.0f - yPos - 0.001f;

                /* Bind Buffer */
                glBindBuffer(GL_ARRAY_BUFFER, vbos5[NORMAL_BUFFER]); /* Bind the vertex buffer */
                glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * EV, &texCoords[0]);
                
                /*-----------------------------------------------------------*/
                
                glBindBuffer(GL_ARRAY_BUFFER, vbos5[VERTEX_BUFFER]);
                
                /* Vertex */
                const GLint vsize = 2;			    /* ( X, Y, Z, W ) */
                const GLenum vtype = GL_FLOAT;
                const GLboolean vnormalize = FALSE;
                const GLsizei vstride = 0; 
                const GLbyte voffset = 0;
                
                /*glVertexPointer(vsize, vtype, vstride, &w_vertices5[voffset]);*/
                glVertexAttribPointer((GLint)0, vsize, vtype, vnormalize, vstride, &w_vertices5[voffset]);
                
                /*-----------------------------------------------------------*/
                
                glBindBuffer(GL_ARRAY_BUFFER, vbos5[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;
                
                /*glTexCoordPointer(tsize, ttype, tstride, &w_texCoords5[toffset]);*/
                glVertexAttribPointer((GLint)1, tsize, ttype, tnormalize, tstride, &w_texCoords5[toffset]);

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

	        /* Passing Data */
	        glGetFloatv(GL_PROJECTION_MATRIX, projection1);
	        glGetFloatv(GL_MODELVIEW_MATRIX, modelview1);
	        
	        /* Matrix */
	        Uniform4x4(t.fontProgram, "projection_matrix", 0, projection1);
	        Uniform4x4(t.fontProgram, "modelview_matrix", 1, modelview1);

                /* Draw & Move */
                glDrawArrays(GL_QUADS, 0, 4);
                glTranslatef(m_fontSize * 0.80f, 0, 0); /* Move along a bit for the next character */
        }

        /* Disable Client State */
        /*glDisableClientState(GL_TEXTURE_COORD_ARRAY);*/
	/*glDisableClientState(GL_VERTEX_ARRAY);*/
        
        /* Disable Array */
        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
        
        /* Delete Shader */
        /*DeleteShader(t.fontProgram);*/
        
        /* Unset Ortho */
        unsetOrthoMode();
}

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

/* Set Ortho Mode */
void setOrthoMode()
{
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(0, (float)(m_Width), 0, (float)(m_Height), -1, 1);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadIdentity();
}

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

/* Unset Ortho Mode */
void unsetOrthoMode()
{
        glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
}

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

