Texture Mapped Fonts from Beginning OpenGL Book

I’m using the code from Chapter 11 of the Beginning OpenGL Game Programming book in line with a previous example from the same book that’s using vertex buffer objects…I’m having a hard time getting the fonts to display on the same screen as my regular geometry…and I’m pretty sure it has something to do with the setting up of the VBO’s and GLIdentities and Matrices in the TextureMappedFont.cpp module conflicting with my regular VBO rendering process.

Is anyone here familiar with that book that would like to take a look at my code for me? I’ve got two problems…

I can either make the call to m_font->printString before or after my existing glDrawElements in render and see the text but not my elements. Or I can comment out the call to m_font->printString and see the elements…

Either way…if the block in init that gets the GL_VIEWPORT and initializes the TextureMappedFont object is called, I can not debug the application…debugger says “Could not initialize the application” but the exe runs just fine outside of debugging.

Any ideas?

Here’s some code if anyone is interested in helping…

I have two apparently competing bits…here’s the texturemappedfont object, and it’s unmodified from the sample except to change the directory of the font files to the current directory.


#ifdef WIN32
#include <windows.h>
#endif

#include "texturemappedfont.h"
#include <GL/glu.h>

TextureMappedFont::TextureMappedFont(const string& textureName, int screenWidth, int screenHeight, float fontSize)
{ 
    m_textureName = textureName;
    m_shaderProgram = new GLSLProgram("font.vert", "font.frag");
    m_screenWidth = screenWidth;
    m_screenHeight = screenHeight;
    m_fontSize = fontSize;
}

bool TextureMappedFont::initialize()
{
    if (!m_texture.load(m_textureName)) {
        std::cerr << "Couldn't load the font texture" << std::endl;
        return false;

    }
        
    glBindTexture(GL_TEXTURE_2D, m_textureID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, m_texture.getWidth(), 
                      m_texture.getHeight(), GL_RGB, GL_UNSIGNED_BYTE, m_texture.getImageData());


    float vertices [] = {
        0.0f, 0.0f,
        m_fontSize, 0.0f, 
        m_fontSize, m_fontSize,
        0.0f, m_fontSize
    };

    glGenBuffers(1, &m_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, &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
    };

    glGenBuffers(1, &m_texCoordBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, &texCoords[0], GL_DYNAMIC_DRAW);

    if (!m_shaderProgram->initialize()) {
        std::cerr << "The shader program could not be initialized" << std::endl;
        return false;
    }

    m_shaderProgram->bindAttrib(0, "a_Vertex");
    m_shaderProgram->bindAttrib(1, "a_TexCoord0");
    m_shaderProgram->linkProgram();

    m_shaderProgram->sendUniform("texture0", 0);

    return true;
}

void TextureMappedFont::printString(const string& str, float x, float y) 
{
    static float modelviewMatrix[16];
    static float projectionMatrix[16];

    m_shaderProgram->bindShader();

    setOrthoMode();

    float texCoords[8];

    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

    glBindTexture(GL_TEXTURE_2D, m_textureID);

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glTranslatef(x, y, 0.0); //Position our text
    for(string::size_type i = 0; i < str.size(); ++i) 
    {
        const float oneOverSixteen = 1.0f / 16.0f;

        int ch = int(str[i]);
        float xPos = float(ch % 16) * oneOverSixteen;
        float yPos = float(ch / 16) * oneOverSixteen;

        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;

        glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * 8, &texCoords[0]);

        glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
        glVertexAttribPointer((GLint)0, 2, GL_FLOAT, GL_FALSE, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);
        glVertexAttribPointer((GLint)1, 2, GL_FLOAT, GL_FALSE, 0, 0);

        glGetFloatv(GL_MODELVIEW_MATRIX, modelviewMatrix);
        glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);

        m_shaderProgram->sendUniform4x4("modelview_matrix", modelviewMatrix);
        m_shaderProgram->sendUniform4x4("projection_matrix", projectionMatrix);

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

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    unsetOrthoMode();
}

