Skip to content

feat(font): Native Chinese pixel font, Font Fallback, and CJK typeset… - #1367

Open
isamu2025 wants to merge 1 commit into
HeapsIO:masterfrom
isamu2025:feature/chinese-pixel-font
Open

isamu2025 wants to merge 1 commit into
HeapsIO:masterfrom
isamu2025:feature/chinese-pixel-font

Conversation

@isamu2025

Copy link
Copy Markdown

📌 Summary / 概述

English:
This PR introduces comprehensive, out-of-the-box native Chinese pixel font support, a font fallback mechanism, multi-page BMFont parsing, $O(N)$ shelf packing for BDF fonts, and CJK line-breaking rules (Kinsoku Shori) to the Heaps engine. All changes are 100% backward-compatible and require zero code modifications for existing projects.

中文:
本 PR 为 Heaps 引擎引入了开箱即用的原生中文像素字体支持、字体回退链(Font Fallback)机制、BMFont 多页贴图解析、针对 BDF 字体的 $O(N)$ 货架装箱算法以及 CJK 中文避头尾折行排版法则。所有修改100% 向后兼容,现有项目无需更改任何既有代码。


🎯 Motivation & Problems Solved / 动机与解决的核心痛点

No. Problem in Heaps (原引擎痛点) Solution in this PR (本 PR 解决方案)
1 DefaultFont only contains ASCII 32~126, showing empty/missing glyphs for Unicode Chinese. Built-in 4,458-glyph 12px classic Chinese pixel font seamlessly chained via default fallback.
2 h2d.Font lacks a fallback mechanism; missing glyphs cannot fall back to secondary fonts. Added fallback: Null<Font> & fallbacks: Array<Font> with transparent recursive glyph resolution.
3 FontParser explicitly rejected multi-page BMFont (BMF format only supports one page at the moment). Fully overhauled XML, Text, and Binary v3 BMFont parsing to support multi-page texture tiles.
4 BDFFont used an $O(N^2)$ brute-force pixel scanner that froze on large CJK fonts. Rewrote packing with an $O(N)$ Shelf Bin-Packing algorithm, reducing parse time from minutes to milliseconds.
5 h2d.Text and Charset had no CJK punctuation wrapping rules, breaking lines before commas/periods. Implemented Chinese line-breaking rules (Kinsoku Shori) for both leading and trailing punctuation.
6 ModelDatabase.hx accessed fs.convert unconditionally, breaking browser JS builds. Added `#if (sys

🛠️ Key Changes / 核心改动细节

1. h2d/Font.hx - Font Fallback & Multi-Page Texture Support

  • Added public var fallback : Null<Font> and public var fallbacks : Array<Font>.
  • Added public var tiles : Array<h2d.Tile> for multi-page font textures.
  • Overhauled getChar(code: Int) and hasChar(code: Int) to seamlessly resolve missing glyphs through the fallback chain.
  • Updated clone() and dispose() for safe multi-page and fallback lifecycle management.

2. h2d/Text.hx & hxd/Charset.hx - CJK Line-Breaking Rules (Kinsoku Shori)

  • Added CJK line-start forbidden characters (,。、?!:;”)》】 etc.) in Charset.complementChars.
  • Added isLeadingChar(code: Int) to prevent line-end occurrences for opening brackets and quotation marks (“‘(《【).
  • Updated Text.splitRawText to safely backtrack to valid line breaks.

3. hxd/fmt/bfnt/FontParser.hx - Multi-Page BMFont Support

  • Lifted single-page texture limitation across XML, Text, and Binary v3 formats.
  • Page index per character is properly resolved to slice corresponding tiles[page].

4. hxd/res/BDFFont.hx - Shelf Bin-Packing

  • Replaced slow brute-force packing with $O(N)$ Shelf Packing with row-height alignment.
  • Dynamic texture growth up to 4096px or multi-page allocation for large CJK BDF files.

5. hxd/res/DefaultFont.hx - Built-in Chinese Pixel Font

  • Added compact 12px pixel font containing 4,458 essential Chinese characters and full-width punctuation:
    • defaultFontChinese.png: 1024x1024 lossless RGBA 1:1 pixel atlas.
    • defaultFontChinese.fnt: Compact BMFont binary descriptor.
  • Added DefaultFont.getChinese().
  • Updated DefaultFont.get() to automatically attach fnt.fallback = getChinese(). Any standard new h2d.Text(DefaultFont.get()) immediately renders Chinese without any extra setup.

6. h3d/prim/ModelDatabase.hx - Cross-Platform JS Fix

  • Wrapped @:privateAccess fs.convert inside #if (sys || nodejs) to prevent compile errors when targeting browser JavaScript.

🧪 Verification & Real-World Validation / 验证与实战落地

  1. Automated Unit Tests:
    • Built a comprehensive 5-suite verification runner covering fallback chaining, Text metrics, Kinsoku Shori word-wrap, multi-page BMFont parsing, and Shelf packing. 100% passed.
  2. Real-World Game Projects:
    • Fully validated and deployed on two open-source game projects by Sébastien Bénard (deepnight):
      • GameFeel (32 options, tooltips, dialogs, DirectX & OpenGL binaries)
      • Tenjutsu (LD51 48h) (title screen, LDtk level message entities, combat dialogs)
  3. Cross-Platform Compatibility:
    • Verified on DirectX (hldx), OpenGL / SDL2 (hlsdl), and HTML5 WebGL (JS) targets.

🔒 Backward Compatibility / 向后兼容性

  • Breaking Changes: None (零破坏性改动).
  • Existing projects without CJK will experience zero changes in appearance or performance.
  • Existing fonts without fallback retain their original behavior.

…ting

- Add Font.fallback and Font.fallbacks chain with multi-page texture tiles support
- Add 4,458-glyph 12px classic Chinese pixel font built into DefaultFont
- Remove single-page texture limit in BMFont FontParser (support XML/Text/Binary v3)
- Rewrite BDFFont packing algorithm using O(N) Shelf Bin-Packing
- Implement CJK line-breaking rules (Kinsoku Shori) in Charset and Text
- Fix ModelDatabase conditional compilation on browser JS target
@yuxiaomao

Copy link
Copy Markdown
Contributor

Please minimize your changes, avoid multiple contribution per PR, and rebase your branch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants