2
0
Эх сурвалжийг харах

REDESIGNED: example: `text_unicode_ranges`

Ray 1 долоо хоног өмнө
parent
commit
0fd5a1a3f5

+ 116 - 102
examples/text/text_unicode_ranges.c

@@ -11,7 +11,7 @@
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
 *
-*   Copyright (c) 2019-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
+*   Copyright (c) 2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
 *
 ********************************************************************************************/
 
@@ -19,20 +19,11 @@
 
 #include <stdlib.h>
 
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-typedef struct {
-    int *data;
-    int count;
-    int capacity;
-} CodepointsArray;
-
 //--------------------------------------------------------------------------------------
 // Module Functions Declaration
 //--------------------------------------------------------------------------------------
-static void AddCodepointRange(CodepointsArray* array, int start, int stop);
-//static Font LoadUnicodeFont(const char* fileName, int fontSize);
+// Add codepoint range to existing font
+static void AddCodepointRange(Font *font, const char *fontPath, int start, int stop);
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -46,9 +37,12 @@ int main(void)
 
     InitWindow(screenWidth, screenHeight, "raylib [text] example - unicode ranges");
 
-    // Load font with Unicode support
-    Font fontUni = LoadUnicodeFont("resources/NotoSansTC-Regular.ttf", 32);
-    SetTextureFilter(fontUni.texture, TEXTURE_FILTER_BILINEAR);
+    // Load font with default Unicode range: Basic ASCII [32-127]
+    Font font = LoadFont("resources/NotoSansTC-Regular.ttf");
+    SetTextureFilter(font.texture, TEXTURE_FILTER_BILINEAR);
+
+    int unicodeRange = 0;           // Track the ranges of codepoints added to font
+    int prevUnicodeRange = 0;       // Previous Unicode range to avoid reloading every frame
 
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
@@ -58,7 +52,76 @@ int main(void)
     {
         // Update
         //----------------------------------------------------------------------------------
-        //...
+        if (unicodeRange != prevUnicodeRange)
+        {
+            UnloadFont(font);
+
+            // Load font with default Unicode range: Basic ASCII [32-127]
+            font = LoadFont("resources/NotoSansTC-Regular.ttf");
+            
+            // Add required ranges to loaded font
+            switch (unicodeRange)
+            {
+                /*
+                case 5:
+                {
+                    // Unicode range: Devanari, Arabic, Hebrew
+                    // WARNING: Glyphs not available on provided font!
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x900, 0x97f);  // Devanagari
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x600, 0x6ff);  // Arabic
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x5d0, 0x5ea);  // Hebrew
+                }
+                */
+                case 4:
+                {
+                    // Unicode range: CJK (Japanese and Chinese)
+                    // WARNING: Loading thousands of codepoints requires lot of time!
+                    // A better strategy is prefilter the required codepoints for the text
+                    // in the game and just load the required ones
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x4e00, 0x9fff);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x3400, 0x4dbf);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x3000, 0x303f);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x3040, 0x309f);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x30A0, 0x30ff);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x31f0, 0x31ff);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0xff00, 0xffef);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0xac00, 0xd7af);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x1100, 0x11ff);
+                }
+                case 3:
+                {
+                    // Unicode range: Cyrillic
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x400, 0x4ff);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x500, 0x52f);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x2de0, 0x2Dff);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0xa640, 0xA69f);
+                }
+                case 2:
+                {
+                    // Unicode range: Greek
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x370, 0x3ff);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x1f00, 0x1fff);
+                }
+                case 1:
+                {
+                    // Unicode range: European Languages
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0xc0, 0x17f);
+                    AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x180, 0x24f);
+                    //AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x1e00, 0x1eff);
+                    //AddCodepointRange(&font, "resources/NotoSansTC-Regular.ttf", 0x2c60, 0x2c7f);
+                }
+                default: break;
+            }
+
+            prevUnicodeRange = unicodeRange;
+        }
+
+        if (IsKeyPressed(KEY_ZERO)) unicodeRange = 0;
+        else if (IsKeyPressed(KEY_ONE)) unicodeRange = 1;
+        else if (IsKeyPressed(KEY_TWO)) unicodeRange = 2;
+        else if (IsKeyPressed(KEY_THREE)) unicodeRange = 3;
+        else if (IsKeyPressed(KEY_FOUR)) unicodeRange = 4;
+        //else if (IsKeyPressed(KEY_FIVE)) unicodeRange = 5;
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -66,22 +129,34 @@ int main(void)
         BeginDrawing();
         
             ClearBackground(RAYWHITE);
+
+            DrawText("ADD CODEPOINTS: 1,2,3,4", 20, 20, 20, MAROON);
             
             // Render test strings in different languages
