Skip to content

Commit

Permalink
[TextRenderer] render text at 3d pose
Browse files Browse the repository at this point in the history
  • Loading branch information
sarthou committed Aug 16, 2024
1 parent d8c9066 commit 1378b17
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 1 deletion.
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ find_package(assimp REQUIRED)
find_package(Bullet REQUIRED)
find_package(Eigen3 3.3 REQUIRED NO_MODULE)
find_package(glm CONFIG REQUIRED)
find_package(Freetype REQUIRED)

include(FetchContent)
include(CheckLanguage)
Expand Down Expand Up @@ -171,9 +172,11 @@ owds_add_library(overworld_graphics
src/Engine/Graphics/OpenGL/Renderer.cpp
src/Engine/Graphics/OpenGL/Screen.cpp
src/Engine/Graphics/OpenGL/Shader.cpp
src/Engine/Graphics/OpenGL/TextRenderer.cpp
src/Engine/Graphics/OpenGL/AmbientShadow.cpp
src/Engine/Graphics/OpenGL/Texture2D.cpp)
target_link_libraries(overworld_graphics PUBLIC overworld_engine_common overworld_glad assimp glfw)
target_link_libraries(overworld_graphics PUBLIC overworld_engine_common overworld_glad assimp glfw ${FREETYPE_LIBRARIES})
target_include_directories(overworld_graphics PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_compile_options(overworld_graphics PRIVATE $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-function>)

# ##################################
Expand Down
2 changes: 2 additions & 0 deletions include/overworld/Engine/Graphics/OpenGL/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "overworld/Engine/Graphics/OpenGL/PointShadow.h"
#include "overworld/Engine/Graphics/OpenGL/Screen.h"
#include "overworld/Engine/Graphics/OpenGL/Shader.h"
#include "overworld/Engine/Graphics/OpenGL/TextRenderer.h"

namespace owds {
class Window;
Expand Down Expand Up @@ -46,6 +47,7 @@ namespace owds {
Cubemap sky_;
AmbientShadow shadow_;
PointShadow point_shadows_;
TextRenderer text_renderer_;
float max_fps_ = 120;
float delta_time_;
float last_frame_;
Expand Down
40 changes: 40 additions & 0 deletions include/overworld/Engine/Graphics/OpenGL/TextRenderer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef OWDS_TEXTRENDERER_H
#define OWDS_TEXTRENDERER_H

#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <map>
#include <string>

namespace owds {

class Shader;

struct Character_t
{
unsigned int texture_id_;
glm::ivec2 size; // size of glyph
glm::ivec2 bearing; // offset from baseline to left/top of glyph
unsigned int advance; // horizontal offset to advance to next glyph
};

class TextRenderer
{
public:
void init();

bool load(const std::string& font, unsigned int font_size);

void renderText(Shader& shader, const std::string& text, const glm::vec3& position, float height, const glm::vec3& color);

private:
unsigned int vao_;
unsigned int vbo_;
unsigned int pixel_size_;

std::map<char, Character_t> characters_;
};

} // namespace owds

#endif // OWDS_TEXTRENDERER_H
21 changes: 21 additions & 0 deletions src/Engine/Graphics/OpenGL/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,15 @@ namespace owds {
shaders_.insert({
"depthcube", {"depthcube_shader.vs", "depthcube_shader.fs", "depthcube_shader.gs"}
});
shaders_.insert({
"text", {"text_shader.vs", "text_shader.fs"}
});

sky_.init("/home/gsarthou/Robots/Dacobot2/ros2_ws/src/overworld/models/textures/skybox/Footballfield/");

shadow_.init(render_camera_.getNearPlane(), render_camera_.getFarPlane());
text_renderer_.init();
text_renderer_.load("/usr/share/fonts/truetype/open-sans/OpenSans-Regular.ttf", 48);

shaders_.at("screen").use();
shaders_.at("screen").setInt("screenTexture", 0);
Expand Down Expand Up @@ -319,6 +324,7 @@ namespace owds {
{
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDisable(GL_BLEND);

// glStencilFunc(GL_ALWAYS, 1, 0xFF); // all fragments should pass the stencil test
// glStencilMask(0xFF); // enable writing to the stencil buffer
Expand All @@ -329,6 +335,7 @@ namespace owds {
auto& sky_shader = shaders_.at("sky");
auto& shadow_shader = shaders_.at("depth");
auto& shadow_point_shader = shaders_.at("depthcube");
auto& text_shader = shaders_.at("text");

// 0. draw scene as normal in depth buffers

Expand Down Expand Up @@ -389,14 +396,28 @@ namespace owds {

renderModels(light_shader, 2);

// 1.2 draw background

sky_shader.use();
glm::mat4 view = glm::mat4(glm::mat3(render_camera_.getViewMatrix()));
sky_shader.setMat4("view", view);
sky_shader.setMat4("projection", render_camera_.getProjectionMatrix());

sky_.draw(sky_shader);

// 1.3 draw text

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

text_shader.use();
text_shader.setMat4("projection", render_camera_.getProjectionMatrix());
text_shader.setMat4("view", render_camera_.getViewMatrix());

text_renderer_.renderText(text_shader, "tesH", glm::vec3(0, 0, 5), 1, glm::vec3(1.f, 0.f, 1.f));

// 2. now blit multisampled buffer(s) to normal colorbuffer of intermediate FBO. Image is stored in screenTexture
glDisable(GL_BLEND);
screen_.generateColorTexture();

// 3. now render quad with scene's visuals as its texture image
Expand Down
138 changes: 138 additions & 0 deletions src/Engine/Graphics/OpenGL/TextRenderer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#include "overworld/Engine/Graphics/OpenGL/TextRenderer.h"

#include <freetype/freetype.h>
#include <string>

#include "glad/glad.h"
#include "overworld/Engine/Graphics/OpenGL/Shader.h"
#include "overworld/Utility/ShellDisplay.h"

namespace owds {

void TextRenderer::init()
{
glGenVertexArrays(1, &vao_);
glGenBuffers(1, &vbo_);
glBindVertexArray(vao_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, nullptr, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}

bool TextRenderer::load(const std::string& font, unsigned int font_size)
{
characters_.clear();

FT_Library ft;
if(FT_Init_FreeType(&ft) != 0) // all functions return a value different than 0 whenever an error occurred
{
ShellDisplay::error("[TextRenderer] Could not init FreeType Library");
return false;
}

FT_Face face;
if(FT_New_Face(ft, font.c_str(), 0, &face))
{
ShellDisplay::error("[TextRenderer] CFailed to load font " + font);
return false;
}

FT_Set_Pixel_Sizes(face, 0, font_size);
pixel_size_ = font_size;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

for(GLubyte c = 0; c < 128; c++)
{
if(FT_Load_Char(face, c, FT_LOAD_RENDER))
{
ShellDisplay::error("[TextRenderer] Failed to load Glyph " + std::string(1, c));
continue;
}

unsigned int texture = 0;
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_t character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
(unsigned int)face->glyph->advance.x};
characters_.emplace((char)c, character);
}
glBindTexture(GL_TEXTURE_2D, 0);

FT_Done_Face(face);
FT_Done_FreeType(ft);

return true;
}

void TextRenderer::renderText(Shader& shader, const std::string& text, const glm::vec3& position, float height, const glm::vec3& color)
{
shader.use();
shader.setVec3("text_color", color);

glActiveTexture(GL_TEXTURE0);
glBindVertexArray(vao_);

height = height / (float)pixel_size_;

float x = position.x;
float y = position.y;
float z = position.z;

std::string::const_iterator c;
for(c = text.begin(); c != text.end(); c++)
{
Character_t& ch = characters_[*c];

float xpos = x + ch.bearing.x * height;
float zpos = z - (ch.size.y - ch.bearing.y) * height;

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

float vertices[6 * 5] = {
xpos, y, zpos + h, 0.0f, 0.0f,
xpos, y, zpos, 0.0f, 1.0f,
xpos + w, y, zpos, 1.0f, 1.0f,

xpos, y, zpos + h, 0.0f, 0.0f,
xpos + w, y, zpos, 1.0f, 1.0f,
xpos + w, y, zpos + h, 1.0f, 0.0f};

glBindTexture(GL_TEXTURE_2D, ch.texture_id_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);

glDrawArrays(GL_TRIANGLES, 0, 6);

x += (ch.advance >> 6) * height; // bitshift by 6 to get value in pixels (1/64th times 2^6 = 64)
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}

} // namespace owds

0 comments on commit 1378b17

Please sign in to comment.