1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package renderer
BASE_FONT_WIDTH :: 5
BASE_FONT_HEIGHT :: 7
BASE_FONT_ADVANCE :: 6
BASE_FONT_LINE_ADVANCE :: 8
@(private)
base_font_normalize_char :: proc(ch: u8) -> u8 {
if ch >= 'a' && ch <= 'z' {
return ch - ('a' - 'A')
}
return ch
}
@(private)
base_font_unknown_glyph :: proc() -> [BASE_FONT_HEIGHT]u8 {
return {
0b11111,
0b10001,
0b10101,
0b10001,
0b10101,
0b10001,
0b11111,
}
}
base_font_glyph :: proc(ch: u8) -> [BASE_FONT_HEIGHT]u8 {
switch base_font_normalize_char(ch) {
case '0': return {0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110}
case '1': return {0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110}
case '2': return {0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b01000, 0b11111}
case '3': return {0b11110, 0b00001, 0b00001, 0b01110, 0b00001, 0b00001, 0b11110}
case '4': return {0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010}
case '5': return {0b11111, 0b10000, 0b10000, 0b11110, 0b00001, 0b00001, 0b11110}
case '6': return {0b01110, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110}
case '7': return {0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000}
case '8': return {0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110}
case '9': return {0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00001, 0b01110}
case 'A': return {0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}
case 'B': return {0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110}
case 'C': return {0b01111, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b01111}
case 'D': return {0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110}
case 'E': return {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111}
case 'F': return {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000}
case 'G': return {0b01111, 0b10000, 0b10000, 0b10111, 0b10001, 0b10001, 0b01111}
case 'H': return {0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}
case 'I': return {0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b11111}
case 'J': return {0b00001, 0b00001, 0b00001, 0b00001, 0b10001, 0b10001, 0b01110}
case 'K': return {0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001}
case 'L': return {0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111}
case 'M': return {0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001}
case 'N': return {0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001, 0b10001}
case 'O': return {0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110}
case 'P': return {0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000}
case 'Q': return {0b01110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101}
case 'R': return {0b11110, 0b10001, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001}
case 'S': return {0b01111, 0b10000, 0b10000, 0b01110, 0b00001, 0b00001, 0b11110}
case 'T': return {0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100}
case 'U': return {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110}
case 'V': return {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01010, 0b00100}
case 'W': return {0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b10101, 0b01010}
case 'X': return {0b10001, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b10001}
case 'Y': return {0b10001, 0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100}
case 'Z': return {0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111}
case ':': return {0b00000, 0b00100, 0b00100, 0b00000, 0b00100, 0b00100, 0b00000}
case '.': return {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b01100, 0b01100}
case ',': return {0b00000, 0b00000, 0b00000, 0b00000, 0b00100, 0b00100, 0b01000}
case '-': return {0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000}
case '_': return {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111}
case '+': return {0b00000, 0b00100, 0b00100, 0b11111, 0b00100, 0b00100, 0b00000}
case '=': return {0b00000, 0b00000, 0b11111, 0b00000, 0b11111, 0b00000, 0b00000}
case '!': return {0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00000, 0b00100}
case '?': return {0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b00000, 0b00100}
case '/': return {0b00001, 0b00010, 0b00100, 0b00100, 0b01000, 0b10000, 0b10000}
case '\\': return {0b10000, 0b01000, 0b00100, 0b00100, 0b00010, 0b00001, 0b00001}
case '(': return {0b00010, 0b00100, 0b01000, 0b01000, 0b01000, 0b00100, 0b00010}
case ')': return {0b01000, 0b00100, 0b00010, 0b00010, 0b00010, 0b00100, 0b01000}
case '[': return {0b01110, 0b01000, 0b01000, 0b01000, 0b01000, 0b01000, 0b01110}
case ']': return {0b01110, 0b00010, 0b00010, 0b00010, 0b00010, 0b00010, 0b01110}
case '<': return {0b00010, 0b00100, 0b01000, 0b10000, 0b01000, 0b00100, 0b00010}
case '>': return {0b01000, 0b00100, 0b00010, 0b00001, 0b00010, 0b00100, 0b01000}
case '#': return {0b01010, 0b01010, 0b11111, 0b01010, 0b11111, 0b01010, 0b01010}
case '%': return {0b11001, 0b11010, 0b00100, 0b01000, 0b10110, 0b00110, 0b00000}
case '\'': return {0b00100, 0b00100, 0b01000, 0b00000, 0b00000, 0b00000, 0b00000}
case '"': return {0b01010, 0b01010, 0b01010, 0b00000, 0b00000, 0b00000, 0b00000}
}
return base_font_unknown_glyph()
}
base_font_add_text :: proc(batch: ^Batch_2D, x, y: f32, text: string, color: [4]f32, scale: f32 = 1.0) {
if scale <= 0 {
return
}
cursor_x := x
cursor_y := y
for i in 0..<len(text) {
ch := text[i]
if ch == '\n' {
cursor_x = x
cursor_y += f32(BASE_FONT_LINE_ADVANCE) * scale
continue
}
if ch == ' ' || ch == '\t' {
cursor_x += f32(BASE_FONT_ADVANCE) * scale
continue
}
rows := base_font_glyph(ch)
for row in 0..<BASE_FONT_HEIGHT {
bits := rows[row]
col := 0
for col < BASE_FONT_WIDTH {
mask := u8(1 << u32(BASE_FONT_WIDTH - 1 - col))
if (bits & mask) == 0 {
col += 1
continue
}
start_col := col
for col < BASE_FONT_WIDTH {
run_mask := u8(1 << u32(BASE_FONT_WIDTH - 1 - col))
if (bits & run_mask) == 0 {
break
}
col += 1
}
batch_add_rectangle(
batch,
cursor_x + f32(start_col) * scale,
cursor_y + f32(row) * scale,
f32(col - start_col) * scale,
scale,
color,
)
}
}
cursor_x += f32(BASE_FONT_ADVANCE) * scale
}
}
base_font_text_width :: proc(text: string, scale: f32 = 1.0) -> f32 {
if scale <= 0 || len(text) == 0 {
return 0
}
max_chars := 0
line_chars := 0
for i in 0..<len(text) {
if text[i] == '\n' {
max_chars = max(max_chars, line_chars)
line_chars = 0
continue
}
line_chars += 1
}
max_chars = max(max_chars, line_chars)
return f32(max_chars * BASE_FONT_ADVANCE) * scale
}
base_font_text_height :: proc(text: string, scale: f32 = 1.0) -> f32 {
if scale <= 0 || len(text) == 0 {
return 0
}
lines := 1
for i in 0..<len(text) {
if text[i] == '\n' && i + 1 < len(text) {
lines += 1
}
}
return f32(lines * BASE_FONT_LINE_ADVANCE) * scale
}