load_bmfont :: (fnt_data: [] u8) -> BMFont {
bmf: BMFont;
+ memory.set(^bmf, 0, sizeof BMFont);
+
map.init(^bmf.pages);
map.init(^bmf.glyphs);
@Cleanup // this was a stupid way of doing this. Just use a f-ing for loop.
array.map(^bmf.glyphs.entries, ^bmf, (glyph: ^map.Map.Entry(i32, BMFont_Glyph), font: ^BMFont) {
glyph.value.tex_x = ~~ glyph.value.x / cast(f32) font.common.scale_width;
- glyph.value.tex_y = ~~ glyph.value.y / cast(f32) font.common.scale_width;
+ glyph.value.tex_y = ~~ glyph.value.y / cast(f32) font.common.scale_height;
glyph.value.tex_w = ~~ glyph.value.w / cast(f32) font.common.scale_width;
- glyph.value.tex_h = ~~ glyph.value.h / cast(f32) font.common.scale_width;
+ glyph.value.tex_h = ~~ glyph.value.h / cast(f32) font.common.scale_height;
});
return bmf;
out vec4 fragColor;
void main() {
- float alpha = texture(u_texture, v_texture).a;
+ float alpha = texture(u_texture, v_texture).r;
fragColor = v_color * alpha;
}
\ No newline at end of file
surface_color = color_lerp(animation_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 := bmfont.get_width(^font, text, theme.font_size);
- text_height := bmfont.get_height(^font, text, theme.font_size);
+ text_width, text_height := main_font->get_dimensions(text, theme.font_size);
@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,
+ y0 + main_font->get_baseline(theme.font_size) + (height - text_height) / 2,
theme.font_size, theme.text_color);
move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed);
surface_color
);
- text_width := bmfont.get_width(^font, text, theme.font_size);
- text_height := bmfont.get_height(^font, text, theme.font_size);
+ text_width, text_height := main_font->get_dimensions(text, theme.font_size);
draw_text_raw(
text,
x0 + box_size + 4 * 2, @Cleanup @ThemeConfiguration
- y0 + ~~ font.common.baseline * theme.font_size + (height - text_height) / 2,
+ y0 + main_font->get_baseline(theme.font_size) + (height - text_height) / 2,
theme.font_size, theme.text_color);
move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed);
gfx.circle(.{ cx, cy }, radius - theme.radio_border_radius, color=surface_color);
- text_width := bmfont.get_width(^font, text, theme.font_size);
- text_height := bmfont.get_height(^font, text, theme.font_size);
+ text_width, text_height := main_font->get_dimensions(text, theme.font_size);
draw_text_raw(
text,
x0 + 2 * radius + 4, @ThemeConfiguration
- y0 + ~~ font.common.baseline * theme.font_size + (height - text_height) / 2,
+ y0 + main_font->get_baseline(theme.font_size) + (height - text_height) / 2,
theme.font_size, theme.text_color);
move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed);
text = placeholder;
text_color = theme.placeholder_text_color;
}
- text_width := bmfont.get_width(^font, text, theme.font_size);
- text_height := bmfont.get_height(^font, text, theme.font_size);
+
+ text_width, text_height := main_font->get_dimensions(text, theme.font_size);
text_x := x0 + border_width;
- text_y := y0 + ~~ font.common.baseline * theme.font_size + (height - text_height) / 2;
+ text_y := y0 + main_font->get_baseline(theme.font_size) + (height - text_height) / 2;
if is_hot_item(hash) && !is_active_item(hash) {
if mouse_state.left_button_down && Rectangle.contains(r, mx, my) {
text := string.buffer_to_str(text_buffer);
- for glyph: bmfont.get_character_positions(^font, text_size, text, text_x, text_y) {
+ bm_font := ^main_font.font;
+ for glyph: bmfont.get_character_positions(bm_font, text_size * main_font.em / ~~bm_font.common.line_height, text, text_x, text_y) {
if countdown == 0 do return last_x;
last_x = glyph.pos_x;
last_x: f32 = text_x;
text := string.buffer_to_str(text_buffer);
- for glyph: bmfont.get_character_positions(^font, text_size, text, text_x, text_y) {
+ @FontCleanup
+ bm_font := ^main_font.font;
+ for glyph: bmfont.get_character_positions(bm_font, text_size * main_font.em / ~~bm_font.common.line_height, text, text_x, text_y) {
cursor_position += 1;
if cursor_position == 1 do continue;
package ui
+// A simple wrapper for a BMFont and an OpenGL Texture
+
+#private_file RK :: enum { Luminance; Color; }
+
Font :: struct {
- texture: gfx.Texture;
-}
\ No newline at end of file
+ texture : gfx.Texture;
+ font : bmfont.BMFont;
+
+ em: f32 = 32;
+ rendering_kind := RK.Luminance;
+
+ get_width :: (use f: ^Font, text: str, font_size: f32) -> f32 {
+ size := font_size * (em / ~~font.common.line_height);
+ return bmfont.get_width(^font, text, size);
+ }
+
+ get_height :: (use f: ^Font, text: str, font_size: f32) -> f32 {
+ size := font_size * (em / ~~font.common.line_height);
+ return bmfont.get_height(^font, text, size);
+ }
+
+ get_dimensions :: (use f: ^Font, text: str, font_size: f32) -> (width: f32, height: f32) {
+ size := font_size * (em / ~~font.common.line_height);
+ return bmfont.get_width(^font, text, size),
+ bmfont.get_height(^font, text, size);
+ }
+
+ get_baseline :: (use f: ^Font, font_size: f32) -> f32 {
+ size := font_size * (em / ~~font.common.line_height);
+ return ~~font.common.baseline * size;
+ }
+
+ render :: (use f: ^Font, text: str, x: f32, y: f32, font_size: f32, color := gfx.Color4.{1,1,1}) {
+ gfx.set_texture(^texture);
+
+ switch rendering_kind {
+ case .Luminance do gfx.use_alpha_shader(0);
+ case .Color do gfx.set_texture(0);
+ }
+
+ size := font_size * (em / ~~font.common.line_height);
+ for glyph: bmfont.get_character_positions(^font, size, text, x, y) {
+ gfx.textured_rect(
+ .{ glyph.pos_x, glyph.pos_y }, .{ glyph.pos_w, glyph.pos_h },
+ .{ glyph.tex_x, glyph.tex_y }, .{ glyph.tex_w, glyph.tex_h },
+ color = color);
+ }
+
+ gfx.set_texture();
+ }
+}
+
+create_font :: (bmfont_data: [] u8, font_texture_data: [] u8) -> Font {
+ font := bmfont.load_bmfont(bmfont_data);
+
+ color_channels_have_data := (font.common.blue_channel + font.common.green_channel + font.common.red_channel) == ~~0;
+
+ // This may not always be right
+ texture_width, texture_height := font.common.scale_width, font.common.scale_height;
+ assert(texture_width * texture_height * (4 if color_channels_have_data else 1) == font_texture_data.count, "Bad font texture size.");
+
+ rendering_kind: RK = (.Color) if color_channels_have_data else .Luminance;
+ font_format := gl.RGBA if color_channels_have_data else gl.LUMINANCE;
+
+ texture := gfx.load_texture(texture_width, texture_height, font_texture_data, font_format, font_format);
+
+ return .{ texture=texture, font=font, rendering_kind=rendering_kind };
+}
+
#load "./ui"
#load "./flow"
#load "./input"
+#load "./font"
#load "./components/button"
#load "./components/checkbox"
@Cleanup // Move these to the theme?
// Or create a cache of fonts and put pointers/string in the themes?
-#private font : bmfont.BMFont;
-#private font_texture : gfx.Texture;
+#private main_font : Font;
@Temporary
DEFAULT_TEXT_SIZE :: 1.0f
@FontSizing // Currently, `size` is just a multipler for the baked font size. This should be changed to be height in pixels, or 'em's.
draw_text_raw :: (text: str, x: f32, y: f32, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) {
- gfx.set_texture(^font_texture);
- gfx.use_alpha_shader(0);
-
- for glyph: bmfont.get_character_positions(^font, size, text, x, y) {
- gfx.textured_rect(
- .{ glyph.pos_x, glyph.pos_y }, .{ glyph.pos_w, glyph.pos_h },
- .{ glyph.tex_x, glyph.tex_y }, .{ glyph.tex_w, glyph.tex_h },
- color = color);
- }
-
- gfx.flush();
- gfx.set_texture();
+ main_font->render(text, x, y, size, color);
}
draw_rect :: #match {
}
draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme, site := #callsite) -> bool {
- draw_text_raw(text, x0, y0 + ~~font.common.baseline * theme.font_size, theme.font_size, theme.text_color);
+ draw_text_raw(text, x0, y0 + main_font->get_baseline(theme.font_size), theme.font_size, theme.text_color);
}
Rectangle :: struct {
}
get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
- return font->get_width(text, size);
+ return main_font->get_width(text, size);
}
// 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/Calibri.fnt";
- texture_data := #file_contents "./resources/fonts/Calibri_0.data";
+ fnt_file_data := #file_contents "./resources/fonts/FiraCode.fnt";
+ texture_data := #file_contents "./resources/fonts/FiraCode.data";
- font = bmfont.load_bmfont(fnt_file_data);
+ main_font = create_font(fnt_file_data, texture_data);
+}
- tex_width, tex_height := font.common.scale_width, font.common.scale_height;
+TEMP_switch_font :: () {
+ fnt_file_data := #file_contents "./resources/fonts/Calibri.fnt";
+ texture_data := #file_contents "./resources/fonts/Calibri_0.data";
- font_texture = gfx.load_texture(tex_width, tex_height, texture_data, gl.ALPHA, gl.ALPHA);
+ main_font = create_font(fnt_file_data, texture_data);
}