Quản Lý Font Chữ Động Trong Hệ Thống Render Game - nói dối e blog

Quản Lý Font Chữ Động Trong Hệ Thống Render Game

Trong bài viết trước, tôi đã chia sẻ về thiết kế module giao diện người dùng (UI) và một trong những thách thức cốt lõi khi triển khai module này chính là bài toán render chữ. Khác với hệ thống chữ viết phương Tây chỉ gồm vài chục ký tự, bảng chữ Hán với hàng vạn ký tự khiến việc nướng toàn bộ glyph vào texture trở nên thiếu hiệu quả. Phương pháp lưu trữ tĩnh chỉ phù hợp với các dự án sử dụng giới hạn font chữ, nhưng với các ứng dụng đa dạng font như game mobile hiện đại, chúng ta cần một giải pháp linh hoạt hơn.

Trong quá trình phát triển engine ejoy2d, tôi đã thiết kế một hệ thống quản lý font chữ động. Phiên bản đầu tiên tuy hoạt động được nhưng còn nhiều hạn chế về hiệu năng. Gần đây, tôi đã tái thiết kế lại hệ thống này với những cải tiến đột phá:

1. Chuyển đổi sang công nghệ SDF (Signed Distance Field)

Thay vì phải quản lý nhiều kích thước glyph trên texture như trước, việc sử dụng SDF cho phép chúng ta render chữ ở mọi kích thước chỉ với một glyph duy nhất. Điều này giúp giảm đáng kể việc sử dụng tài nguyên texture và đơn giản hóa quy trình quản lý.

2. Thiết kế layout texture thông minh

Nhận thấy đặc điểm chiều rộng đồng nhất của chữ Hán, tôi đã thiết kế cơ chế chia vùng texture thành các ô vuông cố định có cùng chiều rộng và chiều cao. Cách tiếp cận này giúp:

  • Tránh sử dụng thuật toán đóng thùng phức tạp
  • Tối ưu hóa không gian lưu trữ
  • Dễ dàng mở rộng khi cần

3. Giao diện API linh hoạt

Hệ thống mới cung cấp tập hợp API C sau:

1
2
3
4
5
6
7
8
void font_manager_init(struct font_manager *);
int font_manager_addfont(struct font_manager *, const void *ttfbuffer);
int font_manager_rebindfont(struct font_manager *, int fontid, const void *ttfbuffer);
void font_manager_fontheight(struct font_manager *F, int fontid, int size, int *ascent, int *descent, int *lineGap);
int font_manager_touch(struct font_manager *, int font, int codepoint, struct font_glyph *);
const char * font_manager_update(struct font_manager *, int font, int codepoint, struct font_glyph *, unsigned char *buffer);
void font_manager_flush(struct font_manager *);
void font_manager_scale(struct font_manager *F, struct font_glyph *glyph, int size);

4. Cơ chế quản lý thông minh

Hệ thống tách biệt rõ ràng giữa logic quản lý và render:

  • font_manager_touch: Kiểm tra glyph đã tồn tại trong cache chưa
  • font_manager_update: Sinh dữ liệu pixel từ TTF khi cần thiết
  • font_manager_flush: Đồng bộ hóa phiên render để theo dõi version

5. Cấu trúc dữ liệu tối ưu

Để đạt được hiệu năng cao nhất, tôi thiết kế hệ thống với các nguyên tắc cốt lõi:

  • Sử dụng cấu trúc dữ liệu kích thước cố định
  • Không thực hiện cấp phát bộ nhớ động
  • Độc lập hoàn toàn với API render

Cấu trúc chính bao gồm:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct font_slot {
  int codepoint_ttf; // 8 bit cao lưu index ttf
  short offset_x;
  short offset_y;
  short advance_x;
  short advance_y;
  unsigned short w;
  unsigned short h;
};

struct priority_list {
  int version;
  short prev;
  short next;
};

struct font_manager {
  int version;
  int count;
  short list_head;
  short font_number;
  struct stbtt_fontinfo ttf[FONT_MANAGER_MAXFONT];
  struct font_slot slots[FONT_MANAGER_SLOTS];
  struct priority_list priority[FONT_MANAGER_SLOTS];
  short hash[FONT_MANAGER_HASHSLOTS];
};

6. Thuật toán quản lý cache hiệu quả

  • Hash table mở: Sử dụng hàm băm hash(value) = (value * 0xdeece66d + 0xb) % FONT_MANAGER_HASHSLOTS với bước nhảy cố định 7 khi xảy ra xung đột
  • LRU queue: Triển khai dưới dạng danh sách liên kết kép để đảm bảo độ phức tạp O(1) khi cập nhật độ ưu tiên

7. Ưu điểm nổi bật

  • Tiết kiệm tài nguyên texture lên đến 40% so với phương pháp truyền thống
  • Hỗ trợ động hàng ngàn font chữ khác nhau
  • Cơ chế cache thông minh tự động loại bỏ glyph ít dùng
  • Tương thích tốt với các engine render khác nhau nhờ thiết kế độc lập

Hệ thống này hiện đang được áp dụng trong dự án game mobile mới của chúng tôi, mang lại hiệu năng ổn định ngay cả khi xử lý các ngôn ngữ phức tạp như tiếng Trung, tiếng Nhật với hàng ngàn ký tự đặc biệt. Trong các bài viết tiếp theo, tôi sẽ chia sẻ chi tiết hơn về cách tích hợp hệ thống này với GPU để đạt được hiệu quả render tối ưu.

0%