|
4 | 4 |
|
5 | 5 | #define SCREEN_WIDTH 800
|
6 | 6 | #define SCREEN_HEIGHT 450
|
| 7 | +#define INITIAL_CAPACITY 65536 // 2^16 - sufficient for most Unicode BMP characters |
7 | 8 |
|
8 |
| -Font LoadUnicodeFont(const char* fileName, int fontSize, int textureFilter) |
| 9 | + |
| 10 | +static int AddCodeRange(int* codePoints, int* count, int start, int stop) |
9 | 11 | {
|
10 |
| - int* cp = NULL; // Array to store Unicode codepoints |
11 |
| - int capacity = 65536; // Initial capacity |
12 |
| - int count = 0; // Counter for codepoints |
13 |
| - |
14 |
| - // Allocate initial array |
15 |
| - cp = (int*)malloc(capacity * sizeof(int)); |
16 |
| - if (!cp) return GetFontDefault(); |
17 |
| - |
18 |
| - // Helper function to add a range of Unicode codepoints |
19 |
| - void AddRange(int start, int stop) |
20 |
| - { |
21 |
| - while (start <= stop) |
22 |
| - { |
23 |
| - // Expand array if needed |
24 |
| - if (count >= capacity) |
25 |
| - { |
26 |
| - capacity += 1024; |
27 |
| - int* newCp = (int*)realloc(cp, capacity * sizeof(int)); |
28 |
| - if (!newCp) |
29 |
| - { |
30 |
| - free(cp); |
31 |
| - return GetFontDefault(); |
32 |
| - } |
33 |
| - cp = newCp; |
34 |
| - } |
35 |
| - |
36 |
| - // Add current codepoint and increment |
37 |
| - cp[count] = start; |
38 |
| - count++; |
39 |
| - start++; |
40 |
| - } |
| 12 | + // Verify we have enough capacity for this range |
| 13 | + if (*count + (stop - start + 1) > INITIAL_CAPACITY) { |
| 14 | + return 0; // Not enough space |
| 15 | + } |
| 16 | + |
| 17 | + // Add all code points in the range |
| 18 | + while (start <= stop) { |
| 19 | + codePoints[*count] = start; |
| 20 | + (*count)++; |
| 21 | + start++; |
41 | 22 | }
|
| 23 | + return 1; // Success |
| 24 | +} |
| 25 | + |
| 26 | +Font LoadUnicodeFont(const char* fileName, int fontSize, int textureFilter) |
| 27 | +{ |
| 28 | + // Allocate memory for code points (fixed size - no reallocation needed) |
| 29 | + int* codePoints = (int*)malloc(INITIAL_CAPACITY * sizeof(int)); |
| 30 | + if (!codePoints) return GetFontDefault(); |
42 | 31 |
|
| 32 | + int count = 0; // Tracks number of added code points |
| 33 | + |
43 | 34 | // --------------------------------------------------
|
44 | 35 | // 1. BASIC ASCII CHARACTERS
|
45 | 36 | // --------------------------------------------------
|
46 |
| - AddRange(32, 126); // Basic Latin (letters, digits, punctuation) |
| 37 | + AddCodeRange(codePoints, &count, 32, 126); // Basic Latin (letters, digits, punctuation) |
47 | 38 |
|
48 | 39 | // --------------------------------------------------
|
49 | 40 | // 2. EUROPEAN LANGUAGES (LATIN SCRIPT)
|
50 | 41 | // --------------------------------------------------
|
51 |
| - AddRange(0xC0, 0x17F); // Latin-1 Supplement + Latin Extended-A |
52 |
| - AddRange(0x180, 0x24F); // Latin Extended-B |
53 |
| - AddRange(0x1E00, 0x1EFF); // Latin Extended Additional |
54 |
| - AddRange(0x2C60, 0x2C7F); // Latin Extended-C |
| 42 | + AddCodeRange(codePoints, &count, 0xC0, 0x17F); // Latin-1 Supplement + Latin Extended-A |
| 43 | + AddCodeRange(codePoints, &count, 0x180, 0x24F); // Latin Extended-B |
| 44 | + AddCodeRange(codePoints, &count, 0x1E00, 0x1EFF); // Latin Extended Additional |
| 45 | + AddCodeRange(codePoints, &count, 0x2C60, 0x2C7F); // Latin Extended-C |
55 | 46 |
|
56 | 47 | // --------------------------------------------------
|
57 | 48 | // 3. GREEK AND COPTIC
|
58 | 49 | // --------------------------------------------------
|
59 |
| - AddRange(0x370, 0x3FF); // Greek and Coptic |
60 |
| - AddRange(0x1F00, 0x1FFF); // Greek Extended |
| 50 | + AddCodeRange(codePoints, &count, 0x370, 0x3FF); // Greek and Coptic |
| 51 | + AddCodeRange(codePoints, &count, 0x1F00, 0x1FFF); // Greek Extended |
61 | 52 |
|
62 | 53 | // --------------------------------------------------
|
63 | 54 | // 4. CYRILLIC SCRIPTS
|
64 | 55 | // --------------------------------------------------
|
65 |
| - AddRange(0x400, 0x4FF); // Basic Cyrillic |
66 |
| - AddRange(0x500, 0x52F); // Cyrillic Supplement |
67 |
| - AddRange(0x2DE0, 0x2DFF); // Cyrillic Extended-A |
68 |
| - AddRange(0xA640, 0xA69F); // Cyrillic Extended-B |
| 56 | + AddCodeRange(codePoints, &count, 0x400, 0x4FF); // Basic Cyrillic |
| 57 | + AddCodeRange(codePoints, &count, 0x500, 0x52F); // Cyrillic Supplement |
| 58 | + AddCodeRange(codePoints, &count, 0x2DE0, 0x2DFF); // Cyrillic Extended-A |
| 59 | + AddCodeRange(codePoints, &count, 0xA640, 0xA69F); // Cyrillic Extended-B |
69 | 60 |
|
70 | 61 | // --------------------------------------------------
|
71 | 62 | // 5. CJK LANGUAGES (CHINESE, JAPANESE, KOREAN)
|
72 | 63 | // --------------------------------------------------
|
73 |
| - AddRange(0x4E00, 0x9FFF); // CJK Unified Ideographs |
74 |
| - AddRange(0x3400, 0x4DBF); // CJK Extension A |
75 |
| - AddRange(0x3000, 0x303F); // CJK Symbols and Punctuation |
76 |
| - AddRange(0x3040, 0x309F); // Hiragana (Japanese) |
77 |
| - AddRange(0x30A0, 0x30FF); // Katakana (Japanese) |
78 |
| - AddRange(0x31F0, 0x31FF); // Katakana Phonetic Extensions |
79 |
| - AddRange(0xFF00, 0xFFEF); // Halfwidth and Fullwidth Forms |
80 |
| - AddRange(0xAC00, 0xD7AF); // Hangul Syllables (Korean) |
81 |
| - AddRange(0x1100, 0x11FF); // Hangul Jamo |
| 64 | + AddCodeRange(codePoints, &count, 0x4E00, 0x9FFF); // CJK Unified Ideographs |
| 65 | + AddCodeRange(codePoints, &count, 0x3400, 0x4DBF); // CJK Extension A |
| 66 | + AddCodeRange(codePoints, &count, 0x3000, 0x303F); // CJK Symbols and Punctuation |
| 67 | + AddCodeRange(codePoints, &count, 0x3040, 0x309F); // Hiragana (Japanese) |
| 68 | + AddCodeRange(codePoints, &count, 0x30A0, 0x30FF); // Katakana (Japanese) |
| 69 | + AddCodeRange(codePoints, &count, 0x31F0, 0x31FF); // Katakana Phonetic Extensions |
| 70 | + AddCodeRange(codePoints, &count, 0xFF00, 0xFFEF); // Halfwidth and Fullwidth Forms |
| 71 | + AddCodeRange(codePoints, &count, 0xAC00, 0xD7AF); // Hangul Syllables (Korean) |
| 72 | + AddCodeRange(codePoints, &count, 0x1100, 0x11FF); // Hangul Jamo |
82 | 73 |
|
83 | 74 | // --------------------------------------------------
|
84 | 75 | // 6. SOUTHEAST ASIAN LANGUAGES
|
85 | 76 | // --------------------------------------------------
|
86 |
| - AddRange(0x0E00, 0x0E7F); // Thai |
87 |
| - AddRange(0x0E80, 0x0EFF); // Lao |
88 |
| - AddRange(0x1780, 0x17FF); // Khmer |
89 |
| - AddRange(0x1000, 0x109F); // Myanmar |
90 |
| - AddRange(0x1980, 0x19DF); // New Tai Lue |
| 77 | + AddCodeRange(codePoints, &count, 0x0E00, 0x0E7F); // Thai |
| 78 | + AddCodeRange(codePoints, &count, 0x0E80, 0x0EFF); // Lao |
| 79 | + AddCodeRange(codePoints, &count, 0x1780, 0x17FF); // Khmer |
| 80 | + AddCodeRange(codePoints, &count, 0x1000, 0x109F); // Myanmar |
| 81 | + AddCodeRange(codePoints, &count, 0x1980, 0x19DF); // New Tai Lue |
91 | 82 |
|
92 | 83 | // --------------------------------------------------
|
93 | 84 | // 7. INDIAN SUBCONTINENT LANGUAGES
|
94 | 85 | // --------------------------------------------------
|
95 |
| - AddRange(0x900, 0x97F); // Devanagari (Hindi, Sanskrit) |
96 |
| - AddRange(0x980, 0x9FF); // Bengali |
97 |
| - AddRange(0xA00, 0xA7F); // Gurmukhi (Punjabi) |
98 |
| - AddRange(0xA80, 0xAFF); // Gujarati |
99 |
| - AddRange(0xB00, 0xB7F); // Oriya |
100 |
| - AddRange(0xB80, 0xBFF); // Tamil |
101 |
| - AddRange(0xC00, 0xC7F); // Telugu |
102 |
| - AddRange(0xC80, 0xCFF); // Kannada |
103 |
| - AddRange(0xD00, 0xD7F); // Malayalam |
104 |
| - AddRange(0xD80, 0xDFF); // Sinhala |
| 86 | + AddCodeRange(codePoints, &count, 0x900, 0x97F); // Devanagari (Hindi, Sanskrit) |
| 87 | + AddCodeRange(codePoints, &count, 0x980, 0x9FF); // Bengali |
| 88 | + AddCodeRange(codePoints, &count, 0xA00, 0xA7F); // Gurmukhi (Punjabi) |
| 89 | + AddCodeRange(codePoints, &count, 0xA80, 0xAFF); // Gujarati |
| 90 | + AddCodeRange(codePoints, &count, 0xB00, 0xB7F); // Oriya |
| 91 | + AddCodeRange(codePoints, &count, 0xB80, 0xBFF); // Tamil |
| 92 | + AddCodeRange(codePoints, &count, 0xC00, 0xC7F); // Telugu |
| 93 | + AddCodeRange(codePoints, &count, 0xC80, 0xCFF); // Kannada |
| 94 | + AddCodeRange(codePoints, &count, 0xD00, 0xD7F); // Malayalam |
| 95 | + AddCodeRange(codePoints, &count, 0xD80, 0xDFF); // Sinhala |
105 | 96 |
|
106 | 97 | // --------------------------------------------------
|
107 | 98 | // 8. MIDDLE EASTERN LANGUAGES
|
108 | 99 | // --------------------------------------------------
|
109 |
| - AddRange(0x600, 0x6FF); // Arabic |
110 |
| - AddRange(0x750, 0x77F); // Arabic Supplement |
111 |
| - AddRange(0x8A0, 0x8FF); // Arabic Extended-A |
112 |
| - AddRange(0xFB50, 0xFDFF); // Arabic Presentation Forms-A |
113 |
| - AddRange(0x5D0, 0x5EA); // Hebrew |
114 |
| - AddRange(0x591, 0x5C7); // Hebrew Extended |
115 |
| - AddRange(0x7C0, 0x7FF); // N'Ko |
116 |
| - AddRange(0x640, 0x6FF); // Syriac |
| 100 | + AddCodeRange(codePoints, &count, 0x600, 0x6FF); // Arabic |
| 101 | + AddCodeRange(codePoints, &count, 0x750, 0x77F); // Arabic Supplement |
| 102 | + AddCodeRange(codePoints, &count, 0x8A0, 0x8FF); // Arabic Extended-A |
| 103 | + AddCodeRange(codePoints, &count, 0xFB50, 0xFDFF); // Arabic Presentation Forms-A |
| 104 | + AddCodeRange(codePoints, &count, 0x5D0, 0x5EA); // Hebrew |
| 105 | + AddCodeRange(codePoints, &count, 0x591, 0x5C7); // Hebrew Extended |
| 106 | + AddCodeRange(codePoints, &count, 0x7C0, 0x7FF); // N'Ko |
| 107 | + AddCodeRange(codePoints, &count, 0x640, 0x6FF); // Syriac |
117 | 108 |
|
118 | 109 | // --------------------------------------------------
|
119 | 110 | // 9. AFRICAN LANGUAGES
|
120 | 111 | // --------------------------------------------------
|
121 |
| - AddRange(0x2C80, 0x2CFF); // Coptic |
122 |
| - AddRange(0x2D30, 0x2D7F); // Tifinagh |
123 |
| - AddRange(0xA6A0, 0xA6FF); // Bamum |
124 |
| - AddRange(0xAB00, 0xAB2F); // Ethiopic Extended |
| 112 | + AddCodeRange(codePoints, &count, 0x2C80, 0x2CFF); // Coptic |
| 113 | + AddCodeRange(codePoints, &count, 0x2D30, 0x2D7F); // Tifinagh |
| 114 | + AddCodeRange(codePoints, &count, 0xA6A0, 0xA6FF); // Bamum |
| 115 | + AddCodeRange(codePoints, &count, 0xAB00, 0xAB2F); // Ethiopic Extended |
125 | 116 |
|
126 | 117 | // --------------------------------------------------
|
127 | 118 | // 10. SPECIAL CHARACTERS AND SYMBOLS
|
128 | 119 | // --------------------------------------------------
|
129 |
| - AddRange(0x300, 0x36F); // Combining Diacritical Marks |
130 |
| - AddRange(0x1DC0, 0x1DFF); // Combining Diacritical Marks Supplement |
131 |
| - AddRange(0x2000, 0x206F); // General Punctuation |
132 |
| - AddRange(0x20A0, 0x20CF); // Currency Symbols |
133 |
| - AddRange(0x2100, 0x214F); // Letterlike Symbols |
134 |
| - AddRange(0x2190, 0x21FF); // Arrows |
135 |
| - AddRange(0x2200, 0x22FF); // Mathematical Operators |
| 120 | + AddCodeRange(codePoints, &count, 0x300, 0x36F); // Combining Diacritical Marks |
| 121 | + AddCodeRange(codePoints, &count, 0x1DC0, 0x1DFF); // Combining Diacritical Marks Supplement |
| 122 | + AddCodeRange(codePoints, &count, 0x2000, 0x206F); // General Punctuation |
| 123 | + AddCodeRange(codePoints, &count, 0x20A0, 0x20CF); // Currency Symbols |
| 124 | + AddCodeRange(codePoints, &count, 0x2100, 0x214F); // Letterlike Symbols |
| 125 | + AddCodeRange(codePoints, &count, 0x2190, 0x21FF); // Arrows |
| 126 | + AddCodeRange(codePoints, &count, 0x2200, 0x22FF); // Mathematical Operators |
136 | 127 |
|
137 |
| - |
138 | 128 | Font result = {0};
|
139 | 129 |
|
140 |
| - if (FileExists(fileName)) |
141 |
| - result = LoadFontEx(fileName, fontSize, cp, count); |
| 130 | + // Attempt to load the font with collected code points |
| 131 | + if (FileExists(fileName)) { |
| 132 | + result = LoadFontEx(fileName, fontSize, codePoints, count); |
| 133 | + } |
142 | 134 |
|
143 |
| - if (result.texture.id == 0) |
| 135 | + // Fallback to default font if loading fails |
| 136 | + if (result.texture.id == 0) { |
144 | 137 | result = GetFontDefault();
|
| 138 | + } |
145 | 139 |
|
| 140 | + // Apply texture filtering |
146 | 141 | SetTextureFilter(result.texture, textureFilter);
|
147 |
| - free(cp); |
| 142 | + |
| 143 | + // Clean up |
| 144 | + free(codePoints); |
148 | 145 | return result;
|
149 | 146 | }
|
150 | 147 |
|
| 148 | +/** |
| 149 | + * Main entry point |
| 150 | + */ |
151 | 151 | int main(void)
|
152 | 152 | {
|
153 |
| - // Initialization |
| 153 | + // Initialize window |
154 | 154 | InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Unicode Font Example");
|
155 | 155 | SetTargetFPS(60);
|
156 | 156 |
|
157 | 157 | // Load font with Unicode support
|
158 | 158 | Font myFont = LoadUnicodeFont("resources/NotoSansTC-Regular.ttf", 36, TEXTURE_FILTER_BILINEAR);
|
159 | 159 |
|
160 |
| - // Main game loop |
| 160 | + // Main render loop |
161 | 161 | while (!WindowShouldClose())
|
162 | 162 | {
|
163 | 163 | BeginDrawing();
|
164 | 164 | ClearBackground(RAYWHITE);
|
165 | 165 |
|
166 |
| - // Draw text |
| 166 | + // Render test strings in different languages |
167 | 167 | DrawTextEx(myFont, "English: Hello World!", (Vector2){50, 50}, 36, 1, DARKGRAY);
|
168 | 168 | DrawTextEx(myFont, "Русский: Привет мир!", (Vector2){50, 100}, 36, 0, DARKGRAY);
|
169 | 169 | DrawTextEx(myFont, "中文: 你好世界!", (Vector2){50, 150}, 36, 1, DARKGRAY);
|
170 | 170 | DrawTextEx(myFont, "日本語: こんにちは世界!", (Vector2){50, 200}, 36, 1, DARKGRAY);
|
171 | 171 |
|
172 |
| - |
173 |
| - DrawText("Font: Noto Sans TC Thin. © 2014-2020 Adobe(http://www.adobe.com/). License: SIL Open Font License 1.1", 10, SCREEN_HEIGHT - 20, 10, GRAY); |
174 |
| - |
| 172 | + // Display font attribution |
| 173 | + DrawText("Font: Noto Sans TC. License: SIL Open Font License 1.1", |
| 174 | + 10, SCREEN_HEIGHT - 20, 10, GRAY); |
175 | 175 | EndDrawing();
|
176 | 176 | }
|
177 | 177 |
|
178 |
| - // Cleanup |
| 178 | + // Cleanup resources |
179 | 179 | UnloadFont(myFont);
|
180 | 180 | CloseWindow();
|
181 | 181 |
|
|
0 commit comments