|
|
@ -0,0 +1,127 @@ |
|
|
|
#include <stdlib.h> |
|
|
|
#include <raylib.h> |
|
|
|
|
|
|
|
#define SCREEN_WIDTH 800 |
|
|
|
#define SCREEN_HEIGHT 450 |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
int* data; |
|
|
|
int count; |
|
|
|
int capacity; |
|
|
|
} CodepointsArray; |
|
|
|
|
|
|
|
static void AddRange(CodepointsArray* array, int start, int stop) { |
|
|
|
int rangeSize = stop - start + 1; |
|
|
|
|
|
|
|
if (array->count + rangeSize > array->capacity) { |
|
|
|
array->capacity = array->count + rangeSize + 1024; |
|
|
|
array->data = (int*)MemRealloc(array->data, array->capacity * sizeof(int)); |
|
|
|
if (!array->data) { |
|
|
|
TraceLog(LOG_ERROR, "FONTUTIL: Memory allocation failed"); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = start; i <= stop; i++) { |
|
|
|
array->data[array->count++] = i; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Font LoadUnicodeFont(const char* fileName, int fontSize, int textureFilter) { |
|
|
|
CodepointsArray cp = {0}; |
|
|
|
cp.capacity = 2048; |
|
|
|
cp.data = (int*)MemAlloc(cp.capacity * sizeof(int)); |
|
|
|
|
|
|
|
if (!cp.data) { |
|
|
|
TraceLog(LOG_ERROR, "FONTUTIL: Initial allocation failed"); |
|
|
|
return GetFontDefault(); |
|
|
|
} |
|
|
|
|
|
|
|
// Basic ASCII |
|
|
|
AddRange(&cp, 32, 126); |
|
|
|
|
|
|
|
// European Languages |
|
|
|
AddRange(&cp, 0xC0, 0x17F); |
|
|
|
AddRange(&cp, 0x180, 0x24F); |
|
|
|
AddRange(&cp, 0x1E00, 0x1EFF); |
|
|
|
AddRange(&cp, 0x2C60, 0x2C7F); |
|
|
|
|
|
|
|
// Greek |
|
|
|
AddRange(&cp, 0x370, 0x3FF); |
|
|
|
AddRange(&cp, 0x1F00, 0x1FFF); |
|
|
|
|
|
|
|
// Cyrillic |
|
|
|
AddRange(&cp, 0x400, 0x4FF); |
|
|
|
AddRange(&cp, 0x500, 0x52F); |
|
|
|
AddRange(&cp, 0x2DE0, 0x2DFF); |
|
|
|
AddRange(&cp, 0xA640, 0xA69F); |
|
|
|
|
|
|
|
// CJK |
|
|
|
AddRange(&cp, 0x4E00, 0x9FFF); |
|
|
|
AddRange(&cp, 0x3400, 0x4DBF); |
|
|
|
AddRange(&cp, 0x3000, 0x303F); |
|
|
|
AddRange(&cp, 0x3040, 0x309F); |
|
|
|
AddRange(&cp, 0x30A0, 0x30FF); |
|
|
|
AddRange(&cp, 0x31F0, 0x31FF); |
|
|
|
AddRange(&cp, 0xFF00, 0xFFEF); |
|
|
|
AddRange(&cp, 0xAC00, 0xD7AF); |
|
|
|
AddRange(&cp, 0x1100, 0x11FF); |
|
|
|
|
|
|
|
// Other |
|
|
|
AddRange(&cp, 0x900, 0x97F); // Devanagari |
|
|
|
AddRange(&cp, 0x600, 0x6FF); // Arabic |
|
|
|
AddRange(&cp, 0x5D0, 0x5EA); // Hebrew |
|
|
|
|
|
|
|
Font font = {0}; |
|
|
|
|
|
|
|
if (FileExists(fileName)) { |
|
|
|
font = LoadFontEx(fileName, fontSize, cp.data, cp.count); |
|
|
|
} |
|
|
|
|
|
|
|
if (font.texture.id == 0) { |
|
|
|
font = GetFontDefault(); |
|
|
|
TraceLog(LOG_WARNING, "FONTUTIL: Using default font"); |
|
|
|
} |
|
|
|
|
|
|
|
SetTextureFilter(font.texture, textureFilter); |
|
|
|
MemFree(cp.data); |
|
|
|
|
|
|
|
return font; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Main entry point |
|
|
|
*/ |
|
|
|
int main(void) |
|
|
|
{ |
|
|
|
// Initialize window |
|
|
|
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Unicode Font Example"); |
|
|
|
SetTargetFPS(60); |
|
|
|
|
|
|
|
// Load font with Unicode support |
|
|
|
Font myFont = LoadUnicodeFont("resources/NotoSansTC-Regular.ttf", 36, TEXTURE_FILTER_BILINEAR); |
|
|
|
|
|
|
|
// Main render loop |
|
|
|
while (!WindowShouldClose()) |
|
|
|
{ |
|
|
|
BeginDrawing(); |
|
|
|
ClearBackground(RAYWHITE); |
|
|
|
|
|
|
|
// Render test strings in different languages |
|
|
|
DrawTextEx(myFont, "English: Hello World!", (Vector2){50, 50}, 36, 1, DARKGRAY); |
|
|
|
DrawTextEx(myFont, "Русский: Привет мир!", (Vector2){50, 100}, 36, 0, DARKGRAY); |
|
|
|
DrawTextEx(myFont, "中文: 你好世界!", (Vector2){50, 150}, 36, 1, DARKGRAY); |
|
|
|
DrawTextEx(myFont, "日本語: こんにちは世界!", (Vector2){50, 200}, 36, 1, DARKGRAY); |
|
|
|
|
|
|
|
// Display font attribution |
|
|
|
DrawText("Font: Noto Sans TC. License: SIL Open Font License 1.1", |
|
|
|
10, SCREEN_HEIGHT - 20, 10, GRAY); |
|
|
|
EndDrawing(); |
|
|
|
} |
|
|
|
|
|
|
|
// Cleanup resources |
|
|
|
UnloadFont(myFont); |
|
|
|
CloseWindow(); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |