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 0000000..90e468e Binary files /dev/null and b/font/outline/uncial_antiqua_36.data differ 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);