Browse Source

Part 7: Text

Austin Morlan 6 months ago
parent
commit
02a911ef9f
Signed by: Austin Morlan <mail@austinmorlan.com> GPG Key ID: FD6B27654AF5E348

+ 1
- 1
README.md View File

@@ -14,7 +14,7 @@ if (ret != ESP_OK) {
14 14
 }
15 15
 ```
16 16
 
17
-* Modify the `export.sh` script in this directory and fill out `IDF_PATH` and `IDF_TOOLS_PATH`
17
+* Modify the `export.sh` script in the `game` directory and fill out `IDF_PATH` and `IDF_TOOLS_PATH`
18 18
 	* `IDF_PATH` is the extracted ESP-IDF
19 19
 	* `IDF_TOOLS_PATH` is the path to the toolchain
20 20
 * `source export.sh`

BIN
assets/export/fonts/simple_16x16.bmp View File


+ 4
- 0
assets/export/fonts/simple_16x16.txt View File

@@ -0,0 +1,4 @@
1
+ABCDEFGHIJ
2
+KLMNOPQRST
3
+UVWXYZ1234
4
+567890:!?

BIN
assets/source/fonts/simple_16x16.aseprite View File


CMakeLists.txt → game/CMakeLists.txt View File


export.sh → game/export.sh View File


sdkconfig.defaults → game/sdkconfig.defaults View File


src/CMakeLists.txt → game/src/CMakeLists.txt View File

@@ -6,6 +6,7 @@ idf_component_register(
6 6
 	"odroid/display.c"
7 7
 	"odroid/input.c"
8 8
 	"odroid/sdcard.c"
9
+	"text.c"
9 10
 
10 11
 	INCLUDE_DIRS
11 12
 	"."

+ 374
- 0
game/src/font.h View File

@@ -0,0 +1,374 @@
1
+// AUTOMATICALLY GENERATED. DO NOT EDIT.
2
+
3
+#pragma once
4
+
5
+#include <assert.h>
6
+#include <stdint.h>
7
+
8
+
9
+static const int GLYPH_WIDTH = 16;
10
+static const int GLYPH_HEIGHT = 16;
11
+
12
+
13
+int GetGlyphIndex(char c)
14
+{
15
+	switch (c)
16
+	{
17
+		case 'a': case 'A': { return 0; break; }
18
+		case 'b': case 'B': { return 1; break; }
19
+		case 'c': case 'C': { return 2; break; }
20
+		case 'd': case 'D': { return 3; break; }
21
+		case 'e': case 'E': { return 4; break; }
22
+		case 'f': case 'F': { return 5; break; }
23
+		case 'g': case 'G': { return 6; break; }
24
+		case 'h': case 'H': { return 7; break; }
25
+		case 'i': case 'I': { return 8; break; }
26
+		case 'j': case 'J': { return 9; break; }
27
+		case 'k': case 'K': { return 10; break; }
28
+		case 'l': case 'L': { return 11; break; }
29
+		case 'm': case 'M': { return 12; break; }
30
+		case 'n': case 'N': { return 13; break; }
31
+		case 'o': case 'O': { return 14; break; }
32
+		case 'p': case 'P': { return 15; break; }
33
+		case 'q': case 'Q': { return 16; break; }
34
+		case 'r': case 'R': { return 17; break; }
35
+		case 's': case 'S': { return 18; break; }
36
+		case 't': case 'T': { return 19; break; }
37
+		case 'u': case 'U': { return 20; break; }
38
+		case 'v': case 'V': { return 21; break; }
39
+		case 'w': case 'W': { return 22; break; }
40
+		case 'x': case 'X': { return 23; break; }
41
+		case 'y': case 'Y': { return 24; break; }
42
+		case 'z': case 'Z': { return 25; break; }
43
+		case '1': { return 26; break; }
44
+		case '2': { return 27; break; }
45
+		case '3': { return 28; break; }
46
+		case '4': { return 29; break; }
47
+		case '5': { return 30; break; }
48
+		case '6': { return 31; break; }
49
+		case '7': { return 32; break; }
50
+		case '8': { return 33; break; }
51
+		case '9': { return 34; break; }
52
+		case '0': { return 35; break; }
53
+		case ':': { return 36; break; }
54
+		case '!': { return 37; break; }
55
+		case '?': { return 38; break; }
56
+		default: { assert(NULL); break; }
57
+	}
58
+}
59
+
60
+static const uint16_t glyphMap[39][16] =
61
+{
62
+	// A
63
+	{
64
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
65
+	0x781E,0x781E,0x781E,0x7FFE,
66
+	0x7FFE,0x7FFE,0x781E,0x781E,
67
+	0x781E,0x781E,0x781E,0x0000,
68
+	},
69
+
70
+	// B
71
+	{
72
+	0x0000,0x7FFC,0x7FFE,0x7FFE,
73
+	0x780E,0x780E,0x7FFE,0x7FFE,
74
+	0x7FFC,0x780C,0x780E,0x780E,
75
+	0x7FFE,0x7FFE,0x7FFC,0x0000,
76
+	},
77
+
78
+	// C
79
+	{
80
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
81
+	0x7800,0x7800,0x7800,0x7800,
82
+	0x7800,0x7800,0x7800,0x7800,
83
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
84
+	},
85
+
86
+	// D
87
+	{
88
+	0x0000,0x7FF8,0x7FFE,0x7FFE,
89
+	0x781E,0x781E,0x781E,0x781E,
90
+	0x781E,0x781E,0x781E,0x781E,
91
+	0x7FFE,0x7FFE,0x7FF8,0x0000,
92
+	},
93
+
94
+	// E
95
+	{
96
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
97
+	0x7800,0x7800,0x7FFC,0x7FFC,
98
+	0x7FFC,0x7800,0x7800,0x7800,
99
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
100
+	},
101
+
102
+	// F
103
+	{
104
+	0x0000,0x7FF8,0x7FF8,0x7FF8,
105
+	0x7800,0x7800,0x7FF0,0x7FF0,
106
+	0x7FF0,0x7800,0x7800,0x7800,
107
+	0x7800,0x7800,0x7800,0x0000,
108
+	},
109
+
110
+	// G
111
+	{
112
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
113
+	0x7800,0x7800,0x7800,0x7800,
114
+	0x787E,0x787E,0x781E,0x781E,
115
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
116
+	},
117
+
118
+	// H
119
+	{
120
+	0x0000,0x781E,0x781E,0x781E,
121
+	0x781E,0x781E,0x7FFE,0x7FFE,
122
+	0x7FFE,0x7FFE,0x781E,0x781E,
123
+	0x781E,0x781E,0x781E,0x0000,
124
+	},
125
+
126
+	// I
127
+	{
128
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
129
+	0x03C0,0x03C0,0x03C0,0x03C0,
130
+	0x03C0,0x03C0,0x03C0,0x03C0,
131
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
132
+	},
133
+
134
+	// J
135
+	{
136
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
137
+	0x00F0,0x00F0,0x00F0,0x00F0,
138
+	0x00F0,0x00F0,0x70F0,0x70F0,
139
+	0x7FF0,0x7FF0,0x7FF0,0x0000,
140
+	},
141
+
142
+	// K
143
+	{
144
+	0x0000,0x780E,0x780E,0x7838,
145
+	0x7838,0x79E0,0x79E0,0x7F80,
146
+	0x7F80,0x79E0,0x79E0,0x7878,
147
+	0x7878,0x781E,0x781E,0x0000,
148
+	},
149
+
150
+	// L
151
+	{
152
+	0x0000,0x7800,0x7800,0x7800,
153
+	0x7800,0x7800,0x7800,0x7800,
154
+	0x7800,0x7800,0x7800,0x7800,
155
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
156
+	},
157
+
158
+	// M
159
+	{
160
+	0x0000,0x781E,0x781E,0x7E7E,
161
+	0x7E7E,0x7FFE,0x7FFE,0x799E,
162
+	0x799E,0x781E,0x781E,0x781E,
163
+	0x781E,0x781E,0x781E,0x0000,
164
+	},
165
+
166
+	// N
167
+	{
168
+	0x0000,0x781E,0x781E,0x7E1E,
169
+	0x7E1E,0x7F9E,0x7F9E,0x7FFE,
170
+	0x79FE,0x79FE,0x787E,0x787E,
171
+	0x781E,0x781E,0x781E,0x0000,
172
+	},
173
+
174
+	// O
175
+	{
176
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
177
+	0x781E,0x781E,0x781E,0x781E,
178
+	0x781E,0x781E,0x781E,0x781E,
179
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
180
+	},
181
+
182
+	// P
183
+	{
184
+	0x0000,0x7FF8,0x7FFE,0x7FFE,
185
+	0x781E,0x781E,0x781E,0x7FFE,
186
+	0x7FF8,0x7FF8,0x7800,0x7800,
187
+	0x7800,0x7800,0x7800,0x0000,
188
+	},
189
+
190
+	// Q
191
+	{
192
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
193
+	0x7006,0x7006,0x7006,0x7006,
194
+	0x7006,0x7006,0x70C6,0x70C6,
195
+	0x7FF8,0x7FF8,0x001E,0x0000,
196
+	},
197
+
198
+	// R
199
+	{
200
+	0x0000,0x7FF8,0x7FFE,0x7FFE,
201
+	0x781E,0x781E,0x781E,0x7FFE,
202
+	0x7FF8,0x7FF8,0x781E,0x781E,
203
+	0x781E,0x781E,0x781E,0x0000,
204
+	},
205
+
206
+	// S
207
+	{
208
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
209
+	0x7800,0x7800,0x7FFE,0x7FFE,
210
+	0x7FFE,0x001E,0x001E,0x001E,
211
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
212
+	},
213
+
214
+	// T
215
+	{
216
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
217
+	0x03C0,0x03C0,0x03C0,0x03C0,
218
+	0x03C0,0x03C0,0x03C0,0x03C0,
219
+	0x03C0,0x03C0,0x03C0,0x0000,
220
+	},
221
+
222
+	// U
223
+	{
224
+	0x0000,0x781E,0x781E,0x781E,
225
+	0x781E,0x781E,0x781E,0x781E,
226
+	0x781E,0x781E,0x781E,0x781E,
227
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
228
+	},
229
+
230
+	// V
231
+	{
232
+	0x0000,0x781E,0x781E,0x781E,
233
+	0x781E,0x781E,0x781E,0x781E,
234
+	0x1E78,0x1E78,0x1E78,0x1E78,
235
+	0x07E0,0x07E0,0x07E0,0x0000,
236
+	},
237
+
238
+	// W
239
+	{
240
+	0x0000,0x781E,0x781E,0x781E,
241
+	0x781E,0x781E,0x781E,0x799E,
242
+	0x799E,0x7FFE,0x7FFE,0x7E7E,
243
+	0x7E7E,0x781E,0x781E,0x0000,
244
+	},
245
+
246
+	// X
247
+	{
248
+	0x0000,0x781E,0x781E,0x781E,
249
+	0x1E78,0x1E78,0x07E0,0x07E0,
250
+	0x07E0,0x07E0,0x1E78,0x1E78,
251
+	0x781E,0x781E,0x781E,0x0000,
252
+	},
253
+
254
+	// Y
255
+	{
256
+	0x0000,0x781E,0x781E,0x781E,
257
+	0x781E,0x781E,0x7E7E,0x7E7E,
258
+	0x1FF8,0x1FF8,0x07E0,0x07E0,
259
+	0x07E0,0x07E0,0x07E0,0x0000,
260
+	},
261
+
262
+	// Z
263
+	{
264
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
265
+	0x0078,0x0078,0x01E0,0x01E0,
266
+	0x0780,0x0780,0x1E00,0x1E00,
267
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
268
+	},
269
+
270
+	// 1
271
+	{
272
+	0x0000,0x01E0,0x01E0,0x01E0,
273
+	0x01E0,0x01E0,0x01E0,0x01E0,
274
+	0x01E0,0x01E0,0x01E0,0x01E0,
275
+	0x01E0,0x01E0,0x01E0,0x0000,
276
+	},
277
+
278
+	// 2
279
+	{
280
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
281
+	0x001E,0x001E,0x7FFE,0x7FFE,
282
+	0x7FFE,0x7800,0x7800,0x7800,
283
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
284
+	},
285
+
286
+	// 3
287
+	{
288
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
289
+	0x001E,0x001E,0x3FFE,0x3FFE,
290
+	0x3FFE,0x001E,0x001E,0x001E,
291
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
292
+	},
293
+
294
+	// 4
295
+	{
296
+	0x0000,0x781E,0x781E,0x781E,
297
+	0x781E,0x781E,0x7FFE,0x7FFE,
298
+	0x7FFE,0x7FFE,0x001E,0x001E,
299
+	0x001E,0x001E,0x001E,0x0000,
300
+	},
301
+
302
+	// 5
303
+	{
304
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
305
+	0x7800,0x7800,0x7FFE,0x7FFE,
306
+	0x7FFE,0x001E,0x001E,0x001E,
307
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
308
+	},
309
+
310
+	// 6
311
+	{
312
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
313
+	0x7800,0x7800,0x7FFE,0x7FFE,
314
+	0x7FFE,0x781E,0x781E,0x781E,
315
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
316
+	},
317
+
318
+	// 7
319
+	{
320
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
321
+	0x001E,0x001E,0x001E,0x001E,
322
+	0x001E,0x001E,0x001E,0x001E,
323
+	0x001E,0x001E,0x001E,0x0000,
324
+	},
325
+
326
+	// 8
327
+	{
328
+	0x0000,0x7FFE,0x7FFE,0x781E,
329
+	0x781E,0x781E,0x7FFE,0x7FFE,
330
+	0x7FFE,0x781E,0x781E,0x781E,
331
+	0x781E,0x7FFE,0x7FFE,0x0000,
332
+	},
333
+
334
+	// 9
335
+	{
336
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
337
+	0x781E,0x781E,0x781E,0x7FFE,
338
+	0x7FFE,0x7FFE,0x001E,0x001E,
339
+	0x001E,0x001E,0x001E,0x0000,
340
+	},
341
+
342
+	// 0
343
+	{
344
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
345
+	0x781E,0x781E,0x799E,0x799E,
346
+	0x799E,0x799E,0x781E,0x781E,
347
+	0x7FFE,0x7FFE,0x7FFE,0x0000,
348
+	},
349
+
350
+	// :
351
+	{
352
+	0x0000,0x0000,0x3C00,0x3C00,
353
+	0x3C00,0x3C00,0x0000,0x0000,
354
+	0x0000,0x0000,0x3C00,0x3C00,
355
+	0x3C00,0x3C00,0x0000,0x0000,
356
+	},
357
+
358
+	// !
359
+	{
360
+	0x0000,0x3C00,0x3C00,0x3C00,
361
+	0x3C00,0x3C00,0x3C00,0x3C00,
362
+	0x3C00,0x3C00,0x0000,0x0000,
363
+	0x3C00,0x3C00,0x3C00,0x0000,
364
+	},
365
+
366
+	// ?
367
+	{
368
+	0x0000,0x7FFE,0x7FFE,0x7FFE,
369
+	0x781E,0x781E,0x79FE,0x79FE,
370
+	0x01E0,0x01E0,0x0000,0x0000,
371
+	0x01E0,0x01E0,0x01E0,0x0000,
372
+	},
373
+
374
+};

src/macros.h → game/src/macros.h View File


src/main.c → game/src/main.c View File

@@ -4,6 +4,7 @@
4 4
 #include "odroid/input.h"
5 5
 #include "odroid/sdcard.h"
6 6
 #include "macros.h"
7
+#include "text.h"
7 8
 #include <esp_log.h>
8 9
 #include <freertos/FreeRTOS.h>
9 10
 #include <freertos/task.h>
@@ -99,6 +100,11 @@ void app_main(void)
99 100
 		lastState = thisState;
100 101
 
101 102
 
103
+		DrawText(gFramebuffer, "The Quick Brown Fox", 19, 0, 5, SWAP_ENDIAN_16(RGB565(0xFF, 0, 0)));
104
+		DrawText(gFramebuffer, "Jumped Over The:", 16, 0, 6, SWAP_ENDIAN_16(RGB565(0, 0xFF, 0)));
105
+		DrawText(gFramebuffer, "Lazy Dog?!", 10, 0, 7, SWAP_ENDIAN_16(RGB565(0, 0, 0xFF)));
106
+
107
+
102 108
 		int spriteRow = 0;
103 109
 		int spriteCol = 0;
104 110
 

src/odroid/audio.c → game/src/odroid/audio.c View File


src/odroid/audio.h → game/src/odroid/audio.h View File


src/odroid/battery.c → game/src/odroid/battery.c View File


src/odroid/battery.h → game/src/odroid/battery.h View File


src/odroid/display.c → game/src/odroid/display.c View File


src/odroid/display.h → game/src/odroid/display.h View File


src/odroid/input.c → game/src/odroid/input.c View File


src/odroid/input.h → game/src/odroid/input.h View File


src/odroid/sdcard.c → game/src/odroid/sdcard.c View File


src/odroid/sdcard.h → game/src/odroid/sdcard.h View File


+ 46
- 0
game/src/text.c View File

@@ -0,0 +1,46 @@
1
+#include "font.h"
2
+#include "odroid/display.h"
3
+#include "text.h"
4
+
5
+
6
+static const int MAX_GLYPHS_PER_ROW = LCD_WIDTH / GLYPH_WIDTH;
7
+static const int MAX_GLYPHS_PER_COL = LCD_HEIGHT / GLYPH_HEIGHT;
8
+
9
+void DrawText(uint16_t* framebuffer, char* string, int length, int x, int y, uint16_t color)
10
+{
11
+	assert(x + length < MAX_GLYPHS_PER_ROW);
12
+	assert(y < MAX_GLYPHS_PER_COL);
13
+
14
+	for (int charIndex = 0; charIndex < length; ++charIndex)
15
+	{
16
+		char c = string[charIndex];
17
+
18
+		if (c == ' ')
19
+		{
20
+			continue;
21
+		}
22
+
23
+		int xStart = GLYPH_WIDTH * (x + charIndex);
24
+		int yStart = GLYPH_HEIGHT * y;
25
+
26
+		for (int row = 0; row < GLYPH_HEIGHT; ++row)
27
+		{
28
+			for (int col = 0; col < GLYPH_WIDTH; ++col)
29
+			{
30
+				int bitPosition = 1U << (15U - col);
31
+				int glyphIndex = GetGlyphIndex(c);
32
+
33
+				uint16_t pixel = glyphMap[glyphIndex][row] & bitPosition;
34
+
35
+				if (pixel)
36
+				{
37
+					int screenX = xStart + col;
38
+					int screenY = yStart + row;
39
+
40
+					framebuffer[screenY * LCD_WIDTH + screenX] = color;
41
+				}
42
+			}
43
+		}
44
+	}
45
+}
46
+

+ 3
- 0
game/src/text.h View File

@@ -0,0 +1,3 @@
1
+
2
+void DrawText(uint16_t* framebuffer, char* string, int length, int tileX, int tileY, uint16_t color);
3
+

+ 8
- 0
tools/CMakeLists.txt View File

@@ -0,0 +1,8 @@
1
+cmake_minimum_required(VERSION 3.5)
2
+
3
+project(tools)
4
+
5
+set(CMAKE_C_FLAGS "-Wall -Werror")
6
+
7
+add_executable(font_generator src/font_generator.c)
8
+

+ 246
- 0
tools/src/font_generator.c View File

@@ -0,0 +1,246 @@
1
+#include <assert.h>
2
+#include <ctype.h>
3
+#include <stdint.h>
4
+#include <stdio.h>
5
+#include <stdlib.h>
6
+#include <string.h>
7
+
8
+
9
+int main(int argc, char** argv)
10
+{
11
+	if (argc != 6)
12
+	{
13
+		fprintf(stderr, "Usage: %s <input image> <layout file> <output header> <glyph width> <glyph height>\n", argv[0]);
14
+
15
+		return 1;
16
+	}
17
+
18
+	const char* inFilename = argv[1];
19
+	const char* layoutFilename = argv[2];
20
+	const char* outFilename = argv[3];
21
+	const int glyphWidth = atoi(argv[4]);
22
+	const int glyphHeight = atoi(argv[5]);
23
+
24
+
25
+	int imageWidth;
26
+	int imageHeight;
27
+	uint8_t* imageBuffer;
28
+	{
29
+		FILE* inFile = fopen(inFilename, "rb");
30
+		assert(inFile);
31
+
32
+		#pragma pack(push,1)
33
+		struct BmpHeader
34
+		{
35
+			char magic[2];
36
+			uint32_t totalSize;
37
+			uint32_t reserved;
38
+			uint32_t offset;
39
+			uint32_t headerSize;
40
+			int32_t width;
41
+			int32_t height;
42
+			uint16_t planes;
43
+			uint16_t depth;
44
+			uint32_t compression;
45
+			uint32_t imageSize;
46
+			int32_t horizontalResolution;
47
+			int32_t verticalResolution;
48
+			uint32_t paletteColorCount;
49
+			uint32_t importantColorcount;
50
+		} bmpHeader;
51
+		#pragma pack(pop)
52
+
53
+		// Read the BMP header so we know where the image data is located
54
+		fread(&bmpHeader, 1, sizeof(bmpHeader), inFile);
55
+		assert(bmpHeader.magic[0] == 'B' && bmpHeader.magic[1] == 'M');
56
+		assert(bmpHeader.depth == 8);
57
+		assert(bmpHeader.headerSize == 40);
58
+
59
+		// Go to location in file of image data
60
+		fseek(inFile, bmpHeader.offset, SEEK_SET);
61
+
62
+		// Read in the image data
63
+		imageBuffer = malloc(bmpHeader.imageSize);
64
+		assert(imageBuffer);
65
+		fread(imageBuffer, 1, bmpHeader.imageSize, inFile);
66
+
67
+		imageWidth = bmpHeader.width;
68
+		imageHeight = bmpHeader.height;
69
+
70
+		fclose(inFile);
71
+	}
72
+
73
+
74
+	char** glyphLayout = NULL;
75
+	int layoutRows = 0;
76
+	{
77
+		FILE* layoutFile = fopen(layoutFilename, "r");
78
+		assert(layoutFile);
79
+
80
+
81
+		// Count the number of lines in the file
82
+		while (!feof(layoutFile))
83
+		{
84
+			char c = fgetc(layoutFile);
85
+
86
+			if (c == '\n')
87
+			{
88
+				++layoutRows;
89
+			}
90
+		}
91
+
92
+
93
+		// Return file position indicator to start
94
+		rewind(layoutFile);
95
+
96
+
97
+		// Allocate enough memory for one string pointer per row
98
+		glyphLayout = malloc(sizeof(*glyphLayout) * layoutRows);
99
+		assert(glyphLayout);
100
+
101
+
102
+		// Read the file into memory
103
+		for (int rowIndex = 0; rowIndex < layoutRows; ++rowIndex)
104
+		{
105
+			char* line = NULL;
106
+			size_t len = 0;
107
+
108
+			getline(&line, &len, layoutFile);
109
+
110
+
111
+			int newlinePosition = strlen(line) - 1;
112
+
113
+			if (line[newlinePosition] == '\n')
114
+			{
115
+				line[newlinePosition] = '\0';
116
+			}
117
+
118
+
119
+			glyphLayout[rowIndex] = line;
120
+		}
121
+
122
+		fclose(layoutFile);
123
+	}
124
+
125
+
126
+	printf("Input: %s\n", inFilename);
127
+	printf("Output: %s\n", outFilename);
128
+	printf("Width: %d\n", imageWidth);
129
+	printf("Height: %d\n", imageHeight);
130
+	printf("Glyph: %dx%d\n\n", glyphWidth, glyphHeight);
131
+
132
+	FILE* outFile = fopen(outFilename, "w");
133
+	assert(outFile);
134
+
135
+
136
+	// Generate the preamble
137
+	{
138
+		fprintf(outFile, "// AUTOMATICALLY GENERATED. DO NOT EDIT.\n");
139
+		fprintf(outFile, "\n");
140
+		fprintf(outFile, "#pragma once\n");
141
+		fprintf(outFile, "\n");
142
+		fprintf(outFile, "#include <assert.h>\n");
143
+		fprintf(outFile, "#include <stdint.h>\n");
144
+		fprintf(outFile, "\n");
145
+		fprintf(outFile, "\n");
146
+		fprintf(outFile, "static const int GLYPH_WIDTH = %d;\n", glyphWidth);
147
+		fprintf(outFile, "static const int GLYPH_HEIGHT = %d;\n", glyphHeight);
148
+		fprintf(outFile, "\n");
149
+		fprintf(outFile, "\n");
150
+	}
151
+
152
+
153
+	// Generate the GetGlyphIndex function
154
+	int glyphCount = 0;
155
+	{
156
+		fprintf(outFile, "int GetGlyphIndex(char c)\n");
157
+		fprintf(outFile, "{\n");
158
+		fprintf(outFile, "	switch (c)\n");
159
+		fprintf(outFile, "	{\n");
160
+
161
+		for (int row = 0; row < layoutRows; ++row)
162
+		{
163
+			int glyphsInRow = strlen(glyphLayout[row]);
164
+
165
+			for (int glyph = 0; glyph < glyphsInRow; ++glyph)
166
+			{
167
+				char c = glyphLayout[row][glyph];
168
+
169
+				fprintf(outFile, "		");
170
+
171
+				if (isalpha(c))
172
+				{
173
+					fprintf(outFile, "case '%c': ", tolower(c));
174
+				}
175
+
176
+				fprintf(outFile, "case '%c': { return %d; break; }\n", c, glyphCount);
177
+
178
+				++glyphCount;
179
+			}
180
+		}
181
+
182
+		fprintf(outFile, "		default: { assert(NULL); break; }\n");
183
+		fprintf(outFile, "	}\n");
184
+		fprintf(outFile, "}\n\n");
185
+	}
186
+
187
+
188
+	// Generate the font map with the calculated glyph bytes
189
+	{
190
+		fprintf(outFile, "static const uint16_t glyphMap[%d][%d] =\n", glyphCount, glyphHeight);
191
+		fprintf(outFile, "{\n");
192
+
193
+		for (int y = 0; y < layoutRows; ++y)
194
+		{
195
+			int glyphsInRow = strlen(glyphLayout[y]);
196
+
197
+			for (int x = 0; x < glyphsInRow; ++x)
198
+			{
199
+				char c = glyphLayout[y][x];
200
+
201
+				fprintf(outFile, "	// %c\n", c);
202
+				fprintf(outFile, "	{\n");
203
+				fprintf(outFile, "	");
204
+
205
+				int count = 0;
206
+
207
+				for (int row = y * glyphHeight; row < (y + 1) * glyphHeight; ++row)
208
+				{
209
+					uint16_t val = 0;
210
+
211
+					for (int col = x * glyphWidth; col < (x + 1) * glyphWidth; ++col)
212
+					{
213
+						// BMP is laid out bottom-to-top, but we want top-to-bottom (0-indexed)
214
+						int y = imageHeight - row - 1;
215
+
216
+						uint8_t pixel = imageBuffer[y * imageWidth + col];
217
+
218
+						int bitPosition = 15 - (col % glyphWidth);
219
+						val |= (pixel << bitPosition);
220
+					}
221
+
222
+					fprintf(outFile, "0x%04X,", val);
223
+					++count;
224
+
225
+					// Put a newline after four values to keep it orderly
226
+					if ((count % 4) == 0)
227
+					{
228
+						fprintf(outFile, "\n");
229
+						fprintf(outFile, "	");
230
+						count = 0;
231
+					}
232
+				}
233
+
234
+				fprintf(outFile, "},\n\n");
235
+			}
236
+		}
237
+
238
+		fprintf(outFile, "};\n");
239
+	}
240
+
241
+	fclose(outFile);
242
+
243
+	printf("DONE\n");
244
+
245
+	return 0;
246
+}

Loading…
Cancel
Save