Skip to content
This repository has been archived by the owner on Aug 23, 2023. It is now read-only.

Commit

Permalink
Text Rendering: initial
Browse files Browse the repository at this point in the history
  • Loading branch information
corwinn committed Feb 4, 2023
1 parent 754ae4c commit 2728902
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 96 deletions.
Binary file modified diagrams/font_engine.dia
Binary file not shown.
29 changes: 23 additions & 6 deletions engines/h3r_textrenderingengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,13 @@ static void TextService__ToLines(const String & txt, T & s,
const int H3R_MAX_TEXT_WIDTH {640}; // TODO measure the at the game
const int H3R_MAX_TEXT_HEIGHT {480}; // TODO measure the at the game

String TextRenderingEngine::LayoutText(
Font & fnt, const String & txt, const Box & box, Box & actualbox)
String TextRenderingEngine::LayoutText(const String & font_name,
const String & txt, const Box & box, Box & actualbox)
{
Font * fnt = TryLoadFont (font_name);
H3R_ENSURE(fnt != nullptr, "Font not found")
if (H3R_MAX_TEXT_HEIGHT) return txt;

List<String> txt_rows {};
int line_spacing = 0;
int tw = 0, th = 0; // TODO MeasureMultilineText - see
Expand Down Expand Up @@ -146,11 +150,15 @@ String TextRenderingEngine::LayoutText(
bh = th;
actualbox.Size.Y = bh - box.Pos.Y;
}
return txt;
}

byte * TextRenderingEngine::RenderText(
Font & fnt, const String & txt, int & tw, int & th)
const String & font_name, const String & txt, int & tw, int & th)
{
Font * fnt = TryLoadFont (font_name);
H3R_ENSURE(fnt != nullptr, "Font not found")

tw = th = 0;
if (txt.Empty ()) return nullptr;
//TODO shall I render an "Error: Empty String"?
Expand All @@ -161,7 +169,7 @@ byte * TextRenderingEngine::RenderText(
auto trick = [&](String && s)
{
txt_rows.Add ((String &&)s);
Point & size = txt_rows_size.Add (fnt.MeasureText (s));
Point & size = txt_rows_size.Add (fnt->MeasureText (s));
if (size.X > tw) tw = size.X;
if (size.Y > hh) hh = size.Y;
th += size.Y;
Expand All @@ -175,7 +183,7 @@ byte * TextRenderingEngine::RenderText(
//LATER R&D IEnumerable<T> using this.
TextService__ToLines<decltype(trick)> (txt, trick,
[](String && s, decltype(trick) & f) -> void { f ((String &&)s); });
printf ("TRE: rows: %ul: tw: %d, th: %d, hh: %d" EOL,
printf ("TRE: rows: %zu: tw: %d, th: %d, hh: %d" EOL,
txt_rows.Count (), tw, th, hh);
H3R_ENSURE(txt_rows.Count () > 0, "Nope; at least one row shall be here")

Expand All @@ -198,7 +206,7 @@ byte * TextRenderingEngine::RenderText(
int t = b - hh;
printf ("TRE: render text of size: w:%d, h:%d" EOL,
txt_rows_size[i].X, txt_rows_size[i].Y);
fnt.RenderText (
fnt->RenderText (
txt_rows[i], row_buf, txt_rows_size[i].X, txt_rows_size[i].Y);
printf ("TRE: copy rectangle: l:%d, t:%d, w:%d, h:%d" EOL, l, t,
txt_rows_size[i].X, txt_rows_size[i].Y);
Expand All @@ -211,6 +219,15 @@ byte * TextRenderingEngine::RenderText(
return _text_buffer;
}// TextRenderingEngine::RenderText()

Point TextRenderingEngine::MeasureText(
const String & font_name, const String & txt)
{
Font * fnt = TryLoadFont (font_name);
H3R_ENSURE(fnt != nullptr, "Font not found")

return fnt->MeasureText (txt);
}

TextRenderingEngine & TextRenderingEngine::One()
{
static TextRenderingEngine e {};
Expand Down
13 changes: 8 additions & 5 deletions engines/h3r_textrenderingengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
H3R_NAMESPACE

// Renders text into off-screen buffers. Manages glyph caches.
// Optionally: Manages font objects.
// Manages font objects.
// Singleton.
class TextRenderingEngine final
{
Expand All @@ -67,17 +67,20 @@ class TextRenderingEngine final
// Layout and render the text into 2-channel LUMINANCE_ALPHA buffer.
// The "box" could increase in size. Do not manage the returned buffer.
//LATER Alignment
public: byte * RenderText(Font & fnt, const String & txt, int & w, int & h);
public: byte * RenderText(const String & font_name, const String & txt,
int & w, int & h);

public: String LayoutText(Font & fnt, const String & txt, const Box & box,
Box & actualbox);
public: String LayoutText(const String & font_name, const String & txt,
const Box & box, Box & actualbox);

public: Point MeasureText(const String & font_name, const String & txt);

// Helper for font loading + memory management + handle duplicates.
// Returns nullptr on failure. The "! nullptr" one is managed by the engine.
// The Font object can be used at RenderText().
// Feel free to create and manage font objects outside the
// TextRenderingEngine.
public: Font * TryLoadFont(const String & name);
private: Font * TryLoadFont(const String & name);

public: static TextRenderingEngine & One();
};// TextRenderingEngine
Expand Down
101 changes: 95 additions & 6 deletions engines/render_gl/h3r_renderengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "h3r_texcache.h"
#include "h3r_log.h"
#include "h3r_string.h"
#include "h3r_textrenderingengine.h"
#include "h3r_math.h"
#include "h3r_font.h"

H3R_NAMESPACE

Expand All @@ -58,9 +61,6 @@ RenderEngine::RenderEngine(GLsizeiptr max_sprite_frames)
//TODO then figure out little z-offsets (relative) for each control
// (f(z-order) so the entire UI shall be rendered in one gl call
// GL_DEPTH_TEST; and compare to the above; choose the less-code one
//
//TODO texture atlas(es) for the animated sprites (encode frame number at
// some pixel; PixelDB - NoSQL :) )

H3R_ENSURE(global_render_gl_init, "You forgot to call RenderEngine::Init()")

Expand All @@ -73,9 +73,12 @@ RenderEngine::RenderEngine(GLsizeiptr max_sprite_frames)
glBufferData (GL_ARRAY_BUFFER,
_vbo_max_elements * H3R_VERTEX_COMPONENTS * H3R_SPRITE_COMPONENT_SIZE,
nullptr, GL_STATIC_DRAW);
glVertexPointer (2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(0));

// As it happens this ain't a server state: you bind a VBO, you remind the
// server whats what.
/*glVertexPointer (2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(0));
glTexCoordPointer (
2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(2*sizeof(GLfloat)));
2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(2*sizeof(GLfloat)));*/
}

RenderEngine::~RenderEngine()
Expand All @@ -87,13 +90,29 @@ void RenderEngine::Render()
{
// glBindBuffer (GL_ARRAY_BUFFER, _vbo);
// glDrawArrays (GL_TRIANGLE_STRIP, 4, 4);

// sprite stage
glBindBuffer (GL_ARRAY_BUFFER, _vbo);
glVertexPointer (2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(0));
glTexCoordPointer (
2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(2*sizeof(GLfloat)));
for (size_t i = 0; i < _tex2_list.Count (); i++ ) {
glBindTexture (GL_TEXTURE_2D, _tex2_list[i].Texture);
glMultiDrawArrays (GL_TRIANGLE_STRIP,
_tex2_list[i]._index.begin (), _tex2_list[i]._count.begin (),
_tex2_list[i]._index.Count ());
}
}

// text stage
for (size_t i = 0; i < _texts.Count (); i++) {
glBindTexture (GL_TEXTURE_2D, _texts[i].Texture);
glBindBuffer (GL_ARRAY_BUFFER, _texts[i].Vbo);
glVertexPointer (2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(0));
glTexCoordPointer (
2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(2*sizeof(GLfloat)));
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
}
}// RenderEngine::Render()

int RenderEngine::GenKey()
{
Expand Down Expand Up @@ -214,4 +233,74 @@ void RenderEngine::ChangeOffset(int key, GLint value)
global_render_gl_init = true;
}

// -- Text -------------------------------------------------------------------

int RenderEngine::GenTextKey()
{
RenderEngine::TextEntry entry {};
_texts.Add (entry);
return _texts.Count () - 1;
}

// Slow and simple. Let me establish the most use-able protocol first. The game
// haven't even been started yet; no need to fine tune anything just yet. This
// is proof of concept code - wasting too much time with it is pointless.
void RenderEngine::UploadText(
int key, const String & font_name, const String & txt, int top, int left)
{
H3R_ENSURE(key >= 0 && key < (int)_texts.Count (), "Bug: wrong key")
int w, h;
byte * tb = TextRenderingEngine::One ().RenderText (font_name, txt, w, h);
int tw = Log2i (w), th = Log2i (h);
Array<byte> tex_buf {(size_t)tw*th*2};
Font::CopyRectangle (tex_buf, tw, 0, 0, tb, w, h);
// int b = t + h, r = l + w;
GLfloat t = top, l = left, b = t + h, r = l + w;
GLfloat u = 1.f * w / tw, v = 1.f * h / th;
RenderEngine::TextEntry & e = _texts[key];
if (e.InUse) {
glDeleteBuffers (1, &(e.Vbo));
glDeleteTextures (1, &(e.Texture));
}
else
e.InUse = true;
glGenTextures (1, &(e.Texture));
glBindTexture (GL_TEXTURE_2D, e.Texture);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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_MAX_LEVEL, 0);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, tw, th,
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, tex_buf.operator byte * ());
// same ordering and components as the big VBO (no point but consistency)
GLfloat vertices[16] {l,t,0,0, l,b,0,v, r,t,u,0, r,b,u,v};
glGenBuffers (1, &(e.Vbo));
glBindBuffer (GL_ARRAY_BUFFER, e.Vbo);
// Server state:
/*glVertexPointer (2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(0));
glTexCoordPointer (
2, GL_FLOAT, 4*sizeof(GLfloat), (void *)(2*sizeof(GLfloat)));*/
glBufferData (GL_ARRAY_BUFFER, 64, vertices, GL_STATIC_DRAW);
}

void RenderEngine::UpdateText(
int key, const String & font_name, const String & txt, int top, int left)
{
UploadText (key, font_name, txt, top, left);
}

void RenderEngine::ChangeTextVisibility(int key, bool state)
{
H3R_ENSURE(key >= 0 && key < (int)_texts.Count (), "Bug: wrong key")
_texts[key].Visible = state;
}

void RenderEngine::DeleteText(int key)
{
H3R_ENSURE(key >= 0 && key < (int)_texts.Count (), "Bug: wrong key")
_texts.RemoveAt (key);
}

NAMESPACE_H3R
23 changes: 23 additions & 0 deletions engines/render_gl/h3r_renderengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "h3r.h"
#include "h3r_list.h"
#include "h3r_array.h"
#include "h3r_string.h"
#include <GL/gl.h>

H3R_NAMESPACE
Expand Down Expand Up @@ -210,6 +211,28 @@ class RenderEngine final
public static RenderEngine & UI();

public static void Init();

// Text

// Each entry has its own texture and its own VBO; that should be fast
// enough for the simplicity.
private struct TextEntry
{
GLuint Texture {};//LATER Glyph cache; there are no more than 128 text
GLuint Vbo {}; // objs visible at once
bool Visible {true};
bool InUse {false};
};
List<TextEntry> _texts {};
public int GenTextKey();
// Layout it prior rendering. Everything TextRenderingEngine::RenderText()
// supports, is supported.
public void UploadText(int key,
const String & font_name, const String & txt, int top, int left);
public void UpdateText(int key,
const String & font_name, const String & txt, int top, int left);
public void ChangeTextVisibility(int key, bool state);
public void DeleteText(int key);
};

#undef public
Expand Down
2 changes: 2 additions & 0 deletions engines/render_gl/h3r_texcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ H3R_NAMESPACE
// ...
//
// TexCache::Bind (e)
//LATER is there a point creatinc a dynamic tex. atlas (to save resources)?
// Dynamic tex. atlas: resize the tex. atlas on an as needed basis.
class TexCache final
{
public struct Entry final
Expand Down
6 changes: 3 additions & 3 deletions game/h3r_gamefont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ H3R_NAMESPACE
GameFont::GameFont(const String & name)
: Font {name}, _fnt {Game::GetResource (name)}
{
if (_fnt) Log::Info (String::Format ("Font load: %s", name.AsZStr ()));
else Log::Err (String::Format ("Font load failed: %s", name.AsZStr ()));
if (_fnt) Log::Info (String::Format ("Font load: %s" EOL, name.AsZStr ()));
else Log::Err (String::Format ("Font load failed: %s" EOL, name.AsZStr ()));
}

Point GameFont::MeasureText(const String & text)
Expand Down Expand Up @@ -80,7 +80,7 @@ void GameFont::RenderText(const String & text, byte * buf, int w, int h)
for (size_t i = 0; i < text.Length (); i++) {
int gw = _fnt.GlyphWidth (txt[i]);
byte * glyph = _fnt.GlyphBitmap (txt[i]);
/*printf ("Glyph %3d:" EOL, txt[i]);
/*printf ("Glyph %3d:" EOL, txt[i]); TODO h3r_debug_helpers
for (int y = 0; y < gh; y++) {
for (int x = 0; x < gw; x++)
printf ("%3d ", glyph[y*gw+x]);
Expand Down

0 comments on commit 2728902

Please sign in to comment.