Allow multiple fonts
This commit is contained in:
@@ -16,6 +16,9 @@ struct Font {
|
||||
float ascent;
|
||||
float line_gap;
|
||||
|
||||
Int line_spacing;
|
||||
Int char_spacing;
|
||||
|
||||
Rect2 white_texture_bounding_box;
|
||||
};
|
||||
|
||||
@@ -92,6 +95,16 @@ Rect2 PackBitmap(Atlas *atlas, uint8_t *bitmap, int width, int height) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Glyph *GetGlyph(Font *font, uint32_t codepoint) {
|
||||
bool is_in_range = codepoint >= font->first_char && codepoint <= font->last_char;
|
||||
if (is_in_range) {
|
||||
uint32_t index = codepoint - font->first_char;
|
||||
return &font->glyphs[index];
|
||||
} else {
|
||||
uint32_t index = '?' - font->first_char;
|
||||
return &font->glyphs[index];
|
||||
}
|
||||
}
|
||||
Font CreateFont(Atlas *atlas, int32_t size, String path) {
|
||||
Allocator allocator = GetSystemAllocator();
|
||||
Scratch scratch;
|
||||
@@ -143,16 +156,9 @@ Font CreateFont(Atlas *atlas, int32_t size, String path) {
|
||||
Add(&result.glyphs, glyph);
|
||||
}
|
||||
|
||||
Glyph *g = GetGlyph(&result, '_');
|
||||
result.char_spacing = (Int)g->xadvance ? (Int)g->xadvance : (Int)g->size.x;
|
||||
result.line_spacing = (Int)(result.ascent - result.descent + result.line_gap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Glyph *GetGlyph(Font *font, uint32_t codepoint) {
|
||||
bool is_in_range = codepoint >= font->first_char && codepoint <= font->last_char;
|
||||
if (is_in_range) {
|
||||
uint32_t index = codepoint - font->first_char;
|
||||
return &font->glyphs[index];
|
||||
} else {
|
||||
uint32_t index = '?' - font->first_char;
|
||||
return &font->glyphs[index];
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,8 @@ Shader Shader2D;
|
||||
BlockArena RenderArena;
|
||||
Rect2 CurrentScissor;
|
||||
|
||||
Font MainFont;
|
||||
Int FontLineSpacing;
|
||||
Int FontCharSpacing;
|
||||
Font PrimaryFont;
|
||||
Font SecondaryFont;
|
||||
|
||||
// ---------- shaders (ES3 / WebGL2) ----------
|
||||
static const char *glsl_vshader_es3 = R"==(#version 300 es
|
||||
@@ -227,7 +226,7 @@ void EndFrameRender(float wx, float wy, Color color) {
|
||||
|
||||
// bind texture unit 0 and the font texture
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, MainFont.texture_id);
|
||||
glBindTexture(GL_TEXTURE_2D, PrimaryFont.texture_id);
|
||||
|
||||
// draw
|
||||
glDrawArrays(GL_TRIANGLES, 0, it->count);
|
||||
@@ -308,10 +307,10 @@ void PushQuad2D(Allocator arena, VertexList2D *list, Rect2 rect, Rect2 tex, Colo
|
||||
}
|
||||
|
||||
void DrawRect(Rect2 rect, Color color) {
|
||||
PushQuad2D(RenderArena, &Vertices, rect, MainFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, rect, PrimaryFont.white_texture_bounding_box, color);
|
||||
}
|
||||
void DrawRect(Rect2I rect, Color color) {
|
||||
PushQuad2D(RenderArena, &Vertices, ToRect2(rect), MainFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, ToRect2(rect), PrimaryFont.white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
void DrawRectOutline(Rect2 rect, Color color, float thickness = 2) {
|
||||
@@ -319,29 +318,18 @@ void DrawRectOutline(Rect2 rect, Color color, float thickness = 2) {
|
||||
Rect2 b = CutRight(&rect, thickness);
|
||||
Rect2 c = CutTop(&rect, thickness);
|
||||
Rect2 d = CutBottom(&rect, thickness);
|
||||
PushQuad2D(RenderArena, &Vertices, a, MainFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, b, MainFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, c, MainFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, d, MainFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, a, PrimaryFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, b, PrimaryFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, c, PrimaryFont.white_texture_bounding_box, color);
|
||||
PushQuad2D(RenderArena, &Vertices, d, PrimaryFont.white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
void DrawRectOutline(Rect2I rect, Color color, Int thickness = 2) {
|
||||
DrawRectOutline(ToRect2(rect), color, (float)thickness);
|
||||
}
|
||||
|
||||
Int GetCharSpacing(Font *font, int codepoint = '_') {
|
||||
Glyph *g = GetGlyph(font, codepoint);
|
||||
if (g->xadvance) return (Int)g->xadvance;
|
||||
return (Int)g->size.x;
|
||||
}
|
||||
|
||||
Int GetLineSpacing(Font *font) {
|
||||
Int result = (Int)(font->ascent - font->descent + font->line_gap);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2 DrawString(Font *font, String16 string, Vec2 pos, Color color, bool draw = true) {
|
||||
pos.y += GetLineSpacing(font) + font->descent;
|
||||
pos.y += font->line_spacing + font->descent; // TODO: descent?
|
||||
Vec2 original_pos = pos;
|
||||
For(string) {
|
||||
Glyph *g = GetGlyph(font, it);
|
||||
@@ -371,7 +359,7 @@ void DrawCircle(Vec2 pos, float radius, Color color) {
|
||||
int point_i = 0;
|
||||
int segment_i = 0;
|
||||
for (; segment_i < vertex_count; segment_i += 3, point_i += 1) {
|
||||
Rect2 tex = MainFont.white_texture_bounding_box;
|
||||
Rect2 tex = PrimaryFont.white_texture_bounding_box;
|
||||
Vertex2D *it = vertices + segment_i;
|
||||
it[0].color = color;
|
||||
it[1].color = color;
|
||||
@@ -386,35 +374,30 @@ void DrawCircle(Vec2 pos, float radius, Color color) {
|
||||
}
|
||||
}
|
||||
|
||||
GLuint UploadAtlas(Atlas *atlas) {
|
||||
GLuint tex = 0;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, (GLsizei)atlas->size.x, (GLsizei)atlas->size.y, 0, GL_RED, GL_UNSIGNED_BYTE, atlas->bitmap);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
atlas->texture_id = tex;
|
||||
return tex;
|
||||
}
|
||||
|
||||
void ReloadFont() {
|
||||
Int size = StyleFontSize;
|
||||
size = ClampBottom((Int)2, size);
|
||||
if (MainFont.texture_id) {
|
||||
glDeleteTextures(1, &MainFont.texture_id);
|
||||
Dealloc(&MainFont.glyphs);
|
||||
MainFont = {};
|
||||
if (PrimaryFont.texture_id) {
|
||||
glDeleteTextures(1, &PrimaryFont.texture_id);
|
||||
Dealloc(&PrimaryFont.glyphs);
|
||||
PrimaryFont = {};
|
||||
}
|
||||
|
||||
Scratch scratch;
|
||||
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
|
||||
MainFont = CreateFont(&atlas, (uint32_t)size, StyleFont);
|
||||
|
||||
// create and fill texture with ES3-compatible API
|
||||
GLint filter = GL_NEAREST;
|
||||
if (StyleFontFilter == 1) filter = GL_LINEAR;
|
||||
|
||||
GLuint tex = 0;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
// allocate storage and upload
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, (GLsizei)atlas.size.x, (GLsizei)atlas.size.y, 0, GL_RED, GL_UNSIGNED_BYTE, atlas.bitmap);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
MainFont.texture_id = tex;
|
||||
FontCharSpacing = GetCharSpacing(&MainFont);
|
||||
FontLineSpacing = GetLineSpacing(&MainFont);
|
||||
PrimaryFont = CreateFont(&atlas, (uint32_t)ClampBottom(2u, (U32)StyleFontSize), StyleFont);
|
||||
SecondaryFont = CreateFont(&atlas, 10, StyleFont);
|
||||
SecondaryFont.texture_id = PrimaryFont.texture_id = UploadAtlas(&atlas);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user