slightly better font rendering; using 'em' units
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 9 May 2021 03:57:14 +0000 (22:57 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 9 May 2021 03:57:14 +0000 (22:57 -0500)
build.bat [new file with mode: 0644]
src/font/bitmap_font.onyx
src/res/font.data
src/res/font_2.data [new file with mode: 0644]
src/tower.onyx

diff --git a/build.bat b/build.bat
new file mode 100644 (file)
index 0000000..c70f55d
--- /dev/null
+++ b/build.bat
@@ -0,0 +1,10 @@
+@echo off
+
+set TARGET=site\tower.wasm
+set ONYX_INSTALLATION_FOLDER=\dev\onyx
+
+copy "%ONYX_INSTALLATION_FOLDER%\bin\onyx-loader.js" .\site\js\onyx-loader.js  >NUL
+copy "%ONYX_INSTALLATION_FOLDER%\modules\webgl2\webgl2.js" .\site\js\webgl2.js >NUL
+copy "%ONYX_INSTALLATION_FOLDER%\modules\js_events\js_events.js" .\site\js\js_events.js >NUL
+
+\dev\onyx\onyx -r js --use-post-mvp-features -V -o %TARGET% src\build.onyx -I %ONYX_INSTALLATION_FOLDER%
index 1ec0cb5a3ebddf5da2ace336ba5f9d65319d6d71..88078626836a3d7a29150d8175914346666a3c33 100644 (file)
@@ -30,10 +30,13 @@ use package core
 Bitmap_Font :: struct {
     font_texture : Bitmap_Font_Texture;
 
+    em: f32; // Width of 'M'
+
     glyphs : map.Map(u32, Glyph);
 
     Glyph :: struct {
         x0, y0, x1, y1: f32;
+        w, h: f32;
     }
 
     get_glyph :: (use bmp: ^Bitmap_Font, char: u8) -> ^Glyph {
@@ -49,10 +52,15 @@ Bitmap_Font_Texture :: struct {
 
     // NOTE: Assumes pixels are laid out in RGBA format.
     get_pixel :: (use texture: ^Bitmap_Font_Texture, x: u32, y: u32) -> u32 {
-        return (cast(u32) data[(y * width + x) * Components_Per_Pixel + 0] << 24)
-             | (cast(u32) data[(y * width + x) * Components_Per_Pixel + 1] << 16)
-             | (cast(u32) data[(y * width + x) * Components_Per_Pixel + 2] << 8)
-             | (cast(u32) data[(y * width + x) * Components_Per_Pixel + 3] << 0);
+        return (cast(^u32) data.data)[y * width + x];
+
+        // SPEED: All of these values could be read simultaneously by treating the data
+        // array as a slice of u32, and then not multiplying by Components_Per_Pixel.
+        //
+        // return (cast(u32) data[(y * width + x) * Components_Per_Pixel + 0] << 24)
+        //      | (cast(u32) data[(y * width + x) * Components_Per_Pixel + 1] << 16)
+        //      | (cast(u32) data[(y * width + x) * Components_Per_Pixel + 2] << 8)
+        //      | (cast(u32) data[(y * width + x) * Components_Per_Pixel + 3] << 0);
     }
 }
 
@@ -66,7 +74,7 @@ bitmap_font_create :: (bft: Bitmap_Font_Texture, glyph_str: str) -> Bitmap_Font
 
     bmp: Bitmap_Font;
     bmp.font_texture = bft;
-    map.init(^bmp.glyphs, .{0,0,0,0});
+    map.init(^bmp.glyphs, .{0,0,0,0,0,0});
 
     success := bitmap_font_prepare_glyphs(^bmp, glyph_str);
     assert(success, "Failed to load glyphs out of font.");
@@ -81,6 +89,8 @@ bitmap_font_prepare_glyphs :: (use bmp: ^Bitmap_Font, glyph_str: str) -> bool {
     g_x0, g_y0 = 0, 0;
 
     for glyph_char: glyph_str {
+        if g_y0 >= font_texture.height do return false;
+
         // These will need to be converted to floating point when they are inserted into the glyph,
         // but it is easier to think about them as actual pixel coordinates when parsing the glyphs.
         x0, y0, x1, y1: u32;
@@ -95,6 +105,8 @@ bitmap_font_prepare_glyphs :: (use bmp: ^Bitmap_Font, glyph_str: str) -> bool {
             y0 = cast(f32) y0 / ~~font_texture.height,
             x1 = cast(f32) x1 / ~~font_texture.width,
             y1 = cast(f32) y1 / ~~font_texture.height,
+            w  = cast(f32) (x1 - x0) / ~~font_texture.width,
+            h  = cast(f32) (y1 - y0) / ~~font_texture.height,
         });
 
         g_x0 = x1 + 1;
@@ -107,5 +119,13 @@ bitmap_font_prepare_glyphs :: (use bmp: ^Bitmap_Font, glyph_str: str) -> bool {
         }
     }
 
+    M_glyph := map.get_ptr(^glyphs, #char "M");
+    if M_glyph != null {
+        em = M_glyph.w * ~~font_texture.width;
+    } else {
+        // ROBUSTNESS: If there is no 'M' in the character set, then just use 16. It will probably be very wrong.
+        em = 16;
+    }
+
     return true;
 }
index 96b8ec4c06cf978b1e45ef5306f0df325b39fab2..615eafbd72191e1cd88f15011f1f4289b42345c3 100644 (file)
Binary files a/src/res/font.data and b/src/res/font.data differ
diff --git a/src/res/font_2.data b/src/res/font_2.data
new file mode 100644 (file)
index 0000000..85287d4
Binary files /dev/null and b/src/res/font_2.data differ
index 35d0bd3abdac3a024a2a282839745c2a31d45107..47a97a4b6b888a6b13149e3cd3eb779fae31aecd 100644 (file)
@@ -19,12 +19,15 @@ main :: (args: [] cstr) {
 
     init_font();
 
+    gl.enable(gl.BLEND);
+    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
     start_loop :: () -> void #foreign "game" "start_loop" ---
     start_loop();
 }
 
 init_font :: () {
-    font_data := #file_contents "src/res/font.data";
+    font_data := #file_contents "src/res/font_2.data";
 
     bft := bitmap_font.Bitmap_Font_Texture.{
         data = font_data,
@@ -32,7 +35,7 @@ init_font :: () {
         height = 256,
     };
 
-    font = bitmap_font.bitmap_font_create(bft, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \xff");
+    font = bitmap_font.bitmap_font_create(bft, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \xff:");
 
     font_texture = gl.createTexture();
     gl.bindTexture(gl.TEXTURE_2D, font_texture);
@@ -73,21 +76,37 @@ poll_events :: () {
 
             gl.setSize(event.resize.width, event.resize.height);
             gl.viewport(0, 0, event.resize.width, event.resize.height);
+            gfx.use_ortho_projection(0, ~~window_width, 0, ~~window_height);
         }
     }
 }
 
+fps := 0;
+fps_timer := 1.0f;
+frames := 0
 update :: (dt: f32) {
+    fps_timer -= dt;
+    frames += 1;
+    if fps_timer < 0 {
+        fps = frames;
+        frames = 0;
+        fps_timer = 1.0f;
+    }
 }
 
 draw :: () {
     gl.clearColor(0.1, 0.1, 0.1, 1);
     gl.clear(gl.COLOR_BUFFER_BIT);
 
-    gfx.use_ortho_projection(0, ~~window_width, 0, ~~window_height);
+    fps_buffer : [16] u8;
+    fps_str := conv.str_format("FPS: %i", ~~ fps_buffer, fps);
+    draw_text(fps_str, 0, 0, 32, .{0,1,0});
 
     draw_text("Hello World", 100, 100, 128);
-    draw_text("something else...", 100, 230, 32);
+    draw_text("something else...", 100, 230, 32, .{1,0,0});
+
+    draw_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 100, 300, 16);
+    draw_text("abcdefghijklmnopqrstuvwxyz", 100, 340, 16);
 
     gfx.flush();
 }
@@ -96,11 +115,10 @@ draw :: () {
 
 
 
-draw_text :: (text: str, x: f32, y: f32, size := 32.0f) {
+draw_text :: (text: str, x: f32, y: f32, size := 32.0f, color := gfx.Color4.{1,1,1}) {
 
     gl.bindTexture(gl.TEXTURE_2D, font_texture);
     gfx.set_texture(0);
-    gfx.use_ortho_projection(0, ~~window_width, 0, ~~window_height);
 
     for char: text {
         glyph := font->get_glyph(char);
@@ -110,13 +128,14 @@ draw_text :: (text: str, x: f32, y: f32, size := 32.0f) {
             assert(glyph != null, "NO NULL GLYPH");
         }
 
-        gfx.textured_quad(
+        gfx.textured_rect(
             .{ x, y },
-            .{ size, size },
+            .{ glyph.w * size * font.em, glyph.h * size * font.em },
             .{ glyph.x0, glyph.y0 },
-            .{ glyph.x1 - glyph.x0, glyph.y1 - glyph.y0 });
+            .{ glyph.x1 - glyph.x0, glyph.y1 - glyph.y0 },
+            color = color);
 
-        x += size;
+        x += glyph.w * size * 16;
     }
     
     gfx.flush();