Skip to content

Commit c13feb2

Browse files
authored
[Bindings/Odin] Improve example text measurement function (#541)
1 parent fd97d81 commit c13feb2

File tree

1 file changed

+64
-12
lines changed

1 file changed

+64
-12
lines changed

bindings/odin/examples/clay-official-website/clay_renderer_raylib.odin

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package main
22

3+
import "core:unicode/utf8"
4+
import "base:runtime"
35
import clay "../../clay-odin"
46
import "core:math"
57
import "core:strings"
@@ -16,24 +18,74 @@ clay_color_to_rl_color :: proc(color: clay.Color) -> rl.Color {
1618

1719
raylib_fonts := [dynamic]Raylib_Font{}
1820

19-
measure_text :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions {
20-
line_width: f32 = 0
21+
// Alias for compatibility, default to ascii support
22+
measure_text :: measure_text_ascii
2123

22-
font := raylib_fonts[config.fontId].font
24+
measure_text_unicode :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions {
25+
// Needed for grapheme_count
26+
context = runtime.default_context()
27+
28+
line_width: f32 = 0
29+
30+
font := raylib_fonts[config.fontId].font
31+
text_str := string(text.chars[:text.length])
2332

24-
for i in 0 ..< text.length {
25-
glyph_index := text.chars[i] - 32
33+
// This function seems somewhat expensive, if you notice performance issues, you could assume
34+
// - 1 codepoint per visual character (no grapheme clusters), where you can get the length from the loop
35+
// - 1 byte per visual character (ascii), where you can get the length with `text.length`
36+
// see `measure_text_ascii`
37+
grapheme_count, _, _ := utf8.grapheme_count(text_str)
38+
39+
for letter, byte_idx in text_str {
40+
glyph_index := rl.GetGlyphIndex(font, letter)
2641

2742
glyph := font.glyphs[glyph_index]
2843

29-
if glyph.advanceX != 0 {
30-
line_width += f32(glyph.advanceX)
31-
} else {
32-
line_width += font.recs[glyph_index].width + f32(glyph.offsetX)
33-
}
34-
}
44+
if glyph.advanceX != 0 {
45+
line_width += f32(glyph.advanceX)
46+
} else {
47+
line_width += font.recs[glyph_index].width + f32(font.glyphs[glyph_index].offsetX)
48+
}
49+
}
50+
51+
scaleFactor := f32(config.fontSize) / f32(font.baseSize)
52+
53+
// Note:
54+
// I'd expect this to be `grapheme_count - 1`,
55+
// but that seems to be one letterSpacing too small
56+
// maybe that's a raylib bug, maybe that's Clay?
57+
total_spacing := f32(grapheme_count) * f32(config.letterSpacing)
58+
59+
return {width = line_width * scaleFactor + total_spacing, height = f32(config.fontSize)}
60+
}
61+
62+
measure_text_ascii :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions {
63+
line_width: f32 = 0
64+
65+
font := raylib_fonts[config.fontId].font
66+
text_str := string(text.chars[:text.length])
67+
68+
for i in 0..<len(text_str) {
69+
glyph_index := text_str[i] - 32
70+
71+
glyph := font.glyphs[glyph_index]
72+
73+
if glyph.advanceX != 0 {
74+
line_width += f32(glyph.advanceX)
75+
} else {
76+
line_width += font.recs[glyph_index].width + f32(font.glyphs[glyph_index].offsetX)
77+
}
78+
}
79+
80+
scaleFactor := f32(config.fontSize) / f32(font.baseSize)
81+
82+
// Note:
83+
// I'd expect this to be `len(text_str) - 1`,
84+
// but that seems to be one letterSpacing too small
85+
// maybe that's a raylib bug, maybe that's Clay?
86+
total_spacing := f32(len(text_str)) * f32(config.letterSpacing)
3587

36-
return {width = line_width / 2, height = f32(config.fontSize)}
88+
return {width = line_width * scaleFactor + total_spacing, height = f32(config.fontSize)}
3789
}
3890

3991
clay_raylib_render :: proc(render_commands: ^clay.ClayArray(clay.RenderCommand), allocator := context.temp_allocator) {

0 commit comments

Comments
 (0)