下面的方式就可以绘制出中文字体,先不说它的问题,我们先看到在游戏窗口看到中文再说。
它的问题是码点(codepoints) 很少 (这东西是什么,后面紧接着就会介绍) ,我只能很少量的中文,比如下面的代码,字体里面只有 6 个码点 ,如果绘制其他内容 "生而为人,我…" 就要创建新的字体,并加载对应的码点才能满足需求。
它的解决办法可能会这样想,缺码点是吧。那我就多加载些,大不了….
可问题在于中文汉字有几万个,把全部中文一次性读入显存显然不是一个很理智的做法。一般来说载入7000常用汉字,但是碰到生僻字依然抓瞎。所以需要一个动态机制,遇到没有的码点时,更新字体。这些都是后话了,我们先来看第一个有问题但是最简洁的例子。

#include <raylib.h>
#include <string>
int main() {
SetWindowState(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI);
InitWindow(1200, 800, "game");
SetTargetFPS(60);
// Get font data from file system to memory
int font_data_size;
unsigned char* font_data =
LoadFileData("path/to/your/zh-ch.ttf", &font_data_size);
// Text to display (Draw)
std::string text = "你好,世界。";
// Convert UTF8 text to unicode
int codepoint_count;
int* codepoints = LoadCodepoints(text.c_str(), &codepoint_count);
// Load Font
Font font = LoadFontFromMemory(".ttf", font_data, font_data_size, 64,
codepoints, codepoint_count);
UnloadCodepoints(codepoints);
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(WHITE);
int fs = 32; // font size
Vector2 pos = {20, 20}; // text position
DrawTextEx(font, text.c_str(), pos, fs, 1, BLACK);
EndDrawing();
}
UnloadFont(font);
CloseWindow();
return 0;
}
UTF-8 是一种针对 Unicode 的可变长字符编码。
UTF-8 specs from <https://www.ietf.org/rfc/rfc3629.txt>
Char. number range | UTF-8 octet sequence
(hexadecimal) | (binary)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
**举个栗子 🌰 :**中文字符 爱
→ Unicode U+7231
→ Unicode 7231 转为二进制 01110010 00110001(共 16 位),然后
→ 按三字节填充,最终的 UTF-8 编码为 为 E7 88 B1 (十六进制显示)
const char* text 里面就是 UTF-8 的二进制编码,可以这样不严谨地简单打印检查一下。

/**
* @brief Load UTF-8 text encoded as codepoints array
*
* @param text
* @param count :point to store codepoint count result
* @return an int array that contains the Unicode of each char of text.
*/
int *LoadCodepoints(const char *text, int *count) {
int textLength = TextLength(text);
int codepointSize = 0;
int codepointCount = 0;
// Allocate a big enough buffer to store as many codepoints as text bytes
int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int));
for (int i = 0; i < textLength; codepointCount++) {
codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize);
i += codepointSize;
}
// Re-allocate buffer to the actual number of codepoints loaded
codepoints = (int *)RL_REALLOC(codepoints, codepointCount * sizeof(int));
*count = codepointCount;
return codepoints;
}
/** @brief Unload codepoints data from memory */
void UnloadCodepoints(int *codepoints) { RL_FREE(codepoints); }
// Get total number of characters(codepoints) in a UTF-8 encoded text, until
// '\\0' is found NOTE: If an invalid UTF-8 sequence is encountered a '?'(0x3f)
// codepoint is counted instead
int GetCodepointCount(const char *text) {
unsigned int length = 0;
const char *ptr = text;
while (*ptr != '\\0') {
int next = 0;
GetCodepointNext(ptr, &next);
ptr += next;
length++;
}
return length;
}
int GetCodepointNext(const char *text, int *codepointSize) {
const char *p = text;
int codepoint = 0x3f; // Codepoint (defaults to '?')
*codepointSize = 1;
// Get current codepoint and bytes processed
if (0xf0 == (0xf8 & p[0])) {
// 4 byte UTF-8 codepoint
if (((p[1] & 0xC0) ^ 0x80) || ((p[2] & 0xC0) ^ 0x80) ||
((p[3] & 0xC0) ^ 0x80)) {
return codepoint;
} // 10xxxxxx checks
codepoint = ((0x07 & p[0]) << 18) | ((0x3f & p[1]) << 12) |
((0x3f & p[2]) << 6) | (0x3f & p[3]);
*codepointSize = 4;
}
else if (0xe0 == (0xf0 & p[0])) {
// 3 byte UTF-8 codepoint */
if (((p[1] & 0xC0) ^ 0x80) || ((p[2] & 0xC0) ^ 0x80)) {
return codepoint;
} // 10xxxxxx checks
codepoint =
((0x0f & p[0]) << 12) | ((0x3f & p[1]) << 6) | (0x3f & p[2]);
*codepointSize = 3;
}
else if (0xc0 == (0xe0 & p[0])) {
// 2 byte UTF-8 codepoint
if ((p[1] & 0xC0) ^ 0x80) {
return codepoint;
} // 10xxxxxx checks
codepoint = ((0x1f & p[0]) << 6) | (0x3f & p[1]);
*codepointSize = 2;
} else if (0x00 == (0x80 & p[0])) {
// 1 byte UTF-8 codepoint
codepoint = p[0];
*codepointSize = 1;
}
return codepoint;
}
FontCache LRU Cache
https://www.cnblogs.com/evencai/p/18842502