From 16c012362709813fdbfbd7aa23924389e2d8a9d8 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 19 Mar 2026 22:36:16 -0500 Subject: [PATCH] outline font --- Makefile | 3 +- font/{ => bitmap}/terminus_128x128_8x16.data | Bin font/{ => bitmap}/terminus_128x64_6x12.data | Bin font/{ => bitmap}/terminus_256x128_10x18.data | Bin font/{ => bitmap}/terminus_256x128_12x24.data | Bin font/{ => bitmap}/terminus_256x256_16x32.data | Bin font/outline/uncial_antiqua_36.data | Bin 0 -> 67484 bytes include/{font.h => font/bitmap.h} | 13 +- include/font/outline.h | 29 ++++ include/font/outline_types.h | 49 ++++++ shader/font.vert | 22 +-- shader/font_outline.frag | 17 ++ src/{font.cpp => font/bitmap.cpp} | 6 +- src/font/outline.cpp | 150 ++++++++++++++++++ src/hud.cpp | 57 +++---- src/lua_api.cpp | 14 +- src/test.cpp | 21 ++- 17 files changed, 306 insertions(+), 75 deletions(-) rename font/{ => bitmap}/terminus_128x128_8x16.data (100%) rename font/{ => bitmap}/terminus_128x64_6x12.data (100%) rename font/{ => bitmap}/terminus_256x128_10x18.data (100%) rename font/{ => bitmap}/terminus_256x128_12x24.data (100%) rename font/{ => bitmap}/terminus_256x256_16x32.data (100%) create mode 100644 font/outline/uncial_antiqua_36.data rename include/{font.h => font/bitmap.h} (81%) create mode 100644 include/font/outline.h create mode 100644 include/font/outline_types.h create mode 100644 shader/font_outline.frag rename src/{font.cpp => font/bitmap.cpp} (97%) create mode 100644 src/font/outline.cpp diff --git a/Makefile b/Makefile index bdb08ab..8e352cd 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ OBJS = \ src/gl.o \ src/opengl.o \ src/test.o \ - src/font.o \ + src/font/bitmap.o \ + src/font/outline.o \ src/window.o \ src/bresenham.o \ src/file.o \ diff --git a/font/terminus_128x128_8x16.data b/font/bitmap/terminus_128x128_8x16.data similarity index 100% rename from font/terminus_128x128_8x16.data rename to font/bitmap/terminus_128x128_8x16.data diff --git a/font/terminus_128x64_6x12.data b/font/bitmap/terminus_128x64_6x12.data similarity index 100% rename from font/terminus_128x64_6x12.data rename to font/bitmap/terminus_128x64_6x12.data diff --git a/font/terminus_256x128_10x18.data b/font/bitmap/terminus_256x128_10x18.data similarity index 100% rename from font/terminus_256x128_10x18.data rename to font/bitmap/terminus_256x128_10x18.data diff --git a/font/terminus_256x128_12x24.data b/font/bitmap/terminus_256x128_12x24.data similarity index 100% rename from font/terminus_256x128_12x24.data rename to font/bitmap/terminus_256x128_12x24.data diff --git a/font/terminus_256x256_16x32.data b/font/bitmap/terminus_256x256_16x32.data similarity index 100% rename from font/terminus_256x256_16x32.data rename to font/bitmap/terminus_256x256_16x32.data diff --git a/font/outline/uncial_antiqua_36.data b/font/outline/uncial_antiqua_36.data new file mode 100644 index 0000000000000000000000000000000000000000..90e468ec7191858217d774d08728957ce4cf178e GIT binary patch literal 67484 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 Njq?7lsCrD4{67;E(d7UD literal 0 HcmV?d00001 diff --git a/include/font.h b/include/font/bitmap.h similarity index 81% rename from include/font.h rename to include/font/bitmap.h index 3b8b649..c7dc9fc 100644 --- a/include/font.h +++ b/include/font/bitmap.h @@ -1,6 +1,6 @@ #pragma once -namespace font { +namespace font::bitmap { struct font_desc { char const * const path; @@ -12,35 +12,35 @@ namespace font { font_desc const terminus[] = { { - .path = "font/terminus_128x64_6x12.data", + .path = "font/bitmap/terminus_128x64_6x12.data", .texture_width = 128, .texture_height = 64, .glyph_width = 6, .glyph_height = 12, }, { - .path = "font/terminus_128x128_8x16.data", + .path = "font/bitmap/terminus_128x128_8x16.data", .texture_width = 128, .texture_height = 128, .glyph_width = 8, .glyph_height = 16, }, { - .path = "font/terminus_256x128_10x18.data", + .path = "font/bitmap/terminus_256x128_10x18.data", .texture_width = 256, .texture_height = 128, .glyph_width = 10, .glyph_height = 18, }, { - .path = "font/terminus_256x128_12x24.data", + .path = "font/bitmap/terminus_256x128_12x24.data", .texture_width = 256, .texture_height = 128, .glyph_width = 12, .glyph_height = 24, }, { - .path = "font/terminus_256x256_16x32.data", + .path = "font/bitmap/terminus_256x256_16x32.data", .texture_width = 256, .texture_height = 256, .glyph_width = 16, @@ -60,7 +60,6 @@ namespace font { }; void load_shader(); - font load_font(font_desc const& desc); void load_fonts(font * const fonts, font_desc const * const descs, int length); int best_font(font_desc const * const descs, int length); void draw_start(font const& font, unsigned int vertex_array_object, unsigned int index_buffer); diff --git a/include/font/outline.h b/include/font/outline.h new file mode 100644 index 0000000..6036795 --- /dev/null +++ b/include/font/outline.h @@ -0,0 +1,29 @@ +#pragma once + +#include "outline_types.h" + +namespace font::outline { + + struct font_desc { + char const * const path; + }; + + font_desc const uncial_antiqua[] = { + { + .path = "font/outline/uncial_antiqua_36.data", + }, + }; + int const uncial_antiqua_length = (sizeof (uncial_antiqua)) / (sizeof (font_desc)); + + struct font { + unsigned int texture; + types::font const * font; + types::glyph const * glyphs; + }; + + void load_shader(); + void load_fonts(font * const fonts, font_desc const * const descs, int length); + + void draw_start(font const& font, unsigned int vertex_array_object, unsigned int index_buffer); + int draw_string(font const& font, char const * const s, int x, int y); +} diff --git a/include/font/outline_types.h b/include/font/outline_types.h new file mode 100644 index 0000000..2ef4930 --- /dev/null +++ b/include/font/outline_types.h @@ -0,0 +1,49 @@ +// this file is designed to be platform-agnostic +#pragma once + +#include + +namespace font::outline::types { + + // metrics are 26.6 fixed point + struct glyph_metrics { + int32_t horiBearingX; + int32_t horiBearingY; + int32_t horiAdvance; + } __attribute__ ((packed)); + + static_assert((sizeof (struct glyph_metrics)) == ((sizeof (int32_t)) * 3)); + + struct glyph_bitmap { + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + } __attribute__ ((packed)); + + static_assert((sizeof (struct glyph_bitmap)) == ((sizeof (uint16_t)) * 4)); + + struct glyph { + struct glyph_bitmap bitmap; + struct glyph_metrics metrics; + } __attribute__ ((packed)); + + static_assert((sizeof (struct glyph)) == ((sizeof (struct glyph_bitmap)) + (sizeof (struct glyph_metrics)))); + + struct font { + uint32_t first_char_code; + uint32_t last_char_code; + struct face_metrics { + int32_t height; // 26.6 fixed point + int32_t max_advance; // 26.6 fixed point + } face_metrics; + uint16_t glyph_count; + uint16_t _texture_stride; + uint16_t texture_width; + uint16_t texture_height; + uint32_t max_z_curve_ix; + } __attribute__ ((packed)); + + static_assert((sizeof (struct font)) == ((sizeof (uint32_t)) * 7)); + +} diff --git a/shader/font.vert b/shader/font.vert index 3b8b299..9883da5 100644 --- a/shader/font.vert +++ b/shader/font.vert @@ -1,29 +1,11 @@ -#version 330 core +#version 430 core const vec2 vtx[4] = vec2[](vec2(-1.0, 1.0), // tl vec2( 1.0, 1.0), // tr vec2( 1.0, -1.0), // br vec2(-1.0, -1.0)); // bl -/* -tl tr - br - -0 1 2 -tr tl br -1 0 2 - -tl -bl br - -2 1 3 -br tl bl -2 0 3 - -1 0 2 3 -*/ - -uniform mat4 Transform; +layout (location = 0) uniform mat4 Transform; out vec4 PixelTexture; diff --git a/shader/font_outline.frag b/shader/font_outline.frag new file mode 100644 index 0000000..27a3e74 --- /dev/null +++ b/shader/font_outline.frag @@ -0,0 +1,17 @@ +#version 430 core + +layout (location = 1) uniform vec2 TextureSize; +layout (location = 2) uniform vec4 WidthHeightXY; + +layout (location = 3, binding = 0) uniform sampler2D TextureSampler; + +out vec4 g_color; + +in vec4 PixelTexture; + +void main() +{ + vec2 coord = (PixelTexture.xy * WidthHeightXY.xy + WidthHeightXY.zw) * TextureSize; + vec4 color = texture(TextureSampler, coord); + g_color = vec4(color.x); +} diff --git a/src/font.cpp b/src/font/bitmap.cpp similarity index 97% rename from src/font.cpp rename to src/font/bitmap.cpp index cc215b7..541f2dc 100644 --- a/src/font.cpp +++ b/src/font/bitmap.cpp @@ -7,10 +7,10 @@ #include "opengl.h" #include "file.h" -#include "font.h" +#include "font/bitmap.h" #include "window.h" -namespace font { +namespace font::bitmap { struct location { struct { @@ -46,7 +46,7 @@ namespace font { font_program = program; } - font load_font(font_desc const& desc) + static inline font load_font(font_desc const& desc) { unsigned int texture; glGenTextures(1, &texture); diff --git a/src/font/outline.cpp b/src/font/outline.cpp new file mode 100644 index 0000000..374b8dc --- /dev/null +++ b/src/font/outline.cpp @@ -0,0 +1,150 @@ +#include +#include +#include + +#include "directxmath/directxmath.h" +#include "glad/gl.h" +#include "opengl.h" +#include "file.h" + +#include "font/outline.h" +#include "font/outline_types.h" +#include "window.h" + +namespace font::outline { + + struct layout { + struct { + unsigned int transform; + unsigned int texture_size; + unsigned int width_height_xy; + unsigned int texture_sampler; + } uniform; + }; + + static layout const layout = { + .uniform = { + .transform = 0, + .texture_size = 1, + .width_height_xy = 2, + .texture_sampler = 3, + } + }; + + static unsigned int font_program = -1; + + void load_shader() + { + unsigned int program = compile_from_files("shader/font.vert", + NULL, // geom + "shader/font_outline.frag"); + + font_program = program; + } + + static inline font load_font(font_desc const& desc) + { + int font_data_size; + void * font_data = read_file(desc.path, &font_data_size); + assert(font_data != nullptr); + + types::font * font = (types::font *)font_data; + types::glyph * glyphs = (types::glyph *)(((ptrdiff_t)font_data) + (sizeof (types::font))); + + void * texture_data = (void *)(((ptrdiff_t)glyphs) + (sizeof (types::glyph)) * font->glyph_count); + + ptrdiff_t font_end = ((ptrdiff_t)font_data) + font_data_size; + int texture_size = font->texture_width * font->texture_height; + assert(font_end - ((ptrdiff_t)texture_data) == texture_size); + + unsigned int texture; + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + 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); + + int width = font->texture_width; + int height = font->texture_height; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, texture_data); + + glBindTexture(GL_TEXTURE_2D, 0); + + return (outline::font){ + .texture = texture, + .font = font, + .glyphs = glyphs, + }; + } + + void load_fonts(font * const fonts, font_desc const * const descs, int length) + { + for (int i = 0; i < length; i++) { + fonts[i] = load_font(descs[i]); + } + } + + void draw_start(font const& font, unsigned int vertex_array_object, unsigned int index_buffer) + { + glUseProgram(font_program); + glDepthFunc(GL_ALWAYS); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, font.texture); + + glBindVertexArray(vertex_array_object); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + + XMFLOAT2 texture_size = {1.0f / font.font->texture_width, 1.0f / font.font->texture_height}; + glUniform2fv(layout.uniform.texture_size, 1, (float *)&texture_size); + } + + inline static XMFLOAT4X4 glyph_transform(float width, float height, float x, float y) + { + XMMATRIX transform + = XMMatrixScaling(width, height, 0) + * XMMatrixTranslation(x, -y, 0) + * XMMatrixScaling(2.0f / window::width, 2.0f / window::height, 0) + * XMMatrixTranslation(-1, 1, 0); + XMFLOAT4X4 transformf; + XMStoreFloat4x4(&transformf, transform); + return transformf; + } + + int draw_string(font const& font, char const * const s, int x, int y) + { + int advance = 0; + const float fp = 1.0f / 64.0f; + + int i = 0; + while (s[i] != 0) { + char c = s[i++]; + + if (!(c >= 0x20 && c <= 0x7f)) + continue; + + types::glyph const & glyph = font.glyphs[c - 0x20]; + + if (c > 0x20 && c <= 0x7f) { + XMFLOAT4 width_height_xy = { + (float)glyph.bitmap.width, (float)glyph.bitmap.height, + (float)glyph.bitmap.x, (float)glyph.bitmap.y, + }; + XMFLOAT4X4 transform = glyph_transform(glyph.bitmap.width, glyph.bitmap.height, + x + ((float)(advance + glyph.metrics.horiBearingX) * fp), + y - ((float)(glyph.metrics.horiBearingY) * fp)); + + glUniform4fv(layout.uniform.width_height_xy, 1, (float *)&width_height_xy); + glUniformMatrix4fv(layout.uniform.transform, 1, GL_FALSE, (float *)&transform); + + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0); + } + + advance += glyph.metrics.horiAdvance; + } + + return x + (advance >> 6); + } +} diff --git a/src/hud.cpp b/src/hud.cpp index 8db6edc..a589ac7 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -3,19 +3,18 @@ #include "directxmath/directxmath.h" -#include "font.h" +#include "font/bitmap.h" #include "view.h" -extern font::font * terminus_fonts; +extern font::bitmap::font * terminus_fonts; extern unsigned int empty_vertex_array_object; extern unsigned int quad_index_buffer; extern float current_time; extern float last_frame_time; - // depends on: -// - font::load +// - font::bitmap::load // - load_quad_program // - load_quad_index_buffer // - empty_vertex_array_object @@ -34,10 +33,10 @@ namespace hud { buf[label_length + len] = 0; } - inline static float draw_vector(font::font const& ter_best, char * const buf, float y, char const * const label, XMVECTOR vec) + inline static float draw_vector(font::bitmap::font const& ter_best, char * const buf, float y, char const * const label, XMVECTOR vec) { labeled_value(buf, label, ": %5.2f %5.2f %5.2f %5.2f", XMVectorGetX(vec), XMVectorGetY(vec), XMVectorGetZ(vec), XMVectorGetW(vec)); - font::draw_string(ter_best, buf, 10, y); + font::bitmap::draw_string(ter_best, buf, 10, y); y += ter_best.desc->glyph_height; return y; } @@ -73,48 +72,42 @@ namespace hud { return rolling_sum * (1.0f / 16.0f); } + template + static float draw_label(font::bitmap::font const& font, char * buf, float x, float y, char const * const label, char const * const format, Args... args) + { + labeled_value(buf, label, format, args...); + font::bitmap::draw_string(font, buf, x, y); + return y + font.desc->glyph_height; + } + void draw() { - char buf[512]; + static char buf[512]; float y = 10.0f; - int font_ix = font::best_font(font::terminus, font::terminus_length); - font::font const& ter_best = terminus_fonts[font_ix]; - font::draw_start(ter_best, empty_vertex_array_object, quad_index_buffer); + int font_ix = font::bitmap::best_font(font::bitmap::terminus, font::bitmap::terminus_length); + font::bitmap::font const& ter_best = terminus_fonts[font_ix]; + font::bitmap::draw_start(ter_best, empty_vertex_array_object, quad_index_buffer); - labeled_value(buf, "fov: ", "%.3f", view::state.fov); - font::draw_string(ter_best, buf, 10, y); - y += ter_best.desc->glyph_height; - - labeled_value(buf, "font_height: ", "%d", ter_best.desc->glyph_height); - font::draw_string(ter_best, buf, 10, y); - y += ter_best.desc->glyph_height; + y = draw_label(ter_best, buf, 10, y, "fov: ", "%.3f", view::state.fov); + y = draw_label(ter_best, buf, 10, y, "font_height: ", "%d", ter_best.desc->glyph_height); /* - labeled_value(buf, "lighting.quadratic: ", "%.2f", lighting.quadratic); - font::draw_string(ter_best, buf, 10, y); - y += ter_best.desc->glyph_height; - - labeled_value(buf, "lighting.linear: ", "%.2f", lighting.linear); - font::draw_string(ter_best, buf, 10, y); - y += ter_best.desc->glyph_height; + y = draw_label(ter_best, buf, 10, y, "lighting.quadratic: ", "%.2f", lighting.quadratic); + y = draw_label(ter_best, buf, 10, y, "lighting.linear: ", "%.2f", lighting.linear); */ y = draw_vector(ter_best, buf, y, "eye", XMVectorSetW(view::state.eye, 0)); y = draw_vector(ter_best, buf, y, "at", XMVectorSetW(view::state.at, 0)); y = draw_vector(ter_best, buf, y, "forward", XMVectorSetW(view::state.forward, 0)); - labeled_value(buf, "pitch: ", "%.4f", view::state.pitch); - font::draw_string(ter_best, buf, 10, y); + y = draw_label(ter_best, buf, 10, y, "pitch: ", "%.4f", view::state.pitch); + y = draw_label(ter_best, buf, 10, y, "frame_rate_avg: ", "%.2f", 1.0f / update_average(current_time - last_frame_time)); + + font::bitmap::draw_string(ter_best, "mouse:", 10, y); y += ter_best.desc->glyph_height; - labeled_value(buf, "frame_rate_avg: ", "%.2f", 1.0f / update_average(current_time - last_frame_time)); - font::draw_string(ter_best, buf, 10, y); - y += ter_best.desc->glyph_height; - - font::draw_string(ter_best, "mouse:", 10, y); - y += ter_best.desc->glyph_height; y = draw_vector(ter_best, buf, y, " position", XMLoadFloat4((XMFLOAT4*)mouse_position)); y = draw_vector(ter_best, buf, y, " block", XMLoadFloat4((XMFLOAT4*)mouse_block)); } diff --git a/src/lua_api.cpp b/src/lua_api.cpp index ea5cc67..aa891a2 100644 --- a/src/lua_api.cpp +++ b/src/lua_api.cpp @@ -1,24 +1,24 @@ -#include "font.h" +#include "font/bitmap.h" #include "pixel_line_art.h" #include "lua_api.h" -extern font::font * terminus_fonts; +extern font::bitmap::font * terminus_fonts; extern unsigned int empty_vertex_array_object; extern unsigned int quad_index_buffer; int draw_font_start() { - int font_ix = font::best_font(font::terminus, font::terminus_length); - font::font const& ter_best = terminus_fonts[font_ix]; - font::draw_start(ter_best, empty_vertex_array_object, quad_index_buffer); + int font_ix = font::bitmap::best_font(font::bitmap::terminus, font::bitmap::terminus_length); + font::bitmap::font const& ter_best = terminus_fonts[font_ix]; + font::bitmap::draw_start(ter_best, empty_vertex_array_object, quad_index_buffer); return font_ix; } int draw_font(int font_ix, char const * text, int x, int y) { - font::font const& ter_best = terminus_fonts[font_ix]; - font::draw_string(ter_best, text, x, y); + font::bitmap::font const& ter_best = terminus_fonts[font_ix]; + font::bitmap::draw_string(ter_best, text, x, y); return ter_best.desc->glyph_height; } diff --git a/src/test.cpp b/src/test.cpp index 68f08b4..92337c3 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -7,7 +7,8 @@ #include "opengl.h" #include "directxmath/directxmath.h" #include "test.h" -#include "font.h" +#include "font/bitmap.h" +#include "font/outline.h" #include "window.h" #include "bresenham.h" #include "file.h" @@ -26,6 +27,7 @@ #include "collada/instance_types.h" #include "pixel_line_art.h" #include "flame.h" +#include "new.h" #include "world/entry_table.h" #include "world/world.h" @@ -67,7 +69,8 @@ unsigned int quad_index_buffer = -1; float current_time; float last_frame_time; -font::font * terminus_fonts; +font::bitmap::font * terminus_fonts; +font::outline::font * uncial_antiqua_fonts; geometry_buffer<4> geometry_buffer_pnc = {}; static target_type const geometry_buffer_pnc_types[4] = { @@ -142,10 +145,13 @@ void load(const char * source_path) // font ////////////////////////////////////////////////////////////////////// - font::load_shader(); + font::bitmap::load_shader(); + terminus_fonts = New(font::bitmap::terminus_length); + font::bitmap::load_fonts(terminus_fonts, font::bitmap::terminus, font::bitmap::terminus_length); - terminus_fonts = (font::font *)malloc((sizeof (font::font)) * font::terminus_length); - font::load_fonts(terminus_fonts, font::terminus, font::terminus_length); + font::outline::load_shader(); + uncial_antiqua_fonts = New(font::outline::uncial_antiqua_length); + font::outline::load_fonts(uncial_antiqua_fonts, font::outline::uncial_antiqua, font::outline::uncial_antiqua_length); ////////////////////////////////////////////////////////////////////// // pixel_line_art @@ -439,6 +445,11 @@ void draw() minecraft::current_world->light_count); //draw_quad(); hud::draw(); + + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //font::outline::draw_start(uncial_antiqua_fonts[0], empty_vertex_array_object, quad_index_buffer); + //font::outline::draw_string(uncial_antiqua_fonts[0], "test", 150, 500); + } else { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);