mirror of
https://github.com/raysan5/raylib.git
synced 2025-09-05 19:08:13 +00:00
204 lines
10 KiB
C
204 lines
10 KiB
C
/*******************************************************************************************
|
||
*
|
||
* raylib [text] example - unicode ranges
|
||
*
|
||
* Example complexity rating: [★★★★] 4/4
|
||
*
|
||
* Example originally created with raylib 2.5, last time updated with raylib 4.0
|
||
*
|
||
* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
|
||
*
|
||
* 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) 2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
|
||
*
|
||
********************************************************************************************/
|
||
|
||
#include "raylib.h"
|
||
|
||
#include <stdlib.h>
|
||
|
||
//--------------------------------------------------------------------------------------
|
||
// Module Functions Declaration
|
||
//--------------------------------------------------------------------------------------
|
||
// Add codepoint range to existing font
|
||
static void AddCodepointRange(Font *font, const char *fontPath, int start, int stop);
|
||
|
||
//------------------------------------------------------------------------------------
|
||
// Program main entry point
|
||
//------------------------------------------------------------------------------------
|
||
int main(void)
|
||
{
|
||
// Initialization
|
||
//--------------------------------------------------------------------------------------
|
||
const int screenWidth = 800;
|
||
const int screenHeight = 450;
|
||
|
||
InitWindow(screenWidth, screenHeight, "raylib [text] example - unicode ranges");
|
||
|
||
// 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
|
||
//--------------------------------------------------------------------------------------
|
||
|
||
// Main loop
|
||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||
{
|
||
// 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;
|
||
SetTextureFilter(font.texture, TEXTURE_FILTER_BILINEAR); // Set font atlas scale filter
|
||
}
|
||
|
||
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
|
||
//----------------------------------------------------------------------------------
|
||
BeginDrawing();
|
||
|
||
ClearBackground(RAYWHITE);
|
||
|
||
DrawText("ADD CODEPOINTS: [1][2][3][4]", 20, 20, 20, MAROON);
|
||
|
||
// Render test strings in different languages
|
||
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
|
||
float atlasScale = 380.0f/font.texture.width;
|
||
DrawRectangle(400, 16, font.texture.width*atlasScale, font.texture.height*atlasScale, BLACK);
|
||
DrawTexturePro(font.texture, (Rectangle){ 0, 0, font.texture.width, font.texture.height },
|
||
(Rectangle){ 400, 16, font.texture.width*atlasScale, font.texture.height*atlasScale }, (Vector2){ 0, 0 }, 0.0f, WHITE);
|
||
DrawRectangleLines(400, 16, 380, 380, RED);
|
||
|
||
DrawText(TextFormat("ATLAS SIZE: %ix%i px (x%02.2f)", font.texture.width, font.texture.height, atlasScale), 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();
|
||
//----------------------------------------------------------------------------------
|
||
}
|
||
|
||
// De-Initialization
|
||
//--------------------------------------------------------------------------------------
|
||
UnloadFont(font); // Unload font resource
|
||
|
||
CloseWindow(); // Close window and OpenGL context
|
||
//--------------------------------------------------------------------------------------
|
||
|
||
return 0;
|
||
}
|
||
|
||
//--------------------------------------------------------------------------------------
|
||
// Module Functions Definition
|
||
//--------------------------------------------------------------------------------------
|
||
// 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;
|
||
|
||
// TODO: Load glyphs from provided vector font (if available),
|
||
// add them to existing font, regenerating font image and texture
|
||
|
||
int updatedCodepointCount = currentRangeSize + rangeSize;
|
||
int *updatedCodepoints = (int *)RL_CALLOC(updatedCodepointCount, sizeof(int));
|
||
|
||
// Get current codepoint list
|
||
for (int i = 0; i < currentRangeSize; i++) updatedCodepoints[i] = font->glyphs[i].value;
|
||
|
||
// Add new codepoints to list (provided range)
|
||
for (int i = currentRangeSize; i < updatedCodepointCount; i++)
|
||
updatedCodepoints[i] = start + (i - currentRangeSize);
|
||
|
||
UnloadFont(*font);
|
||
*font = LoadFontEx(fontPath, 32, updatedCodepoints, updatedCodepointCount);
|
||
}
|
||
|