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

/* Class */
UNIFORM uniform5;
TMFONT tmfont5;
TARGA targa5;
PNG png5;

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

/* Buffer */
GLuint vbos5[MAX_BUFFERS];

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

/* Texture */
GLubyte *mono5;

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

/* TMFont */
bool TMFONT::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 */
        uniform5.createShader(font_vert, font_frag);  
        uniform5.createProgram(t.fontProgram);
    
        //--------------------------------------------------------------------
                
        /* TMFont */
        m_textureName = textureName;
        m_Width = screenWidth;
        m_Height = screenHeight;
        m_fontSize = fontSize;
    
        //--------------------------------------------------------------------
   
        #if PNG_TEXTURE
        m_textureName = "FONT/mono.png";
	png5.read_png(m_textureName, &mono5);
	#endif
   
        #if TARGA_TEXTURE
        m_textureName = "FONT/mono.tga";       
	targa5.readTarga(m_textureName, &mono5);
	#endif
	
	return true;
}

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

/* Mipmaps Image */
void TMFONT::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 */
bool TMFONT::initFont()
{
        /* Initialize the Font */
        if(!tmfont5.TMFont("FONT/mono.tga", m_Width, m_Height, 25.0f)) 
        {
                std::cerr << " COULD NOT INITIALIZE THE FONT " << std::endl;      
                return false;
        }
        
        //-------------------------------------------------------------------

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

        /* 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 */
	uniform5.Location(t.fontProgram,0, "f_Vertex");
	uniform5.Location(t.fontProgram,1, "f_TexCoord");
	
	uniform5.linkProgram(t.fontProgram);
        uniform5.Uniform(t.fontProgram, "texture3", 0);

        return true;
}

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

/* Print Font */
void TMFONT::printString(const char* str, float mx, float my) 
{
        static float modelview1[ID];
        static float projection1[ID];
        
        /* Font Program */
        uniform5.bindShader(t.fontProgram);         // Enable our shader    
        /* Set Ortho */
        tmfont5.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 */
	glEnableVertexAttribArrayARB(0); 
    	glEnableVertexAttribArrayARB(1);
    	
    	/* Vertex Array */
	//glEnableClientState(GL_VERTEX_ARRAY);
	//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        
        /* !!! UNSTABLE !!! */
        long unsigned int i;
        //string::size_type 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]);
                glVertexAttribPointerARB((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]);
                glVertexAttribPointerARB((GLint)1, tsize, ttype, tnormalize, tstride, &w_texCoords5[toffset]);

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

	        /* Passing Data */
	        glGetFloatv(GL_PROJECTION_MATRIX, projection1);
	        glGetFloatv(GL_MODELVIEW_MATRIX, modelview1);
	        
	        /* Matrix */
	        uniform5.Uniform4x4(t.fontProgram, "projection_matrix", 0, projection1);
	        uniform5.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 */
        glDisableVertexAttribArrayARB(0);
        glDisableVertexAttribArrayARB(1);  
        
        /* Delete Shader */
        //uniform5.DeleteShader(t.fontProgram);
        
        /* Unset Ortho */
        tmfont5.unsetOrthoMode();
}

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

/* Set Ortho Mode */
void TMFONT::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 TMFONT::unsetOrthoMode()
{
        glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
}

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

