diff options
author | Nikolas <nikolas@boutalas.com> | 2024-10-27 12:52:55 +0200 |
---|---|---|
committer | Nikolas <nikolas@boutalas.com> | 2024-10-27 12:52:55 +0200 |
commit | 43394c8a8908442982e3a7e25975c31b3c952923 (patch) | |
tree | 2facd563e29f48fe3b0653ac5c113998940b4d5e /graphics/fonts.cpp |
Diffstat (limited to 'graphics/fonts.cpp')
-rw-r--r-- | graphics/fonts.cpp | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/graphics/fonts.cpp b/graphics/fonts.cpp new file mode 100644 index 0000000..760e676 --- /dev/null +++ b/graphics/fonts.cpp @@ -0,0 +1,212 @@ + +#include "fonts.h" +#include <algorithm> +#include "glm/gtc/matrix_transform.hpp" +#include "glm/gtx/transform.hpp" + +#ifdef __APPLE__ +#define sggBindVertexArray glBindVertexArrayAPPLE +#define sggGenVertexArrays glGenVertexArraysAPPLE +#else +#define sggBindVertexArray glBindVertexArray +#define sggGenVertexArrays glGenVertexArrays +#endif + +const char* __FontVertexShader = R"( +#version 120 + +attribute vec4 coord; +varying vec2 texcoord; +uniform mat4 projection; +uniform mat4 modelview; + +void main(void) { + gl_Position = projection * modelview * vec4(coord.xy, 0, 1); + texcoord = coord.zw; +} +)"; + +const char* __FontFragmentShader = R"( +#version 120 + +varying vec2 texcoord; +uniform vec4 color1; +uniform vec4 color2; +uniform sampler2D tex; +uniform vec2 gradient; + +void main(void) { + vec4 color = mix( color1, color2, dot(texcoord,gradient)); + gl_FragColor = vec4(1, 1, 1, texture2D(tex, texcoord).r) * color; +} +)"; + + + +bool FontLib::init() +{ + if (FT_Init_FreeType(&m_ft)) + { + return false; + } + + glGetError(); + const GLubyte * s = glewGetErrorString(glGetError()); + + m_font_shader = Shader(__FontVertexShader, __FontFragmentShader); + + + if (!m_font_shader.init()) + return false; + + unsigned int attrib_position = m_font_shader.getAttributeLocation("coord"); + + sggGenVertexArrays(1, &m_font_vao); + sggBindVertexArray(m_font_vao); + + glGenBuffers(1, &m_font_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_font_vbo); + glEnableVertexAttribArray(attrib_position); + glVertexAttribPointer(attrib_position, 4, GL_FLOAT, GL_FALSE, 0, 0); + + GLfloat box[4][4] = { + { -1, 1 , 0, 0 }, + { 1, 1 , 1, 0 }, + { -1, -1, 0, 1 }, + { 1, -1, 1, 1 }, + }; + glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW); + + m_curr_font = m_fonts.end(); + + return true; +} + +void FontLib::submitText(const TextRecord & text) +{ + m_content.push_back(text); +} + +void FontLib::drawText(TextRecord entry) +{ + float x = 0.0f; + float y = 0.0f; + + const char *p; + if (m_curr_font == m_fonts.end()) + return; + Font font = m_curr_font->second; + FT_GlyphSlot g = font.face->glyph; + +#ifndef __APPLE__ + //glFrontFace(GL_CW); +#endif + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, font.font_tex); + static int c = 0; + + m_font_shader.use(); + + m_font_shader["tex"] = 0; + + m_font_shader["color1"] = entry.color1; + m_font_shader["color2"] = (entry.use_gradient? entry.color2 : entry.color1); + m_font_shader["gradient"] = entry.gradient; + m_font_shader["projection"] = entry.proj; + + for (p = entry.text.c_str(); *p; p++) { + if (FT_Load_Char(font.face, *p, FT_LOAD_RENDER)) + continue; + + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RED, + g->bitmap.width, + g->bitmap.rows, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + g->bitmap.buffer + ); + + + float w = g->bitmap.width; + float h = g->bitmap.rows; + w = entry.size.x * g->bitmap.width / (float)m_font_res; + h = entry.size.y * g->bitmap.rows / (float)m_font_res; + float b = g->metrics.horiBearingY/(64* (float)m_font_res)*entry.size.y - h; + + GLfloat box[4][4] = { + { x, y-b , 0, 1 }, + { x + w, y-b , 1, 1 }, + { x, y - h - b, 0, 0 }, + { x + w, y - h -b, 1, 0 }, + }; + + m_font_shader["modelview"] = glm::translate(glm::vec3(entry.pos.x, entry.pos.y, 0.0f)) * entry.mv; + + + sggBindVertexArray(m_font_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_font_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + x += std::max(w+ entry.size.x*0.05f, entry.size.x*0.15f); + y += entry.size.y*1.1f*(g->advance.y); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glFrontFace(GL_CCW); +} + +void FontLib::commitText() +{ + m_font_shader.use(); + glEnable(GL_SCISSOR_TEST); + for (auto item : m_content) + { + drawText(item); + } + m_content.clear(); + +} + +void FontLib::setCanvas(glm::vec2 sz) +{ + m_canvas = sz; +} + +bool FontLib::setCurrentFont(std::string fontname) +{ + m_curr_font = m_fonts.find(fontname); + if (m_curr_font != m_fonts.end()) + return true; + + Font font; + if (FT_New_Face(m_ft, fontname.c_str(), 0, &font.face)) + { + return false; + } + FT_Set_Pixel_Sizes(font.face, 0, m_font_res); + + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &font.font_tex); + glBindTexture(GL_TEXTURE_2D, font.font_tex); + 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); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + m_curr_font = m_fonts.insert(std::pair<std::string, Font>(fontname,font)).first; + return true; +} + + + +FT_Library FontLib::m_ft = nullptr; |