So I'm trying to render 2D text in my Game Engine using programmable pipeline.
Normally I'm using perspective projection matrix but for UI elements I'm trying to create orthographic projection matrix with near plane -1 and far plane 1.
I was using deprecated solution before with gluOrtho2D
and it was something like this:
SDL_Color color = { (U8)textsToRender.at(i)->color->r, (U8)textsToRender.at(i)->color->g, (U8)textsToRender.at(i)->color->b };
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluOrtho2D(0, Window::getWidth(), Window::getHeight(), 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
TTF_Font *m_font = TTF_OpenFont(textsToRender.at(i)->file->getPath().c_str(), textsToRender.at(i)->size);
if(!m_font && isGameRunning() == true) Error::throwError((char*) "Cannot load font file!");
SDL_Surface *sFont = TTF_RenderText_Blended(m_font, textsToRender.at(i)->msg.c_str(), color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sFont->w, sFont->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, sFont->pixels);
glBegin(GL_QUADS);
{
glTexCoord2f(0.0f, 0.0f); glVertex2f(textsToRender.at(i)->pos->x, textsToRender.at(i)->pos->y);
glTexCoord2f(1.0f, 0.0f); glVertex2f(textsToRender.at(i)->pos->x + sFont->w, textsToRender.at(i)->pos->y);
glTexCoord2f(1.0f, 1.0f); glVertex2f(textsToRender.at(i)->pos->x + sFont->w, textsToRender.at(i)->pos->y + sFont->h);
glTexCoord2f(0.0f, 1.0f); glVertex2f(textsToRender.at(i)->pos->x, textsToRender.at(i)->pos->y + sFont->h);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glDeleteTextures(1, &texture);
TTF_CloseFont(m_font);
SDL_FreeSurface(sFont);
And with this code everything is OK. I received really nice text, I could change size, even text color.
But because I'm creating my engine with programmable pipeline (GLSL shaders) solutions only I decided to create new shader program, 2 shader files and my own orthographic projection matrix "recipe".
Here is my code after changes:
SDL_Color color = { (U8)textsToRender.at(i)->color->r, (U8)textsToRender.at(i)->color->g, (U8)textsToRender.at(i)->color->b };
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
TTF_Font *m_font = TTF_OpenFont(textsToRender.at(i)->file->getPath().c_str(), textsToRender.at(i)->size);
if(!m_font && isGameRunning() == true) Error::throwError((char*) "Cannot load font file!");
SDL_Surface *sFont = TTF_RenderText_Blended(m_font, textsToRender.at(i)->msg.c_str(), color);
std::vector<F32> positions;
positions.push_back(textsToRender.at(i)->pos->x);
positions.push_back(textsToRender.at(i)->pos->y);
positions.push_back(textsToRender.at(i)->pos->x + sFont->w);
positions.push_back(textsToRender.at(i)->pos->y);
positions.push_back(textsToRender.at(i)->pos->x + sFont->w);
positions.push_back(textsToRender.at(i)->pos->y + sFont->h);
positions.push_back(textsToRender.at(i)->pos->x);
positions.push_back(textsToRender.at(i)->pos->y + sFont->h);
std::vector<F32> textureVectors;
textureVectors.push_back(0.0f);
textureVectors.push_back(0.0f);
textureVectors.push_back(1.0f);
textureVectors.push_back(0.0f);
textureVectors.push_back(1.0f);
textureVectors.push_back(1.0f);
textureVectors.push_back(0.0f);
textureVectors.push_back(1.0f);
U32 vaoID = VertexArrayObject::loadToVAO(positions, textureVectors);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sFont->w, sFont->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, sFont->pixels);
uiShader->start(); //
uiShader->loadProjectionMatrix(projectionMatrixOrtho); //LOADS projection matrix to my shader program
glBindVertexArray(vaoID);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glActiveTexture(GL_TEXTURE0);
glDrawArrays(GL_TRIANGLES, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
uiShader->stop();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glDeleteTextures(1, &texture);
TTF_CloseFont(m_font);
SDL_FreeSurface(sFont);
Recipe for my orthographic matrix:
Matrix4 *projectionMatrix = new Matrix4(); F32 left = 0.0f; F32 right = (F32) Window::getWidth(); F32 bottom = (F32) Window::getHeight(); F32 top = 0.0f; F32 near = -1.0f; F32 far = 1.0f; F32 xO = 2.0f / (right - left); F32 yO = 2.0f / (top - bottom); F32 zO = -2.0f / (far - near); F32 tx = -(right + left) / (right - left); F32 ty = -(top + bottom) / (top - bottom); F32 tz = -(far + near) / (far - near); projectionMatrix->m00 = xO; projectionMatrix->m10 = 0.0f; projectionMatrix->m20 = 0.0f; projectionMatrix->m30 = 0.0f; projectionMatrix->m01 = 0.0f; projectionMatrix->m11 = yO; projectionMatrix->m21 = 0.0f; projectionMatrix->m31 = 0.0f; projectionMatrix->m02 = 0.0f; projectionMatrix->m12 = 0.0f; projectionMatrix->m22 = zO; projectionMatrix->m32 = 0.0f; projectionMatrix->m03 = tx; projectionMatrix->m13 = ty; projectionMatrix->m23 = tz; projectionMatrix->m33 = 1.0f;
Vertex Shader:
#version 400 core in vec2 position; in vec2 textureVector; out vec2 textureCoords; uniform mat4 projectionMatrix; void main(void) { textureCoords = textureVector; gl_Position = projectionMatrix * vec4(position, 0.0, 1.0); }
And Fragment Shader:
#version 400 core in vec2 textureCoords; out vec4 out_Color; uniform sampler2D sampler; void main(void) { out_Color = texture(sampler,textureCoords); }
And what I receive on my screen instead of nice font like before is something like this:
I'm using GLEW, SDL2 with SDL2_image and SDL2_ttf.
Everything is OK with my VAO, shader program. I guess here is something wrong with my orthographic projection matrix, I checked my code 100 times and didn't found any mistake. Maybe wrong recipe?