switched to new font system (bmfont)
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 9 Jun 2021 19:34:45 +0000 (14:34 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 9 Jun 2021 19:34:45 +0000 (14:34 -0500)
modules/bmfont/utils.onyx [new file with mode: 0644]
modules/immediate_mode/shaders/alpha_fragment.glsl [new file with mode: 0644]
modules/ui/components/button.onyx
modules/ui/resources/fonts/test.fnt [new file with mode: 0644]
modules/ui/resources/fonts/test_0.data [new file with mode: 0644]
modules/ui/ui.onyx
src/onyxutils.c

diff --git a/modules/bmfont/utils.onyx b/modules/bmfont/utils.onyx
new file mode 100644 (file)
index 0000000..c470297
--- /dev/null
@@ -0,0 +1,51 @@
+package bmfont
+
+#private_file math :: package core.math
+
+@Incomplete // does not use the size parameter
+get_width :: (use font: ^BMFont, text: str, size: f32) -> f32 {
+    max_x := 0.0f;
+    x := 0.0f;
+
+    for char: text {
+        if char == #char "\n" {
+            max_x = math.max(max_x, x);
+            x = 0.0f;
+            continue;
+        }
+
+        glyph := font->get_glyph(char);
+
+        if glyph == null {
+            glyph = font->get_glyph(0);
+        }
+
+        x += ~~ glyph.xadvance * size;
+    }
+
+    return math.max(max_x, x);
+}
+
+@Incomplete // does not use the size parameter
+get_height :: (use font: ^BMFont, text: str, size: f32) -> f32 {
+    max_y := 0.0f;
+    y := 0.0f;
+
+    for char: text {
+        if char == #char "\n" {
+            y += max_y;
+            max_y = 0;
+            continue;
+        }
+
+        glyph := font->get_glyph(char);
+
+        if glyph == null {
+            glyph = font->get_glyph(0);
+        }
+
+        max_y = math.max(max_y, ~~glyph.h * size);
+    }
+
+    return y + max_y;
+}
\ No newline at end of file
diff --git a/modules/immediate_mode/shaders/alpha_fragment.glsl b/modules/immediate_mode/shaders/alpha_fragment.glsl
new file mode 100644 (file)
index 0000000..38d89ad
--- /dev/null
@@ -0,0 +1,15 @@
+#version 300 es
+
+precision mediump float;
+
+uniform sampler2D u_texture;
+
+in vec4 v_color;
+in vec2 v_texture;
+
+out vec4 fragColor;
+
+void main() {
+    float alpha = texture(u_texture, v_texture).a;
+    fragColor = v_color * alpha;
+}
\ No newline at end of file
index c2923805bc86d3cf209edc7231f5bd529d83e6ac..f5e3d9477f63ec005cfd109f8ee7f7ed93c7098a 100644 (file)
@@ -54,12 +54,12 @@ button :: (use r: Rectangle, text: str, theme := ^default_button_theme, site :=
     }
 
     if is_hot_item(hash) {
-        move_towards(^button_state.hover_time, 1.0f, 0.1f);
+        move_towards(^button_state.hover_time, 1.0f, 0.1f);  @ThemeConfiguration
     } else {
-        move_towards(^button_state.hover_time, 0.0f, 0.1f);
+        move_towards(^button_state.hover_time, 0.0f, 0.1f);  @ThemeConfiguration
     }
 
-    move_towards(^button_state.click_time, 0.0f, 0.08f);
+    move_towards(^button_state.click_time, 0.0f, 0.08f);     @ThemeConfiguration
 
     border_width  := theme.border_width;
     width, height := Rectangle.dimensions(r);
@@ -70,10 +70,11 @@ button :: (use r: Rectangle, text: str, theme := ^default_button_theme, site :=
     surface_color  = color_lerp(button_state.click_time, surface_color, theme.click_color);
     gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, surface_color);
 
