0
\$\begingroup\$

I'm trying to add text rendering to my rendering project and am following the OpenGL tutorial at https://learnopengl.com/In-Practice/Text-Rendering I'm using SDL2 as my backend so had to make some adjustments to the provided examples in the tutorial. The strange thing is that when I comment out the 'glClearColor(GL_COLOR_BUFFER_BIT)' line the text rendering works except because I never clear the screen the rendering is all flickery and weird cause I never clear the other buffer. But when I do clear the screen the window looks fine but there is no text.

Edit: Following the suggestion from @TomTsagk in the comments I added GL_DEPTH_BUFFER_BIT to the glClear call and it cause “Hello World!” To momentarily flash when the window opened by still no luck.

Edit 2: The depth buffer was the issue! But because I was never resetting the x-coordinates to render at, it would flash off screen before I could see it.

Here is an extracted minimal example:

#include <iostream>
#include <string>
#include <map>

#include "SDL.h"
#undef main

#include "glad/glad.h"

#include "ft2build.h"
#include FT_FREETYPE_H

using sdl_gl_context = void*;

struct Character {

    unsigned int texture_id;
    glm::ivec2 size;
    glm::ivec2 bearing;
    unsigned int advance;

};

std::map<char , Character> characters{};

int main(int argc, char* argv[]) {

    SDL_Window* window = nullptr;

    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        std::cout << "SDL2 failed to initialize" << std::endl;
        return 1;
    }

    Uint32 flags = SDL_WINDOW_OPENGL;

    window = SDL_CreateWindow("Tests" , SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED , 1920 , 1080 , flags);
    if (window == nullptr) {
        std::cout << "SDL2 failed to create window" << std::endl;
        return 1;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER , 1);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE , 8);
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS , 1);
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES , 24);

    SDL_SetWindowMinimumSize(window , 200 , 200);

    sdl_gl_context context = SDL_GL_CreateContext(window);
    if (context == nullptr) {
        std::cout << "SDL2 failed to create OpenGL context" << std::endl;
        return 1;
    }
    
    SDL_GL_SetSwapInterval(1);
    
    if (gladLoadGLLoader(SDL_GL_GetProcAddress) == 0) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return 1;
    }

    glEnable(GL_CULL_FACE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glEnable(GL_MULTISAMPLE);

    glClearColor(0.2f , 0.3f , 0.3f , 1.f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    YE::rendering::Shader shader("shaders/text_shader.vert" , "shaders/text_shader.frag");
    glm::mat4 projection = glm::ortho(0.f , 1920.f , 0.f , 1080.f);

    shader.Bind();
    shader.SetUniformMat4("proj" , projection);

    FT_Library ft;
    if (FT_Init_FreeType(&ft)) {
        std::cout << "Failed to initialize FreeType" << std::endl;
        return 1;
    }

    FT_Face face;
    if (FT_New_Face(ft , "res/fonts/Arial.ttf" , 0 , &face)) {
        std::cout << "Failed to load font" << std::endl;
        return 1;
    } else {
        FT_Set_Pixel_Sizes(face , 0 , 48);
        glPixelStorei(GL_UNPACK_ALIGNMENT , 1);

        for (unsigned char c = 0; c < 128; c++) {
            if (FT_Load_Char(face , c , FT_LOAD_RENDER)) {
                std::cout << "Failed to load glyph" << std::endl;
                continue;
            }

            unsigned int texture;
            glGenTextures(1 , &texture);
            glBindTexture(GL_TEXTURE_2D , texture);
            glTexImage2D(GL_TEXTURE_2D , 0 , GL_RED , face->glyph->bitmap.width , face->glyph->bitmap.rows ,
                         0 , GL_RED , GL_UNSIGNED_BYTE , face->glyph->bitmap.buffer);
            
            glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR);

            Character character = {
                texture ,
                glm::ivec2(face->glyph->bitmap.width , face->glyph->bitmap.rows) ,
                glm::ivec2(face->glyph->bitmap_left , face->glyph->bitmap_top) ,
                static_cast<unsigned int>(face->glyph->advance.x)
            };
            characters.insert(std::pair<char , Character>(c , character));
        }
        glBindTexture(GL_TEXTURE_2D , 0);
    }
    FT_Done_Face(face);
    FT_Done_FreeType(ft);

    uint32_t vao , vbo;
    glGenVertexArrays(1 , &vao);
    glGenBuffers(1 , &vbo);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER , vbo);
    glBufferData(GL_ARRAY_BUFFER , sizeof(float) * 6 * 4 , nullptr , GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0 , 4 , GL_FLOAT , GL_FALSE , 4 * sizeof(float) , 0);
    glBindBuffer(GL_ARRAY_BUFFER , 0);
    glBindVertexArray(0);

    float x = 960.f;
    float y = 510.f;
    float scale = 1.f;

    std::string text = "Hello World!";

    bool running = true;
    while (running) {

        SDL_Event e;

        while (SDL_PollEvent(&e)) {
            switch (e.type) {
                case SDL_WINDOWEVENT:
                    switch (e.window.event) {
                        case SDL_WINDOWEVENT_CLOSE: running = false; break;
                        default: break;
                    }
                break;
                break;
                case SDL_KEYDOWN:
                    switch (e.key.keysym.sym) {
                        case SDLK_ESCAPE: running = false; break;
                        default: break;
                    }
                break;
                default: break;
            }
        }
        
        // glClear(GL_COLOR_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

        shader.Bind();
        shader.SetUniformVec3("text_color" , { 1.f , 1.f , 1.f });
        glActiveTexture(GL_TEXTURE0);
        glBindVertexArray(vao);

        std::string::const_iterator c;
        for (c = text.begin(); c != text.end(); c++) {
            Character ch = characters[*c];
            
            float xpos = x + ch.bearing.x * scale;
            float ypos = y - (ch.size.y - ch.bearing.y) * scale;

            float w = ch.size.x * scale;
            float h = ch.size.y * scale;

            float vertices[6][4] = {
                { xpos ,    ypos + h ,   0.f , 0.f } ,
                { xpos ,     ypos ,       0.f , 1.f } ,
                { xpos + w , ypos ,       1.f , 1.f } ,

                { xpos ,     ypos + h ,   0.f , 0.f } ,
                { xpos + w , ypos ,       1.f , 1.f } ,
                { xpos + w , ypos + h ,   1.f , 0.f } ,
            };

            glBindTexture(GL_TEXTURE_2D , ch.texture_id);
            glBindBuffer(GL_ARRAY_BUFFER , vbo);
            glBufferSubData(GL_ARRAY_BUFFER , 0 , sizeof(vertices) , vertices);
            glBindBuffer(GL_ARRAY_BUFFER , 0);
            glDrawArrays(GL_TRIANGLES , 0 , 6);

            x += (ch.advance >> 6) * scale;
        }
        glBindVertexArray(0);
        glBindTexture(GL_TEXTURE_2D , 0);
        shader.Unbind();
        
        SDL_GL_SwapWindow(window);
        SDL_PumpEvents();
        
    }

    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(window);
    SDL_Quit();

}

