Font cache
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m34s
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m34s
This commit is contained in:
53
include/JGL/FontCache.h
Normal file
53
include/JGL/FontCache.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace JGL {
|
||||
class CachedGlyph;
|
||||
class CachedFont;
|
||||
class FontCache;
|
||||
}
|
||||
|
||||
class JGL::CachedGlyph {
|
||||
private:
|
||||
GLuint texture = 0;
|
||||
char character;
|
||||
public:
|
||||
int x2offset = 0, y2offset = 0, w = 0, h = 0;
|
||||
float advanceX = 0, advanceY = 0;
|
||||
|
||||
//CachedGlyph(GLuint texture_id, char c);
|
||||
CachedGlyph(GLuint texture_id, char c, float x2o, float y2o, float w, float h, float advX, float advY);
|
||||
char getCharacter();
|
||||
const GLuint* getTexture();
|
||||
};
|
||||
|
||||
class JGL::CachedFont {
|
||||
private:
|
||||
std::vector<CachedGlyph*> glyphs{};
|
||||
unsigned int font_size = 0;
|
||||
unsigned int font_index = 0;
|
||||
public:
|
||||
void appendGlyph(CachedGlyph* glyph);
|
||||
void eraseGlyph(CachedGlyph* glyph);
|
||||
void eraseGlyph(char c);
|
||||
void eraseGlyph(GLuint texture_id);
|
||||
unsigned int getFontSize();
|
||||
unsigned int getFontIndex();
|
||||
CachedGlyph* getGlyph(char c);
|
||||
std::vector<CachedGlyph*>* getGlyphs();
|
||||
CachedFont(unsigned int font_size, unsigned int font_index);
|
||||
};
|
||||
|
||||
class JGL::FontCache {
|
||||
private:
|
||||
std::vector<CachedFont*> cachedFonts = {};
|
||||
public:
|
||||
std::vector<CachedFont*>* getFonts();
|
||||
CachedFont* getFont(unsigned int font_size, unsigned int font_index);
|
||||
void appendFont(CachedFont* font);
|
||||
void newFont(unsigned int font_size, unsigned int font_index);
|
||||
void eraseFont(CachedFont* font);
|
||||
void purgeCache();
|
||||
};
|
@@ -6,6 +6,7 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <JGL/Color3.h>
|
||||
#include <JGL/FontCache.h>
|
||||
#include <J3ML/LinearAlgebra.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||
#include <J3ML/LinearAlgebra/Vector3.h>
|
||||
@@ -49,7 +50,9 @@ namespace JGL {
|
||||
};
|
||||
|
||||
bool InitTextEngine();
|
||||
inline FontCache fontCache;
|
||||
int LoadFont(const std::string& font_path);
|
||||
|
||||
void UnloadFont(int font_index);
|
||||
// TODO: implement correct coloring
|
||||
|
||||
|
10
main.cpp
10
main.cpp
@@ -34,14 +34,9 @@ class JGLDemoWindow : public ReWindow::RWindow
|
||||
public:
|
||||
|
||||
JGLDemoWindow() : ReWindow::RWindow() {}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) :
|
||||
ReWindow::RWindow(title, width, height)
|
||||
{
|
||||
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height){}
|
||||
|
||||
}
|
||||
|
||||
void initGL()
|
||||
{
|
||||
void initGL() {
|
||||
gladLoadGL();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
@@ -64,7 +59,6 @@ public:
|
||||
|
||||
void display() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, getSize().x, getSize().y, 0, -1, 1);
|
||||
|
119
src/FontCache.cpp
Normal file
119
src/FontCache.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include <JGL/FontCache.h>
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
char CachedGlyph::getCharacter() {
|
||||
return character;
|
||||
}
|
||||
|
||||
const GLuint* CachedGlyph::getTexture() {
|
||||
return &texture;
|
||||
}
|
||||
|
||||
CachedGlyph::CachedGlyph(GLuint texture_id, char c, float x2offset, float y2offset, float w, float h, float advanceX, float advanceY) {
|
||||
texture = texture_id;
|
||||
character = c;
|
||||
this->x2offset = x2offset;
|
||||
this->y2offset = y2offset;
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
this->advanceX = advanceX;
|
||||
this->advanceY = advanceY;
|
||||
}
|
||||
|
||||
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
|
||||
glyphs.push_back(glyph);
|
||||
}
|
||||
|
||||
unsigned int JGL::CachedFont::getFontSize() {
|
||||
return font_size;
|
||||
}
|
||||
|
||||
unsigned int JGL::CachedFont::getFontIndex() {
|
||||
return font_index;
|
||||
}
|
||||
|
||||
CachedGlyph* JGL::CachedFont::getGlyph(char c) {
|
||||
for (const auto& g : glyphs)
|
||||
if (c == g->getCharacter())
|
||||
return g;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CachedFont::CachedFont(unsigned int font_size, unsigned int font_index) {
|
||||
this->font_size = font_size;
|
||||
this->font_index = font_index;
|
||||
}
|
||||
|
||||
void CachedFont::eraseGlyph(CachedGlyph* glyph) {
|
||||
if (glyph == nullptr)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < glyphs.size(); i++)
|
||||
if (glyphs[i] == glyph)
|
||||
glDeleteTextures(1, glyphs[i]->getTexture()),
|
||||
delete glyphs[i],
|
||||
glyphs.erase(glyphs.begin() + i);
|
||||
}
|
||||
|
||||
void CachedFont::eraseGlyph(char c) {
|
||||
for (int i = 0; i < glyphs.size(); i++)
|
||||
if (glyphs[i]->getCharacter() == c)
|
||||
glDeleteTextures(1, glyphs[i]->getTexture()),
|
||||
delete glyphs[i],
|
||||
glyphs.erase(glyphs.begin() + i);
|
||||
}
|
||||
|
||||
void CachedFont::eraseGlyph(GLuint texture_id) {
|
||||
for (int i = 0; i < glyphs.size(); i++)
|
||||
if (glyphs[i]->getTexture() == &texture_id)
|
||||
glDeleteTextures(1, glyphs[i]->getTexture()),
|
||||
delete glyphs[i],
|
||||
glyphs.erase(glyphs.begin() + i);
|
||||
}
|
||||
|
||||
std::vector<CachedGlyph*>* CachedFont::getGlyphs() {
|
||||
return &glyphs;
|
||||
}
|
||||
|
||||
void FontCache::appendFont(CachedFont* font) {
|
||||
cachedFonts.push_back(font);
|
||||
}
|
||||
|
||||
void FontCache::newFont(unsigned int font_size, unsigned int font_index) {
|
||||
auto* font = new CachedFont(font_size, font_index);
|
||||
cachedFonts.push_back(font);
|
||||
}
|
||||
|
||||
void FontCache::eraseFont(CachedFont* font) {
|
||||
for (int i = 0; i < cachedFonts.size(); i++) {
|
||||
if (cachedFonts[i] == font) {
|
||||
for (auto& g: *cachedFonts[i]->getGlyphs())
|
||||
cachedFonts[i]->eraseGlyph(g);
|
||||
|
||||
delete cachedFonts[i];
|
||||
cachedFonts.erase(cachedFonts.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FontCache::purgeCache() {
|
||||
//Remove every font from the cache.
|
||||
for (const auto& font : cachedFonts)
|
||||
eraseFont(font);
|
||||
cachedFonts = {};
|
||||
}
|
||||
|
||||
std::vector<CachedFont*>* FontCache::getFonts() {
|
||||
return &cachedFonts;
|
||||
}
|
||||
|
||||
CachedFont* FontCache::getFont(unsigned int font_size, unsigned int font_index) {
|
||||
if (cachedFonts.empty())
|
||||
return nullptr;
|
||||
|
||||
for (auto* f : cachedFonts)
|
||||
if (f->getFontIndex() == font_index && f->getFontSize() == font_size)
|
||||
return f;
|
||||
return nullptr;
|
||||
}
|
122
src/JGL.cpp
122
src/JGL.cpp
@@ -37,6 +37,7 @@ namespace JGL
|
||||
int LoadFont(const std::string &font_path) {
|
||||
if (ft == nullptr)
|
||||
return -1;
|
||||
|
||||
Font font;
|
||||
if (FT_New_Face(ft, font_path.c_str(), 0, &font.face)) {
|
||||
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
|
||||
@@ -47,9 +48,9 @@ namespace JGL
|
||||
for (const auto& f : faces)
|
||||
if (f.index >= newIndex)
|
||||
newIndex = f.index + 1;
|
||||
|
||||
font.index = newIndex;
|
||||
faces.push_back(font);
|
||||
|
||||
std::cout << "Loaded font from " << font_path << " with index " << newIndex << std::endl;
|
||||
return newIndex;
|
||||
}
|
||||
@@ -61,13 +62,12 @@ namespace JGL
|
||||
faces.erase(faces.begin() + i);
|
||||
}
|
||||
|
||||
namespace J2D
|
||||
{
|
||||
namespace J2D {
|
||||
void FillRect2D(const Color3 &color, const Vector2 &pos, const Vector2 &size) {
|
||||
auto vp_pos = pos;
|
||||
auto vp_size = size;
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(vp_pos.x, vp_pos.y);
|
||||
glVertex2f(vp_pos.x, vp_pos.y + vp_size.y);
|
||||
glVertex2f(vp_pos.x + vp_size.x, vp_pos.y + vp_size.y);
|
||||
@@ -122,9 +122,8 @@ namespace JGL
|
||||
glBegin(GL_LINE_LOOP);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float)subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step)
|
||||
{
|
||||
float step = (2.f * M_PI) / (float) subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step) {
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
@@ -138,9 +137,8 @@ namespace JGL
|
||||
glBegin(GL_POLYGON);
|
||||
GLfloat angle;
|
||||
glColor3f(color.r, color.g, color.b);
|
||||
float step = (2.f * M_PI) / (float)subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step)
|
||||
{
|
||||
float step = (2.f * M_PI) / (float) subdivisions;
|
||||
for (angle = 0.0f; angle < (2.f * M_PI); angle += step) {
|
||||
GLfloat x = radius * sin(angle);
|
||||
GLfloat y = radius * cos(angle);
|
||||
x += center.x;
|
||||
@@ -150,20 +148,18 @@ namespace JGL
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void OutlineTriangle2D(const Color3& color, const Triangle2D& tri)
|
||||
{
|
||||
void OutlineTriangle2D(const Color3 &color, const Triangle2D &tri) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void FillTriangle2D(const Color3& color, const Triangle2D& tri)
|
||||
{
|
||||
void FillTriangle2D(const Color3 &color, const Triangle2D &tri) {
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glColor3f(color.r / 255.f, color.g / 255.f, color.b / 255.f);
|
||||
glVertex2f(tri.A.x, tri.A.y);
|
||||
glVertex2f(tri.B.x, tri.B.y);
|
||||
glVertex2f(tri.C.x, tri.C.y);
|
||||
@@ -174,46 +170,79 @@ namespace JGL
|
||||
glUseProgram(0); // Fixed-function pipeline.
|
||||
|
||||
Font font{};
|
||||
CachedFont* cachedFont = fontCache.getFont(size, font_index);
|
||||
|
||||
//If the font doesn't exist in the cache yet.
|
||||
if (!cachedFont) {
|
||||
fontCache.newFont(size, font_index);
|
||||
cachedFont = fontCache.getFont(size, font_index);
|
||||
}
|
||||
|
||||
//Set up the regular font.
|
||||
for (const auto& f : faces)
|
||||
if (f.index == font_index)
|
||||
font = f;
|
||||
if (font.face == NULL) {
|
||||
std::cout << "null font" << std::endl;
|
||||
if (font.face == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
GLfloat currentColor[4];
|
||||
glGetFloatv(GL_CURRENT_COLOR, currentColor);
|
||||
|
||||
glColor3f(color.r/255.f, color.g/255.f, color.b/255.f);
|
||||
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, 1.0f);
|
||||
|
||||
FT_Set_Pixel_Sizes(font.face, 0, size);
|
||||
|
||||
std::vector<GLuint> textures(text.length());
|
||||
for (int i = 0; i < text.length(); i++)
|
||||
{
|
||||
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenTextures(1, &textures.at(i));
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
float x2 = x + g->bitmap_left * scale;
|
||||
float y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
|
||||
float w = g->bitmap.width * scale;
|
||||
float h = g->bitmap.rows * scale;
|
||||
//For each character
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
float x2, y2, w, h;
|
||||
//If the font is in the cache already.
|
||||
if (cachedFont->getGlyph(text.c_str()[i])) {
|
||||
CachedGlyph* glyph = cachedFont->getGlyph(text.c_str()[i]);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, *glyph->getTexture());
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
x2 = x + glyph->x2offset * scale;
|
||||
y2 = -y - glyph->y2offset * scale; // Adjust y-coordinate
|
||||
w = glyph->w * scale;
|
||||
h = glyph->h * scale;
|
||||
x += glyph->advanceX * scale;
|
||||
y += glyph->advanceY * scale;
|
||||
|
||||
} else {
|
||||
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
|
||||
continue;
|
||||
|
||||
FT_GlyphSlot g = font.face->glyph;
|
||||
glGenTextures(1, &textures.at(i));
|
||||
glBindTexture(GL_TEXTURE_2D, textures[i]);
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||
|
||||
x2 = x + g->bitmap_left * scale;
|
||||
y2 = -y - g->bitmap_top * scale; // Adjust y-coordinate
|
||||
w = g->bitmap.width * scale;
|
||||
h = g->bitmap.rows * scale;
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
cachedFont->appendGlyph(new CachedGlyph(textures.at(i), text.c_str()[i], g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
|
||||
}
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
@@ -236,12 +265,10 @@ namespace JGL
|
||||
glVertex2f(x2 + w, y2);
|
||||
|
||||
glEnd();
|
||||
|
||||
x += (g->advance.x >> 6) * scale;
|
||||
y += (g->advance.y >> 6) * scale;
|
||||
}
|
||||
for (unsigned int& texture : textures)
|
||||
glDeleteTextures(1, &texture);
|
||||
|
||||
//for (unsigned int& texture : textures)
|
||||
//glDeleteTextures(1, &texture);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
@@ -250,7 +277,6 @@ namespace JGL
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace J3D
|
||||
{
|
||||
void DrawLine3D(const Color3& color, const Vector3& A, const Vector3& B, float thickness)
|
||||
|
Reference in New Issue
Block a user