codepoints loading
There is no browser build of this example yet.
Is it the same as C?
- Desktop:verified The Zig version renders a final frame that is byte-identical to the C example.
- Browser:not checked yet The browser comparison does not cover this example yet.
//! raylib [text] example - codepoints loading
//!
//! Zig-API translation of examples/text/text_codepoints_loading.c (raylib 6.2).
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2022-2025 Ramon Santamaria (@raysan5)
const std = @import("std");
const rl = @import("raylib");
// Text to be displayed, must be UTF-8 (save this code file as UTF-8)
// NOTE: It can contain all the required text for the game,
// this text will be scanned to get all the required codepoints
const text = "いろはにほへと ちりぬるを\nわかよたれそ つねならむ\nうゐのおくやま けふこえて\nあさきゆめみし ゑひもせす";
pub fn main() !void {
const allocator = std.heap.c_allocator;
// Initialization
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [text] example - codepoints loading");
defer rl.closeWindow(); // Close window and OpenGL context
// Convert each utf-8 character into its
// corresponding codepoint in the font file
const codepoints = try rl.loadCodepoints(text);
const codepoint_count = codepoints.len;
// Removed duplicate codepoints to generate smaller font atlas
const codepoints_no_dups = try codepointRemoveDuplicates(allocator, codepoints);
const codepoints_no_dups_count = codepoints_no_dups.len;
rl.unloadCodepoints(codepoints);
// Load font containing all the provided codepoint glyphs
// A texture font atlas is automatically generated
const font = try rl.loadFontEx("resources/DotGothic16-Regular.ttf", 36, codepoints_no_dups);
defer rl.unloadFont(font); // Unload font
// Set bilinear scale filter for better font scaling
rl.setTextureFilter(font.texture, .bilinear);
rl.setTextLineSpacing(20); // Set line spacing for multiline text (when line breaks are included '\n')
// Free codepoints, atlas has already been generated
allocator.free(codepoints_no_dups);
var show_font_atlas = false;
var position: usize = 0; // Byte position in text, moved by codepoints
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
if (rl.isKeyPressed(.space)) show_font_atlas = !show_font_atlas;
// Testing code: getting next and previous codepoints on provided text
if (rl.isKeyPressed(.right) and position < text.len) {
// Get next codepoint in string and move position
position += @intCast(rl.getCodepointNext(text[position..]).size);
} else if (rl.isKeyPressed(.left) and position > 0) {
// Get previous codepoint in string and move position
position -= @intCast(rl.getCodepointPrevious(text[position..]).size);
}
// Draw
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
rl.drawRectangle(0, 0, rl.getScreenWidth(), 70, .black);
rl.drawText(rl.textFormat("Total codepoints contained in provided text: {d}", .{codepoint_count}), 10, 10, 20, .green);
rl.drawText(rl.textFormat("Total codepoints required for font atlas (duplicates excluded): {d}", .{codepoints_no_dups_count}), 10, 40, 20, .green);
if (show_font_atlas) {
// Draw generated font texture atlas containing provided codepoints
rl.drawTexture(font.texture, 150, 100, .black);
rl.drawRectangleLines(150, 100, font.texture.width, font.texture.height, .black);
} else {
// Draw provided text with loaded font, containing all required codepoint glyphs
rl.drawTextEx(font, text, .{ .x = 160, .y = 110 }, 48, 5, .black);
}
rl.drawText("Press SPACE to toggle font atlas view!", 10, rl.getScreenHeight() - 30, 20, .gray);
}
}
/// Remove codepoint duplicates, keeping the first occurrence of each.
/// Caller owns the returned slice.
/// WARNING: This process could be a bit slow if the text to process is very long
fn codepointRemoveDuplicates(allocator: std.mem.Allocator, codepoints: []const i32) ![]i32 {
var unique: std.ArrayList(i32) = try .initCapacity(allocator, codepoints.len);
errdefer unique.deinit(allocator);
for (codepoints) |codepoint| {
if (std.mem.indexOfScalar(i32, unique.items, codepoint) == null) unique.appendAssumeCapacity(codepoint);
}
return unique.toOwnedSlice(allocator);
}/*******************************************************************************************
*
* raylib [text] example - codepoints loading
*
* Example complexity rating: [★★★☆] 3/4
*
* Example originally created with raylib 4.2, last time updated with raylib 4.2
*
* 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) 2022-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include <stdlib.h> // Required for: calloc(), realloc(), free()
#include <string.h> // Required for: memcpy()
// Text to be displayed, must be UTF-8 (save this code file as UTF-8)
// NOTE: It can contain all the required text for the game,
// this text will be scanned to get all the required codepoints
static char *text = "いろはにほへと ちりぬるを\nわかよたれそ つねならむ\nうゐのおくやま けふこえて\nあさきゆめみし ゑひもせす";
//------------------------------------------------------------------------------------
// Module Functions Declaration
//------------------------------------------------------------------------------------
// Remove codepoint duplicates if requested
static int *CodepointRemoveDuplicates(int *codepoints, int codepointCount, int *codepointResultCount);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [text] example - codepoints loading");
// Convert each utf-8 character into its
// corresponding codepoint in the font file
int codepointCount = 0;
int *codepoints = LoadCodepoints(text, &codepointCount);
// Removed duplicate codepoints to generate smaller font atlas
int codepointsNoDupsCount = 0;
int *codepointsNoDups = CodepointRemoveDuplicates(codepoints, codepointCount, &codepointsNoDupsCount);
UnloadCodepoints(codepoints);
// Load font containing all the provided codepoint glyphs
// A texture font atlas is automatically generated
Font font = LoadFontEx("resources/DotGothic16-Regular.ttf", 36, codepointsNoDups, codepointsNoDupsCount);
// Set bilinear scale filter for better font scaling
SetTextureFilter(font.texture, TEXTURE_FILTER_BILINEAR);
SetTextLineSpacing(20); // Set line spacing for multiline text (when line breaks are included '\n')
// Free codepoints, atlas has already been generated
RL_FREE(codepointsNoDups);
bool showFontAtlas = false;
int codepointSize = 0;
char *ptr = text;
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_SPACE)) showFontAtlas = !showFontAtlas;
// Testing code: getting next and previous codepoints on provided text
if (IsKeyPressed(KEY_RIGHT))
{
// Get next codepoint in string and move pointer
GetCodepointNext(ptr, &codepointSize);
ptr += codepointSize;
}
else if (IsKeyPressed(KEY_LEFT))
{
// Get previous codepoint in string and move pointer
GetCodepointPrevious(ptr, &codepointSize);
ptr -= codepointSize;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
DrawRectangle(0, 0, GetScreenWidth(), 70, BLACK);
DrawText(TextFormat("Total codepoints contained in provided text: %i", codepointCount), 10, 10, 20, GREEN);
DrawText(TextFormat("Total codepoints required for font atlas (duplicates excluded): %i", codepointsNoDupsCount), 10, 40, 20, GREEN);
if (showFontAtlas)
{
// Draw generated font texture atlas containing provided codepoints
DrawTexture(font.texture, 150, 100, BLACK);
DrawRectangleLines(150, 100, font.texture.width, font.texture.height, BLACK);
}
else
{
// Draw provided text with loaded font, containing all required codepoint glyphs
DrawTextEx(font, text, (Vector2) { 160, 110 }, 48, 5, BLACK);
}
DrawText("Press SPACE to toggle font atlas view!", 10, GetScreenHeight() - 30, 20, GRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadFont(font); // Unload font
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
//------------------------------------------------------------------------------------
// Module Functions Definition
//------------------------------------------------------------------------------------
// Remove codepoint duplicates if requested
// WARNING: This process could be a bit slow if the text to process is very long
static int *CodepointRemoveDuplicates(int *codepoints, int codepointCount, int *codepointsResultCount)
{
int codepointsNoDupsCount = codepointCount;
int *codepointsNoDups = (int *)RL_CALLOC(codepointCount, sizeof(int));
memcpy(codepointsNoDups, codepoints, codepointCount*sizeof(int));
// Remove duplicates
for (int i = 0; i < codepointsNoDupsCount; i++)
{
for (int j = i + 1; j < codepointsNoDupsCount; j++)
{
if (codepointsNoDups[i] == codepointsNoDups[j])
{
for (int k = j; k < codepointsNoDupsCount - 1; k++) codepointsNoDups[k] = codepointsNoDups[k + 1];
codepointsNoDupsCount--;
j--;
}
}
}
// NOTE: The size of codepointsNoDups is the same as original array but
// only required positions are filled (codepointsNoDupsCount)
*codepointsResultCount = codepointsNoDupsCount;
return codepointsNoDups;
}From raylib 6.2. The original on GitHub.