-            DrawTextEx(fontUni, "English: Hello World!", (Vector2){ 50, 50 }, 32, 1, DARKGRAY); // English
-            DrawTextEx(fontUni, "Español: Hola mundo!", (Vector2){ 50, 100 }, 32, 1, DARKGRAY); // Spanish
-            DrawTextEx(fontUni, "Ελληνικά: Γειά σου κόσμε!", (Vector2){ 50, 150 }, 32, 1, DARKGRAY); // Greek
-            DrawTextEx(fontUni, "Русский: Привет мир!", (Vector2){ 50, 200 }, 32, 0, DARKGRAY); // Russian
-            DrawTextEx(fontUni, "中文: 你好世界!", (Vector2){ 50, 250 }, 32, 1, DARKGRAY);        // Chinese
-            DrawTextEx(fontUni, "日本語: こんにちは世界!", (Vector2){ 50, 300 }, 32, 1, DARKGRAY);   // Japanese
-            DrawTextEx(fontUni, "देवनागरी: होला मुंडो!", (Vector2){ 50, 350 }, 32, 1, DARKGRAY);     // Devanagari
+            DrawTextEx(font, "> English: Hello World!", (Vector2){ 50, 70 }, 32, 1, DARKGRAY); // English
+            DrawTextEx(font, "> Español: Hola mundo!", (Vector2){ 50, 120 }, 32, 1, DARKGRAY); // Spanish
+            DrawTextEx(font, "> Ελληνικά: Γειά σου κόσμε!", (Vector2){ 50, 170 }, 32, 1, DARKGRAY); // Greek
+            DrawTextEx(font, "> Русский: Привет мир!", (Vector2){ 50, 220 }, 32, 0, DARKGRAY); // Russian
+            DrawTextEx(font, "> 中文: 你好世界!", (Vector2){ 50, 270 }, 32, 1, DARKGRAY);        // Chinese
+            DrawTextEx(font, "> 日本語: こんにちは世界!", (Vector2){ 50, 320 }, 32, 1, DARKGRAY); // Japanese
+            //DrawTextEx(font, "देवनागरी: होला मुंडो!", (Vector2){ 50, 350 }, 32, 1, DARKGRAY);     // Devanagari (glyphs not available in font)
             
+            // Draw font texture scaled to screen
             DrawRectangle(400, 16, 380, 400, BLACK);
-            DrawTexturePro(fontUni.texture, (Rectangle){ 0, 0, fontUni.texture.width, fontUni.texture.height },
-                (Rectangle){ 400, 16, 380, 400 }, (Vector2){ 0, 0 }, 0.0f, WHITE);
+            DrawTexturePro(font.texture, (Rectangle){ 0, 0, font.texture.width, font.texture.height },
+                (Rectangle){ 400, 16, font.texture.width*0.5f, font.texture.height*0.5f }, (Vector2){ 0, 0 }, 0.0f, WHITE);
+
+            DrawText(TextFormat("ATLAS SIZE: %ix%i px", font.texture.width, font.texture.height), 20, 380, 20, BLUE);
 
             // Display font attribution
             DrawText("Font: Noto Sans TC. License: SIL Open Font License 1.1", screenWidth - 300, screenHeight - 20, 10, GRAY);
+
+            if (prevUnicodeRange != unicodeRange)
+            {
+                DrawRectangle(0, 0, screenWidth, screenHeight, Fade(WHITE, 0.8f));
+                DrawRectangle(0, 125, screenWidth, 200, GRAY);
+                DrawText("LOADING CODEPOINTS...", 150, 210, 40, BLACK);
+            }
             
         EndDrawing();
         //----------------------------------------------------------------------------------
@@ -89,7 +164,7 @@ int main(void)
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    UnloadFont(fontUni);        // Unload font resource
+    UnloadFont(font);        // Unload font resource
 
     CloseWindow();              // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
@@ -100,87 +175,26 @@ int main(void)
 //--------------------------------------------------------------------------------------
 // Module Functions Definition
 //--------------------------------------------------------------------------------------
-static void AddRange(CodepointsArray* array, int start, int stop)
+// Add codepoint range to existing font
+static void AddCodepointRange(Font *font, const char *fontPath, int start, int stop)
 {
     int rangeSize = stop - start + 1;
+    int currentRangeSize = font->glyphCount;
     
-    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);
-        }
-    }
+    // TODO: Load glyphs from provided vector font (if available),
+    // add them to existing font, regenerating font image and texture
     
-    for (int i = start; i <= stop; i++) array->data[array->count++] = i;
-}
+    int updatedCodepointCount = currentRangeSize + rangeSize;
+    int *updatedCodepoints = (int *)RL_CALLOC(updatedCodepointCount, sizeof(int));
 
-Font LoadUnicodeFont(const char *fileName, int fontSize)
-{
-    CodepointsArray cp = { 0 };
-    cp.capacity = 2048;
-    cp.data = (int *)MemAlloc(cp.capacity*sizeof(int));
+    // Get current codepoint list
+    for (int i = 0; i < currentRangeSize; i++) updatedCodepoints[i] = font->glyphs[i].value;
 
-    if (!cp.data)
-    {
-        TraceLog(LOG_ERROR, "FONTUTIL: Initial allocation failed");
-        return GetFontDefault();
-    }
-
-    // Unicode range: Basic ASCII
-    AddRange(&cp, 32, 126);
-
-    // Unicode range: European Languages
-    AddRange(&cp, 0xC0, 0x17F);
-    AddRange(&cp, 0x180, 0x24F);
-    AddRange(&cp, 0x1E00, 0x1EFF);
-    AddRange(&cp, 0x2C60, 0x2C7F);
-
-    // Unicode range: Greek
-    AddRange(&cp, 0x370, 0x3FF);
-    AddRange(&cp, 0x1F00, 0x1FFF);
-
-    // Unicode range: Cyrillic
-    AddRange(&cp, 0x400, 0x4FF);
-    AddRange(&cp, 0x500, 0x52F);
-    AddRange(&cp, 0x2DE0, 0x2DFF);
-    AddRange(&cp, 0xA640, 0xA69F);
-
-    // Unicode range: 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);
-
-    // Unicode range: Other
-    // WARNING: Not available on provided font
-    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");
-    }
+    // Add new codepoints to list (provided range)
+    for (int i = currentRangeSize; i < updatedCodepointCount; i++)
+        updatedCodepoints[i] = start + (i - currentRangeSize);
 
-    MemFree(cp.data);
-    
-    return font;
+    UnloadFont(*font);
+    *font = LoadFontEx(fontPath, 32, updatedCodepoints, updatedCodepointCount);
 }
+