-    text_width  := 0.0f; @Cleanup // font->get_width(text, theme.font_size);
-    text_height := 0.0f; @Cleanup // font->get_height(text, theme.font_size);
+    text_width  := bmfont.get_width(^font, text, theme.font_size);
+    text_height := bmfont.get_height(^font, text, theme.font_size);
 
-    draw_text_raw(text, x0 + (width - text_width) / 2, y0 + (height - text_height) / 2, theme.font_size, theme.text_color);
+    @ThemeConfiguration // This always draws the text centered on the button surface.
+    draw_text_raw(text, x0 + (width - text_width) / 2, y0 + ~~ font.common.baseline * theme.font_size + (height - text_height) / 2, theme.font_size, theme.text_color);
 
     if button_state.click_time > 0 || button_state.hover_time > 0 {
         map.put(^button_states, hash, button_state);
diff --git a/modules/ui/resources/fonts/test.fnt b/modules/ui/resources/fonts/test.fnt
new file mode 100644 (file)
index 0000000..15addba
--- /dev/null
@@ -0,0 +1,100 @@
+info face="Fira Code Retina" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0
+common lineHeight=32 base=24 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4
+page id=0 file="test_0.tga"
+chars count=96
+char id=-1   x=159   y=0     width=16    height=22    xoffset=0     yoffset=4     xadvance=16    page=0  chnl=15
+char id=32   x=252   y=0     width=3     height=1     xoffset=-1    yoffset=31    xadvance=16    page=0  chnl=15
+char id=33   x=249   y=42    width=6     height=19    xoffset=5     yoffset=5     xadvance=16    page=0  chnl=15
+char id=34   x=226   y=79    width=10    height=7     xoffset=3     yoffset=4     xadvance=16    page=0  chnl=15
+char id=35   x=129   y=46    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=36   x=5     y=0     width=14    height=28    xoffset=1     yoffset=0     xadvance=16    page=0  chnl=15
+char id=37   x=97    y=26    width=16    height=20    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=38   x=98    y=47    width=15    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=39   x=237   y=79    width=4     height=7     xoffset=6     yoffset=4     xadvance=16    page=0  chnl=15
+char id=40   x=56    y=0     width=10    height=27    xoffset=2     yoffset=1     xadvance=16    page=0  chnl=15
+char id=41   x=67    y=0     width=10    height=27    xoffset=4     yoffset=1     xadvance=16    page=0  chnl=15
+char id=42   x=161   y=86    width=14    height=14    xoffset=1     yoffset=8     xadvance=16    page=0  chnl=15
+char id=43   x=176   y=84    width=14    height=13    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=44   x=191   y=83    width=6     height=10    xoffset=5     yoffset=19    xadvance=16    page=0  chnl=15
+char id=45   x=17    y=71    width=12    height=3     xoffset=2     yoffset=13    xadvance=16    page=0  chnl=15
+char id=46   x=17    y=111   width=6     height=5     xoffset=5     yoffset=19    xadvance=16    page=0  chnl=15
+char id=47   x=96    y=0     width=14    height=25    xoffset=1     yoffset=2     xadvance=16    page=0  chnl=15
+char id=48   x=15    y=75    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=49   x=44    y=71    width=13    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=50   x=72    y=70    width=13    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=51   x=100   y=67    width=13    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=52   x=114   y=26    width=14    height=20    xoffset=1     yoffset=4     xadvance=16    page=0  chnl=15
+char id=53   x=128   y=67    width=13    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=54   x=0     y=75    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=55   x=129   y=25    width=12    height=20    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=56   x=114   y=47    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=57   x=237   y=0     width=14    height=21    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=58   x=154   y=86    width=6     height=15    xoffset=5     yoffset=9     xadvance=16    page=0  chnl=15
+char id=59   x=142   y=25    width=6     height=20    xoffset=5     yoffset=9     xadvance=16    page=0  chnl=15
+char id=60   x=128   y=87    width=12    height=15    xoffset=2     yoffset=8     xadvance=16    page=0  chnl=15
+char id=61   x=213   y=79    width=12    height=8     xoffset=2     yoffset=11    xadvance=16    page=0  chnl=15
+char id=62   x=60    y=90    width=13    height=15    xoffset=2     yoffset=8     xadvance=16    page=0  chnl=15
+char id=63   x=181   y=63    width=12    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=64   x=176   y=0     width=16    height=22    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=65   x=17    y=51    width=16    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=66   x=114   y=67    width=13    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=67   x=82    y=50    width=15    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=68   x=50    y=50    width=15    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=69   x=86    y=70    width=13    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=70   x=168   y=64    width=12    height=19    xoffset=3     yoffset=5     xadvance=16    page=0  chnl=15
+char id=71   x=34    y=51    width=15    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=72   x=204   y=43    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=73   x=155   y=66    width=12    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=74   x=58    y=70    width=13    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=75   x=189   y=43    width=14    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=76   x=142   y=66    width=12    height=19    xoffset=3     yoffset=5     xadvance=16    page=0  chnl=15
+char id=77   x=0     y=55    width=16    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=78   x=159   y=44    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=79   x=168   y=23    width=16    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=80   x=234   y=43    width=14    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=81   x=126   y=0     width=17    height=24    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=82   x=144   y=46    width=14    height=19    xoffset=2     yoffset=5     xadvance=16    page=0  chnl=15
+char id=83   x=66    y=50    width=15    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=84   x=236   y=22    width=16    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=85   x=174   y=43    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=86   x=219   y=23    width=16    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=87   x=149   y=24    width=18    height=19    xoffset=-1    yoffset=5     xadvance=16    page=0  chnl=15
+char id=88   x=202   y=23    width=16    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=89   x=185   y=23    width=16    height=19    xoffset=0     yoffset=5     xadvance=16    page=0  chnl=15
+char id=90   x=219   y=43    width=14    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=91   x=78    y=0     width=8     height=26    xoffset=4     yoffset=1     xadvance=16    page=0  chnl=15
+char id=92   x=111   y=0     width=14    height=25    xoffset=1     yoffset=2     xadvance=16    page=0  chnl=15
+char id=93   x=87    y=0     width=8     height=26    xoffset=4     yoffset=1     xadvance=16    page=0  chnl=15
+char id=94   x=198   y=79    width=14    height=9     xoffset=1     yoffset=0     xadvance=16    page=0  chnl=15
+char id=95   x=24    y=111   width=14    height=3     xoffset=1     yoffset=26    xadvance=16    page=0  chnl=15
+char id=96   x=242   y=79    width=8     height=5     xoffset=4     yoffset=3     xadvance=16    page=0  chnl=15
+char id=97   x=45    y=91    width=14    height=15    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=98   x=56    y=28    width=13    height=21    xoffset=2     yoffset=3     xadvance=16    page=0  chnl=15
+char id=99   x=243   y=63    width=12    height=15    xoffset=2     yoffset=9     xadvance=16    page=0  chnl=15
+char id=100  x=42    y=28    width=13    height=21    xoffset=1     yoffset=3     xadvance=16    page=0  chnl=15
+char id=101  x=228   y=63    width=14    height=15    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=102  x=28    y=29    width=13    height=21    xoffset=2     yoffset=3     xadvance=16    page=0  chnl=15
+char id=103  x=144   y=0     width=14    height=23    xoffset=1     yoffset=7     xadvance=16    page=0  chnl=15
+char id=104  x=84    y=27    width=12    height=21    xoffset=2     yoffset=3     xadvance=16    page=0  chnl=15
+char id=105  x=208   y=0     width=13    height=22    xoffset=2     yoffset=2     xadvance=16    page=0  chnl=15
+char id=106  x=20    y=0     width=11    height=28    xoffset=2     yoffset=2     xadvance=16    page=0  chnl=15
+char id=107  x=193   y=0     width=14    height=22    xoffset=2     yoffset=2     xadvance=16    page=0  chnl=15
+char id=108  x=0     y=33    width=13    height=21    xoffset=1     yoffset=3     xadvance=16    page=0  chnl=15
+char id=109  x=211   y=63    width=16    height=15    xoffset=0     yoffset=9     xadvance=16    page=0  chnl=15
+char id=110  x=102   y=87    width=12    height=15    xoffset=2     yoffset=9     xadvance=16    page=0  chnl=15
+char id=111  x=0     y=95    width=14    height=15    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=112  x=70    y=28    width=13    height=21    xoffset=2     yoffset=9     xadvance=16    page=0  chnl=15
+char id=113  x=14    y=29    width=13    height=21    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=114  x=74    y=90    width=13    height=15    xoffset=2     yoffset=9     xadvance=16    page=0  chnl=15
+char id=115  x=88    y=90    width=13    height=15    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=116  x=30    y=71    width=13    height=19    xoffset=1     yoffset=5     xadvance=16    page=0  chnl=15
+char id=117  x=115   y=87    width=12    height=15    xoffset=2     yoffset=9     xadvance=16    page=0  chnl=15
+char id=118  x=15    y=95    width=14    height=15    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=119  x=194   y=63    width=16    height=15    xoffset=0     yoffset=9     xadvance=16    page=0  chnl=15
+char id=120  x=30    y=91    width=14    height=15    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=121  x=222   y=0     width=14    height=21    xoffset=1     yoffset=9     xadvance=16    page=0  chnl=15
+char id=122  x=141   y=87    width=12    height=15    xoffset=2     yoffset=9     xadvance=16    page=0  chnl=15
+char id=123  x=44    y=0     width=11    height=27    xoffset=2     yoffset=1     xadvance=16    page=0  chnl=15
+char id=124  x=0     y=0     width=4     height=32    xoffset=6     yoffset=0     xadvance=16    page=0  chnl=15
+char id=125  x=32    y=0     width=11    height=27    xoffset=3     yoffset=1     xadvance=16    page=0  chnl=15
+char id=126  x=0     y=111   width=16    height=5     xoffset=0     yoffset=13    xadvance=16    page=0  chnl=15
diff --git a/modules/ui/resources/fonts/test_0.data b/modules/ui/resources/fonts/test_0.data
new file mode 100644 (file)
index 0000000..7b2450b
Binary files /dev/null and b/modules/ui/resources/fonts/test_0.data differ
index 48e4cd2dd10e63d4e959939d96c650adc2a217f5..167679891a1849da227a9ce7ecfa0029af24cf9b 100644 (file)
@@ -8,7 +8,7 @@ use package core
 #private font_texture : gl.GLTexture;
 
 @Temporary
-DEFAULT_TEXT_SIZE :: 40.0f
+DEFAULT_TEXT_SIZE :: 1.0f
 
 
 UI_Id :: #type u32
@@ -34,7 +34,7 @@ mouse_state: MouseState = MouseState.{};
 init_ui :: () {
     init_font();
 
-    map.init(^button_states, default=.{});
+    map.init(^button_states, default=.{}, hash_count=4);
 }
 
 clear_buttons :: () {
@@ -100,13 +100,15 @@ is_hot_item :: (id: UI_Id) -> bool {
     return hot_item == id;
 }
 
-draw_text_raw :: (text: str, x: f32, y: f32, line_height := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) {
+draw_text_raw :: (text: str, x: f32, y: f32, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) {
     gl.activeTexture(gl.TEXTURE0);
     gl.bindTexture(gl.TEXTURE_2D, font_texture);
-    gfx.set_texture(0);
+    gfx.use_alpha_shader(0);
 
     original_x := x;
-    baseline := cast(f32) font.common.baseline;
+    baseline := cast(f32) font.common.baseline * size;
+
+    line_height := cast(f32) font.common.line_height * size;
 
     for char: text {
         if char == #char "\n" {
@@ -122,19 +124,14 @@ draw_text_raw :: (text: str, x: f32, y: f32, line_height := DEFAULT_TEXT_SIZE, c
             assert(glyph != null, "NO NULL GLYPH");
         }
 
-        // Round to the nearest pixel
-        tx, ty := math.floor(x + ~~glyph.xoffset + .5), math.floor(y + ~~glyph.yoffset + baseline + .5);
-        w      := math.floor(cast(f32) glyph.w + .5);
-        h      := math.floor(cast(f32) glyph.h + .5);
+        // Round to the nearest pixel to avoid bleeding to the next glyph
+        tx, ty := math.floor(x + ~~glyph.xoffset * size + .5), math.floor(y + ~~glyph.yoffset * size - baseline + .5);
+        w      := math.floor(cast(f32) glyph.w * size + .5);
+        h      := math.floor(cast(f32) glyph.h * size + .5);
 
-        gfx.textured_rect(
-            .{ tx, ty },
-            .{ w, h },
-            .{ glyph.tex_x, glyph.tex_y },
-            .{ glyph.tex_w, glyph.tex_h },
-            color = color);
+        gfx.textured_rect(.{ tx, ty }, .{ w, h }, .{ glyph.tex_x, glyph.tex_y }, .{ glyph.tex_w, glyph.tex_h }, color = color);
 
-        x += ~~glyph.xadvance;
+        x += ~~glyph.xadvance * size;
     }
     
     gfx.flush();
@@ -157,7 +154,7 @@ draw_rect :: proc {
 
 @Themeing
 draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme, site := #callsite) -> bool {
-    draw_text_raw(text, x0, y0, theme.font_size, theme.text_color);
+    draw_text_raw(text, x0, y0 + ~~font.common.baseline * theme.font_size, theme.font_size, theme.text_color);
 }
 
 Rectangle :: struct {
@@ -195,7 +192,7 @@ Rectangle :: struct {
 @Relocate
 Text_Theme :: struct {
     text_color := gfx.Color4.{ 1, 1, 1 };
-    font_size  := 18.0f;
+    font_size  := 1.0f;
 }
 
 default_text_theme:   Text_Theme   = Text_Theme.{};
@@ -217,14 +214,18 @@ get_site_hash :: (site: CallSite, increment := 0) -> UI_Id {
 }
 
 get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
-    @Cleanup
-    return 0; // font->get_width(text, size);
+    return font->get_width(text, size);
 }
 
 
+@Cleanup
+// There should be a way to load multiple fonts and have a font cache.
+// The font cache pointers should be stable so you can take a pointer
+// to a font and it will remain valid. Probably want some kind of arena
+// with a map from i32 -> ^BMFont.
 #private init_font :: () {
-    fnt_file_data := #file_contents "./resources/fonts/FiraCode.fnt";
-    texture_data := #file_contents "./resources/fonts/FiraCode.data";
+    fnt_file_data := #file_contents "./resources/fonts/test.fnt";
+    texture_data := #file_contents "./resources/fonts/test_0.data";
 
     font = bmfont.load_bmfont(fnt_file_data);
 
@@ -232,7 +233,7 @@ get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
 
     font_texture = gl.createTexture();
     gl.bindTexture(gl.TEXTURE_2D, font_texture);
-    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, tex_width, tex_height, 0, gl.RGBA, gl.UNSIGNED_BYTE, texture_data);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, tex_width, tex_height, 0, gl.ALPHA, gl.UNSIGNED_BYTE, texture_data);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
index 8d1d9ac9b22281ed0a2439f2e1b714fa4b70e3f6..cca3892d1b19a92af7f26bbb3c06d5010da5fc8b 100644 (file)
@@ -225,7 +225,7 @@ void scope_clear(Scope* scope) {
 // Polymorphic Procedures
 //
 
-AstNode node_that_signals_a_yield = {};
+AstNode node_that_signals_a_yield = { 0 };
 
 static void ensure_polyproc_cache_is_created(AstPolyProc* pp) {
     if (pp->concrete_funcs == NULL) {