For reference here is when I call glClearColor(GL_COLOR_BUFFER_BIT) in the normal spot clearing screen

And here is when I comment it out except you have to imagine a horrible flickering no clearing the screen

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I think that's a Depth Buffer issue

Looking at your code, I suspect the error is you are not clearing the Depth Buffer every frame.

Replace the following line:

// glClear(GL_COLOR_BUFFER_BIT);

With

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Why does it happen?

If that's indeed what the problem is, it happens because on the first frame you draw the text on the screen, but because you don't clear the depth buffer, on the next frame the program things the new text is about to be drawn on the same spot as another object (the text of the previous frame) and it skips rendering it as it thinks it won't be visible.

By clearing the Depth buffer, you are basically telling the system, at the beginning of the frame, there's no objects in the scene, so when the text is about to be drawn again, it shouldn't be skipped, as the depth buffer doesn't have any other object on the same position.

Also: The text's position is not reset

The variable x is initialised before the loop:

float x = 960.f;

Then inside the loop at some point the variable x's value changes:

x += (ch.advance >> 6) * scale;

However the value of x doesn't reset each frame, causing it's value to keep increasing, rendering the text off-screen.

To solve this, you can re-init the variable of x at the beginning of each frame:

while (running) {
    x = 960.f;
    // ...
\$\endgroup\$
3
  • \$\begingroup\$ Unfortunately this doesn’t seem to do it :/ it did cause the “Hello World!” to momentarily flash across the screen right when the window opened though so it did have some effect. \$\endgroup\$
    – YamMan
    Jun 13, 2023 at 2:12
  • \$\begingroup\$ @YamMan One other thing I noticed is, you have the declaration of float x = 960.f; just before your loop starts, and for each letter you change the value of x without resetting it. Could that be an additional issue? Try adding x = 960.f; just after while (running) { \$\endgroup\$ Jun 13, 2023 at 9:00
  • 1
    \$\begingroup\$ That was it! I guess the depth buffer did fix it but it got shifted do far right it didn't even matter!! Thank you for your time and your help I really appreciate it! \$\endgroup\$
    – YamMan
    Jun 13, 2023 at 14:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .