Popcorning Guinea Pig
Search Results for

    Unicode Text Rendering Example

    Unicode example

    This example demonstrates comprehensive Unicode text rendering support in the PopcorningGuineaPig Engine. It showcases multi-language text display using various Unicode scripts including Latin, CJK (Chinese, Japanese, Korean), and emoji characters with proper font loading and rendering.

    Overview

    The Unicode Test example is located in examples/unicode-test/ and demonstrates:

    • Multi-Script Support: English, Chinese, Japanese, Korean text rendering
    • Emoji Rendering: Color emoji support using NotoColorEmoji font
    • Font Loading: Advanced Unicode font loading with extended character ranges
    • Text Rendering: UTF-8 text from a Raylib font atlas built from the codepoints in the strings
    • Font Management: Managing multiple font files for different scripts
    • UI Integration: Unicode text in both labels and interactive buttons

    Key Features

    1. Multi-Language Text Display

    Comprehensive support for various writing systems:

    // English text with Latin font
    englishLabel = new Label("English: Hello World!", 
        new Vector2(50, 50), 20, Color.White, latinFontPath);
    
    // Chinese text with CJK font
    chineseLabel = new Label("中文: 你好世界!", 
        new Vector2(50, 100), 20, Color.Yellow, chineseFontPath);
    
    // Japanese text with appropriate font
    japaneseLabel = new Label("日本語: こんにちは世界!", 
        new Vector2(50, 150), 20, Color.Green, japaneseFontPath);
    
    // Korean text
    koreanLabel = new Label("메인 메뉴", 
        new Vector2(50, 200), 20, Color.SkyBlue, koreanFontPath);
    
    // Emoji support
    emojiLabel = new Label("🌍🎮🚀⭐🎨", 
        new Vector2(50, 250), 24, Color.Pink, emojiFontPath);
    

    2. Font Management System

    Organized font loading for different writing systems:

    public override void Load()
    {
        string baseFontPath = Directory.GetCurrentDirectory();
        
        // Define font paths for different scripts
        string latinFontPath = baseFontPath + "/assets/Roboto-Regular.ttf";
        string emojiFontPath = baseFontPath + "/assets/NotoEmoji-Regular.ttf";
        string chineseFontPath = baseFontPath + "/assets/NotoSansSC-VariableFont_wght.ttf";
        string japaneseFontPath = baseFontPath + "/assets/NotoSansJP-VariableFont_wght.ttf";
        string koreanFontPath = baseFontPath + "/assets/NotoSansKR-VariableFont_wght.ttf";
        
        // Create labels with script-appropriate fonts
        englishLabel = new Label("English: Hello World!", new Vector2(50, 50), 20, Color.White, latinFontPath);
        chineseLabel = new Label("中文: 你好世界!", new Vector2(50, 100), 20, Color.Yellow, chineseFontPath);
        // ... additional labels
    }
    

    3. Advanced Unicode Font Loading

    Comprehensive Unicode character range support:

    private Font LoadFontWithUnicodeSupport(string path)
    {
        if (!File.Exists(path))
        {
            Console.WriteLine($"Font file not found: {path}");
            return Raylib.GetFontDefault();
        }
    
        try
        {
            int fontSize = 32; // Larger size for better glyph quality
            
            unsafe
            {
                // Calculate total codepoints needed
                int totalCodepoints = 
                    (0x7E - 0x20 + 1) +           // ASCII
                    (0x9FFF - 0x4E00 + 1) +       // Chinese CJK
                    (0x309F - 0x3040 + 1) +       // Japanese Hiragana
                    (0x30FF - 0x30A0 + 1) +       // Japanese Katakana
                    (0xD7AF - 0xAC00 + 1);        // Korean Hangul
                
                int[] codepoints = new int[totalCodepoints];
                int index = 0;
                
                // ASCII range (0x20-0x7E)
                for (int i = 0x20; i <= 0x7E; i++)
                    codepoints[index++] = i;
                    
                // Chinese range (0x4E00-0x9FFF) - Common CJK
                for (int i = 0x4E00; i <= 0x9FFF; i++)
                    codepoints[index++] = i;
                    
                // Japanese Hiragana (0x3040-0x309F)
                for (int i = 0x3040; i <= 0x309F; i++)
                    codepoints[index++] = i;
                    
                // Japanese Katakana (0x30A0-0x30FF)
                for (int i = 0x30A0; i <= 0x30FF; i++)
                    codepoints[index++] = i;
                    
                // Korean Hangul (0xAC00-0xD7AF)
                for (int i = 0xAC00; i <= 0xD7AF; i++)
                    codepoints[index++] = i;
                
                // Load font with Unicode ranges
                byte[] pathBytes = Encoding.UTF8.GetBytes(path + '\0');
                
                fixed (int* codepointsPtr = codepoints)
                fixed (byte* pathPtr = pathBytes)
                {
                    var font = Raylib.LoadFontEx((sbyte*)pathPtr, fontSize, codepointsPtr, codepoints.Length);
                    Console.WriteLine($"Successfully loaded font with Unicode support: {path}");
                    return font;
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error loading font '{path}': {ex.Message}");
            return Raylib.GetFontDefault();
        }
    }
    

    4. Interactive Unicode UI Elements

    Unicode text in interactive components:

    // Create button with Chinese text using loaded font
    var chineseFont = LoadFontWithUnicodeSupport(chineseFontPath);
    chineseButton = new Button("中文: 你好世界!", 
        new Vector2(50, 280), 
        new Vector2(150, 25), 
        Color.Purple, 
        chineseFont);
    

    5. Codepoint atlas

    Labels call FontCodepoints.AddText with the string they draw. LoadFontEx bakes that set, and DrawTextEx draws it. A character that was never added draws as ?.

    public override void Render()
    {
        // Title using built-in rendering
        Raylib.DrawText("Unicode Text Rendering Test", 50, 10, 24, Color.White);
        Raylib.DrawText("Using Raylib codepoint atlas", 50, 320, 16, Color.LightGray);
        
        englishLabel?.Draw();
        chineseLabel?.Draw();
        japaneseLabel?.Draw();
        koreanLabel?.Draw();
        emojiLabel?.Draw();
        chineseButton.Draw();
        
        // Instructions
        Raylib.DrawText("Press ESC or close window to exit", 50, 550, 14, Color.Gray);
    }
    

    Font Files and Unicode Coverage

    Included Fonts

    The example includes several high-quality fonts for comprehensive Unicode support:

    • Roboto-Regular.ttf: Western languages (Latin, Cyrillic, Greek)
    • NotoSansSC-VariableFont_wght.ttf: Simplified Chinese
    • NotoSansJP-VariableFont_wght.ttf: Japanese (Hiragana, Katakana, Kanji)
    • NotoSansKR-VariableFont_wght.ttf: Korean (Hangul)
    • NotoEmoji-Regular.ttf: Color emoji support
    • NotoColorEmoji-Regular.ttf: Enhanced color emoji

    Unicode Ranges Supported

    Script Range Description
    ASCII U+0020-U+007E Basic Latin characters
    CJK Unified U+4E00-U+9FFF Common Chinese characters
    Hiragana U+3040-U+309F Japanese phonetic script
    Katakana U+30A0-U+30FF Japanese phonetic script
    Hangul U+AC00-U+D7AF Korean syllabic script
    Emoji Various Unicode emoji characters

    Running the Example

    Prerequisites

    • .NET 10.0 or later
    • PopcorningGuineaPig.Engine reference
    • Raylib-cs package

    Build and Run

    cd examples/unicode-test
    dotnet build
    dotnet run
    

    Project Structure

    unicode-test/
    ├── UnicodeTest.csproj       # Project file
    ├── Program.cs               # Entry point
    ├── UnicodeTest.cs           # Main game implementation
    └── assets/
        ├── Roboto-Regular.ttf                    # Western languages
        ├── NotoEmoji-Regular.ttf                 # Monochrome emoji
        ├── NotoColorEmoji-Regular.ttf            # Color emoji
        ├── NotoSansSC-VariableFont_wght.ttf      # Simplified Chinese
        ├── NotoSansJP-VariableFont_wght.ttf      # Japanese
        └── NotoSansKR-VariableFont_wght.ttf      # Korean
    

    What You'll Learn

    1. Unicode Fundamentals: Understanding character encoding and Unicode ranges
    2. Font Loading: Advanced font loading with custom character ranges
    3. Multi-Script Support: Handling different writing systems in one application
    4. Text Rendering: UTF-8 text from a Raylib codepoint atlas
    5. Font Management: Organizing fonts for different languages
    6. Memory Management: Proper cleanup of font resources
    7. UI Internationalization: Creating multilingual user interfaces

    Technical Details

    Character Range Calculations

    Understanding how Unicode ranges are structured:

    // ASCII printable characters (95 characters)
    int asciiCount = 0x7E - 0x20 + 1;  // 95
    
    // CJK Unified Ideographs (20,992 characters)
    int cjkCount = 0x9FFF - 0x4E00 + 1;  // 20992
    
    // Japanese Hiragana (96 characters)
    int hiraganaCount = 0x309F - 0x3040 + 1;  // 96
    
    // Japanese Katakana (96 characters)
    int katakanaCount = 0x30FF - 0x30A0 + 1;  // 96
    
    // Korean Hangul Syllables (11,172 characters)
    int hangulCount = 0xD7AF - 0xAC00 + 1;  // 11172
    
    // Total: 32,451 characters
    

    Memory Considerations

    Large Unicode fonts require significant memory:

    // Estimate: 32,451 characters × 32px font × ~4 bytes per pixel
    // Approximate memory usage: ~4MB per font
    Console.WriteLine($"Loading font with {codepoints.Length} characters");
    

    Performance Optimization

    Techniques for efficient Unicode text rendering:

    1. Font Caching: Load fonts once and reuse
    2. Selective Loading: Only load needed character ranges
    3. Texture Atlasing: Combine character textures efficiently
    4. Lazy Loading: Load fonts on-demand

    Example Output

    When you run the example, you'll see:

    Unicode Text Rendering Test
    Using Raylib codepoint atlas
    
    English: Hello World!
    中文: 你好世界!
    日本語: こんにちは世界!
    메인 메뉴
    🌍🎮🚀⭐🎨
    
    [Button with Chinese text: 中文: 你好世界!]
    
    Press ESC or close window to exit
    

    Best Practices

    Font Selection

    1. Use Noto Fonts: Google's Noto font family provides excellent Unicode coverage
    2. Variable Fonts: Use variable fonts for better file size optimization
    3. Fallback Fonts: Always provide fallback fonts for missing characters
    4. Test Coverage: Test with actual text in target languages

    Performance

    1. Preload Fonts: Load fonts during initialization, not during rendering
    2. Limit Character Sets: Only load characters you actually need
    3. Font Size Optimization: Use appropriate font sizes for your use case
    4. Memory Management: Dispose of fonts when no longer needed

    Internationalization

    1. Right-to-Left Support: Consider RTL scripts like Arabic and Hebrew
    2. Text Direction: Handle different text directions appropriately
    3. Cultural Considerations: Be aware of cultural differences in text presentation
    4. Testing: Test with native speakers of target languages

    Common Issues and Solutions

    Missing Characters

    Issue: Characters appear as boxes or question marks
    Solution: Ensure font contains the required character ranges
    

    Font Loading Errors

    Issue: Font fails to load with unsafe code
    Solution: Enable unsafe code in project settings
    

    Memory Usage

    Issue: High memory usage with large Unicode fonts
    Solution: Load only required character ranges
    

    Rendering Performance

    Issue: Slow text rendering with complex scripts
    Solution: Use texture caching and batch rendering
    

    Related Documentation

    • Localization - Multi-language application support
    • UI Components - UI elements with Unicode support
    • Asset Registry - Font and asset management
    • Main Menu Example - Practical Unicode implementation

    Next Steps

    After exploring this example, consider:

    1. Add More Languages: Include Arabic, Hebrew, Thai, or other scripts
    2. Dynamic Font Loading: Load fonts based on user language preferences
    3. Text Input: Implement Unicode text input and editing
    4. Localization Integration: Connect with localization systems
    5. Advanced Typography: Add support for complex text layout
    6. Font Substitution: Implement automatic font fallback systems

    This example provides a solid foundation for building truly international applications with comprehensive Unicode support, ensuring your games and applications can reach a global audience with proper text rendering in their native languages.

    • Edit this page
    In this article
    Back to top © 2024 Popcorning Guinea Pig Game Engine. A custom C# game engine for indie developers.