From 2ab09b47bf9537bece226e628288c665c6d2dd73 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 3 Dec 2020 22:31:55 -0500 Subject: [PATCH] Some work on rendering glyphs. --- src/jes/gui/font.c | 2 +- src/jes/gui/font.d | 102 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 6 deletions(-) diff --git a/src/jes/gui/font.c b/src/jes/gui/font.c index db3d05c..1128f79 100644 --- a/src/jes/gui/font.c +++ b/src/jes/gui/font.c @@ -11,10 +11,10 @@ static bool Initialized; typedef struct { - FT_Face face; int32_t advance; int32_t line_height; int32_t baseline_offset; + FT_Face face; } Font; typedef struct diff --git a/src/jes/gui/font.d b/src/jes/gui/font.d index 62a7ab0..a72b5d0 100644 --- a/src/jes/gui/font.d +++ b/src/jes/gui/font.d @@ -1,7 +1,15 @@ module jes.gui.font; import std.string; +import derelict.opengl; +import gltk; +import core.stdc.string; -struct CFont; +struct CFont +{ + int advance; + int line_height; + int baseline_offset; +} struct CGlyph { @@ -20,20 +28,72 @@ private extern(C) void Font_Free(CFont * font); class Font { + private static __gshared Glyph[uint] glyphs; + class Glyph { int advance; + gltk.Texture m_texture; + gltk.Buffer m_buffer; + gltk.Array m_array; + + this(const(CGlyph) * cglyph) + { + advance = cglyph.advance; + m_texture = new gltk.Texture(); + m_texture.bind(GL_TEXTURE_2D); + int rounded_width = gltk.Texture.next_power_of_2(cglyph.width); + int rounded_height = gltk.Texture.next_power_of_2(cglyph.height); + ubyte[] texture = new ubyte[rounded_width * rounded_height]; + memset(texture.ptr, 0, rounded_width * rounded_height); + for (int i = 0; i < cglyph.height; i++) + { + memcpy(&texture[rounded_width * i], + &cglyph.bitmap[cglyph.width * (cglyph.height - i - 1)], + cglyph.width); + } + + 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); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, rounded_width, rounded_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texture.ptr); + + m_array = new gltk.Array(); + m_array.bind(); + + int left = cglyph.left; + int top = cglyph.top; + float s_max = cglyph.width / cast(float)rounded_width; + float t_max = cglyph.height / cast(float)rounded_height; + m_buffer = new gltk.Buffer(); + GLfloat[] data = [ + cast(GLfloat)left, cast(GLfloat)(top - cglyph.height), 0.0, 0.0, + cast(GLfloat)(left + cglyph.width), cast(GLfloat)(top - cglyph.height), s_max, 0.0, + cast(GLfloat)left, cast(GLfloat)top, 0.0, t_max, + cast(GLfloat)(left + cglyph.width), cast(GLfloat)top, s_max, t_max, + ]; + m_buffer.set_buffer_data(GL_ARRAY_BUFFER, GL_STATIC_DRAW, data.ptr, data.length); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, null); + } + void render() { + m_array.bind(); + m_texture.bind(GL_TEXTURE_2D); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } - CFont * font; + CFont * m_font; this(const char * fname, int size) { - font = Font_Load(fname, size); - if (font == null) + m_font = Font_Load(fname, size); + if (m_font == null) { throw new Exception("Could not load font"); } @@ -46,6 +106,38 @@ class Font ~this() { - Font_Free(font); + Font_Free(m_font); + } + + @property int advance() + { + return m_font.advance; + } + + @property int line_height() + { + return m_font.line_height; + } + + @property int baseline_offset() + { + return m_font.baseline_offset; + } + + Glyph get_glyph(uint char_code) + { + if (char_code in glyphs) + { + return glyphs[char_code]; + } + Glyph glyph; + CGlyph * cglyph = Font_LoadGlyph(m_font, char_code); + if (cglyph != null) + { + glyph = new Glyph(cglyph); + Font_FreeGlyph(cglyph); + } + glyphs[char_code] = glyph; + return glyph; } }