void TextureMappedFont::setOrthoMode()
{
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho(0, m_screenWidth, 0, m_screenHeight, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
}

void TextureMappedFont::unsetOrthoMode()
{
    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
}

And here’s the pertinent calls in my code.


bool ReactionTime::init(int width, int height)
{
	// Init OpenGL
	if (!glGenBuffers || !glBindBuffer || !glBufferData || !glDrawRangeElements)
		{
			std::cerr << "VBOs are not supported by your graphics card" << std::endl;
			return false;
		}

	screenWidth = width;
	screenHeight = height;

	glEnable(GL_DEPTH_TEST);
	glClearColor(0.0f, 0.0f, 0.3f, 1.0f);

	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	currentStage = RESET;

	plotArrows(CROSS);
	genBuffers();
	updateProjection();

  // If this code is present, I cannot debug, but my drawn elements do appear if the printstring call is commented out of render
  GLint viewport[4];
  glGetIntegerv(GL_VIEWPORT, viewport);
  m_font = new TextureMappedFont("font.tga", viewport[2], viewport[3], 25.0f);
  if (!m_font->initialize()) {
      std::cerr << "Could not initialize the font" << std::endl;
      return false;
  }

	//Return success
	return true;
}
void ReactionTime::render()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//Load the identity matrix (reset to the default position and orientation)
	glLoadIdentity();
	
	updateProjection();
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	glDrawElements(GL_TRIANGLE_FAN, m_indices.size(), GL_UNSIGNED_INT, 0);

        //the following line causes ONLY the text to be displayed, not my drawn elements, even if it's disabled via if statement...if this line is present, the drawelements above does nothing
	m_font->printString("Simple Reaction Time Task", 0, 0);
}
void ReactionTime::genBuffers()
{
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);

	glGenBuffers(MAX_BUFFERS, &m_vbos[0]);
	glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]); //Bind the vertex buffer
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_vertices.size(), &m_vertices[0], GL_DYNAMIC_DRAW); //Send the data to OpenGL

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the index buffer
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_indices.size(), &m_indices[0], GL_DYNAMIC_DRAW); //Send the data to OpenGL

	glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_colors.size(), &m_colors[0], GL_DYNAMIC_DRAW); //Send the data to OpenGL

	//Bind the color array, and set the color pointer to point at it
	glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]);
	glColorPointer(3, GL_FLOAT, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]);
	glVertexPointer(3, GL_FLOAT, 0, 0);
	
}
void ReactionTime::rebufferData()
{
	glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]); //Bind the vertex buffer
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_vertices.size(), &m_vertices[0], GL_DYNAMIC_DRAW); //Send the new data to OpenGL
	
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the index buffer
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_indices.size(), &m_indices[0], GL_DYNAMIC_DRAW); //Send the new data to OpenGL
		
	glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]); //Bind the color buffer
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_colors.size(), &m_colors[0], GL_DYNAMIC_DRAW); //Send the data to OpenGL


}
void ReactionTime::updateProjection()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	float screenAspect, left, right, bottom, top;
	
	screenAspect = (float) screenWidth / screenHeight;

	left = 0;
	right = 0;
	bottom = -8;
	top = 8;

	left -= (screenAspect * 8);
	right = (screenAspect * 8);

	glOrtho(left, right, top, bottom, 1.0, 100.0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

I left out the prepare routine and the plotarrows routine. prepare just decides which symbol gets drawn based on the task logic and calls plotarrows which sets up the vertices and the indices and the colors…

I can only display either text from the texturemappedfont object or my symbology from the GL_TRIANGLE_FAN…

Any help would be greatly appreciated it…I’m sure it’s just some mode that’s getting toggled or switches and clearing everything else when the text is shown, but I don’t know what.

Anybody have any ideas on this?