# How do I render a word in the middle of the screen using FreeType and OpenGL?

I'm following this tutorial series on making a simple 2D clone of the classic Breakout game, but its author doesn't mention how to render a whole word or sentence in the middle of the screen. He simply uses hard-coded X and Y coordinates that obviously work for his screen, but not for mine (hence why the mere suggestion of using hard-coded values for something like this makes my skin crawl).

For more details on how he accomplishes the task, see this page of the aforementioned tutorial.

My version of his game has two major differences:

1. I am rendering the GLFW window in fullscreen mode instead of a 800x600 window.
2. I suspect that even if I were to use a 800x600 window, things still wouldn't look consistent across every device. As such I have made many changes to hard-coded values across the entire code base.

I'm a perfectionist so even though no-one else will probably ever run my game, I'm trying to eliminate the possibility of different results on different resolutions. But to do that has turned out to be a massive undertaking!

Here is the code that I'm having particular trouble with:

void TextRenderer::RenderText(string text, GLfloat x, GLfloat y, GLfloat scale, vec3 color) {
// Activate corresponding render state

glActiveTexture(GL_TEXTURE0);
glBindVertexArray(vao);

// Iterate through all characters
for (auto c = text.begin(); c != text.end(); c++) {
auto ch = characters[*c];

auto xPos = x + ch.bearing.x * scale;
auto yPos = y + (characters['H'].bearing.
y - ch.bearing.y) * scale;
auto w = ch.size.x * scale;
auto h = ch.size.y * scale;

// Update VBO for each character
GLfloat vertices[6][4] = {
{ xPos,     yPos + h, 0.0, 1.0 },
{ xPos + w, yPos,     1.0, 0.0 },
{ xPos,     yPos,     0.0, 0.0 },

{ xPos,     yPos + h, 0.0, 1.0 },
{ xPos + w, yPos + h, 1.0, 1.0 },
{ xPos + w, yPos,     1.0, 0.0 }
};

// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.textureID);

// Update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0,
sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);

// Render quad and advance cursors for next glyph
glDrawArrays(GL_TRIANGLES, 0, 6);
// Bitshift by 6 to get value in pixels (1/64th times 2^6 = 64)
x += (ch.advance >> 6) * scale;
}

glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}


I have tried adding a bool centreX and bool centreY param to the function, as well as another for loop before the main one like this:

if (centreX || centreY) {
auto textWidth = 0.0f;
auto textHeight = 0.0f;

for (auto c = text.begin(); c != text.end(); c++) {
auto ch = characters[*c];

if (centreX) {
textWidth += (ch.bearing.x * scale) + (ch.size.
x * scale) + ((ch.advance >> 6) * scale);
}

if (centreY) {
textHeight += (y + (characters['H'].bearing.y -
ch.bearing.y) * scale) + (ch.size.y * scale);
}
}

if (centreX) {
auto lastCh = text.end() - 1;
textWidth -= (characters[*lastCh].advance >> 6) * scale;
}
}


But for the sentence, font and font size used I'm getting a textWidth value of 1952 while a screenshot of the rendered text is 1143 px wide :S

Where has my math or understanding of the original code gone wrong? My display is a high DPI one and I have my Windows scaling settings at 200%; could either of those things be the culprit?

MTIA!

The picture below (from the website you linked) is quite good to understand what is going on. Advance is the distance from one character's origin to the next. To get the width of the whole text you should add the advances together. Right now you are adding the bearing, the width and the advance.
Once you have the size of your text and the size of your window you can add an offset to each character that is (window_width - text_width)/2.