Files
esengine/packages/fairygui/src/text/BitmapFont.ts
YHH a1e1189f9d feat(fairygui): FairyGUI 完整集成 (#314)
* feat(fairygui): FairyGUI ECS 集成核心架构

实现 FairyGUI 的 ECS 原生集成,完全替代旧 UI 系统:

核心类:
- GObject: UI 对象基类,支持变换、可见性、关联、齿轮
- GComponent: 容器组件,管理子对象和控制器
- GRoot: 根容器,管理焦点、弹窗、输入分发
- GGroup: 组容器,支持水平/垂直布局

抽象层:
- DisplayObject: 显示对象基类
- EventDispatcher: 事件分发
- Timer: 计时器
- Stage: 舞台,管理输入和缩放

布局系统:
- Relations: 约束关联管理
- RelationItem: 24 种关联类型

基础设施:
- Controller: 状态控制器
- Transition: 过渡动画
- ScrollPane: 滚动面板
- UIPackage: 包管理
- ByteBuffer: 二进制解析

* refactor(ui): 删除旧 UI 系统,使用 FairyGUI 替代

* feat(fairygui): 实现 UI 控件

- 添加显示类:Image、TextField、Graph
- 添加基础控件:GImage、GTextField、GGraph
- 添加交互控件:GButton、GProgressBar、GSlider
- 更新 IRenderCollector 支持 Graph 渲染
- 扩展 Controller 添加 selectedPageId
- 添加 STATE_CHANGED 事件类型

* feat(fairygui): 现代化架构重构

- 增强 EventDispatcher 支持类型安全、优先级和传播控制
- 添加 PropertyBinding 响应式属性绑定系统
- 添加 ServiceContainer 依赖注入容器
- 添加 UIConfig 全局配置系统
- 添加 UIObjectFactory 对象工厂
- 实现 RenderBridge 渲染桥接层
- 实现 Canvas2DBackend 作为默认渲染后端
- 扩展 IRenderCollector 支持更多图元类型

* feat(fairygui): 九宫格渲染和资源加载修复

- 修复 FGUIUpdateSystem 支持路径和 GUID 两种加载方式
- 修复 GTextInput 同时设置 _displayObject 和 _textField
- 实现九宫格渲染展开为 9 个子图元
- 添加 sourceWidth/sourceHeight 用于九宫格计算
- 添加 DOMTextRenderer 文本渲染层(临时方案)

* fix(fairygui): 修复 GGraph 颜色读取

* feat(fairygui): 虚拟节点 Inspector 和文本渲染支持

* fix(fairygui): 编辑器状态刷新和遗留引用修复

- 修复切换 FGUI 包后组件列表未刷新问题
- 修复切换组件后 viewport 未清理旧内容问题
- 修复虚拟节点在包加载后未刷新问题
- 重构为事件驱动架构,移除轮询机制
- 修复 @esengine/ui 遗留引用,统一使用 @esengine/fairygui

* fix: 移除 tsconfig 中的 @esengine/ui 引用
2025-12-22 10:52:54 +08:00

270 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* BitmapFont
*
* Bitmap font support for FairyGUI.
* Handles BMFont format from FairyGUI Editor exports.
*
* 位图字体支持
* 处理 FairyGUI 编辑器导出的 BMFont 格式
*/
import type { MSDFFont, IMSDFFontData, IMSDFGlyph } from './MSDFFont';
/**
* FairyGUI bitmap font glyph
* FairyGUI 位图字体字形
*/
export interface IBitmapGlyph {
/** X offset in the glyph | 字形内 X 偏移 */
x: number;
/** Y offset in the glyph | 字形内 Y 偏移 */
y: number;
/** Glyph width | 字形宽度 */
width: number;
/** Glyph height | 字形高度 */
height: number;
/** Horizontal advance | 水平前进量 */
advance: number;
/** Source texture region (if from atlas) | 源纹理区域 */
textureRegion?: {
x: number;
y: number;
width: number;
height: number;
};
/** Texture ID for this glyph | 此字形的纹理 ID */
textureId?: number;
}
/**
* FairyGUI bitmap font data (from UIPackage)
* FairyGUI 位图字体数据(来自 UIPackage
*/
export interface IBitmapFontData {
/** Is TTF (dynamic font) | 是否是 TTF动态字体 */
ttf: boolean;
/** Can be tinted | 可以着色 */
tint: boolean;
/** Font size | 字体大小 */
fontSize: number;
/** Line height | 行高 */
lineHeight: number;
/** Glyphs map (charCode -> glyph) | 字形映射 */
glyphs: Map<number, IBitmapGlyph>;
/** Texture ID for the font atlas | 字体图集纹理 ID */
textureId?: number;
}
/**
* BitmapFont
*
* Adapter for FairyGUI bitmap fonts.
* Can be used for rendering when MSDF fonts are not available.
*
* FairyGUI 位图字体适配器
* 当 MSDF 字体不可用时可用于渲染
*/
export class BitmapFont {
/** Font name | 字体名称 */
public readonly name: string;
/** Texture ID | 纹理 ID */
public textureId: number = 0;
/** Font data | 字体数据 */
private _data: IBitmapFontData;
constructor(name: string, data: IBitmapFontData) {
this.name = name;
this._data = data;
if (data.textureId !== undefined) {
this.textureId = data.textureId;
}
}
/**
* Is this a TTF (dynamic) font
* 是否是 TTF动态字体
*/
public get isTTF(): boolean {
return this._data.ttf;
}
/**
* Can the font be tinted
* 字体是否可以着色
*/
public get canTint(): boolean {
return this._data.tint;
}
/**
* Font size | 字体大小
*/
public get fontSize(): number {
return this._data.fontSize;
}
/**
* Line height | 行高
*/
public get lineHeight(): number {
return this._data.lineHeight;
}
/**
* Get glyph for a character
* 获取字符的字形
*/
public getGlyph(charCode: number): IBitmapGlyph | undefined {
return this._data.glyphs.get(charCode);
}
/**
* Check if font has a glyph
* 检查字体是否有字形
*/
public hasGlyph(charCode: number): boolean {
return this._data.glyphs.has(charCode);
}
/**
* Get all glyphs
* 获取所有字形
*/
public get glyphs(): Map<number, IBitmapGlyph> {
return this._data.glyphs;
}
}
/**
* Bitmap Font Manager
* 位图字体管理器
*/
export class BitmapFontManager {
/** Loaded fonts | 已加载的字体 */
private _fonts: Map<string, BitmapFont> = new Map();
/**
* Register a bitmap font
* 注册位图字体
*/
public registerFont(font: BitmapFont): void {
this._fonts.set(font.name, font);
}
/**
* Get a font by name
* 按名称获取字体
*/
public getFont(name: string): BitmapFont | undefined {
return this._fonts.get(name);
}
/**
* Check if a font is registered
* 检查字体是否已注册
*/
public hasFont(name: string): boolean {
return this._fonts.has(name);
}
/**
* Unload a font
* 卸载字体
*/
public unloadFont(name: string): void {
this._fonts.delete(name);
}
/**
* Clear all fonts
* 清除所有字体
*/
public clear(): void {
this._fonts.clear();
}
/**
* Create from FairyGUI package font data
* 从 FairyGUI 包字体数据创建
*/
public createFromPackageData(name: string, data: IBitmapFontData): BitmapFont {
const font = new BitmapFont(name, data);
this.registerFont(font);
return font;
}
}
/** Global bitmap font manager | 全局位图字体管理器 */
let _bitmapFontManager: BitmapFontManager | null = null;
/**
* Get global bitmap font manager
* 获取全局位图字体管理器
*/
export function getBitmapFontManager(): BitmapFontManager {
if (!_bitmapFontManager) {
_bitmapFontManager = new BitmapFontManager();
}
return _bitmapFontManager;
}
/**
* Convert bitmap font to MSDF-compatible format
* 将位图字体转换为 MSDF 兼容格式
*
* Note: This creates a "fake" MSDF font that uses bitmap rendering.
* The pxRange is set to 0 to disable MSDF processing in the shader.
*
* 注意:这会创建一个使用位图渲染的"伪" MSDF 字体。
* pxRange 设置为 0 以在着色器中禁用 MSDF 处理。
*/
export function convertBitmapToMSDFFormat(
bitmapFont: BitmapFont,
atlasWidth: number,
atlasHeight: number
): IMSDFFontData {
const glyphs: IMSDFGlyph[] = [];
for (const [charCode, glyph] of bitmapFont.glyphs) {
const region = glyph.textureRegion;
if (!region) continue;
glyphs.push({
unicode: charCode,
advance: glyph.advance / bitmapFont.fontSize,
planeBounds: {
left: glyph.x / bitmapFont.fontSize,
bottom: -(glyph.y + glyph.height) / bitmapFont.fontSize,
right: (glyph.x + glyph.width) / bitmapFont.fontSize,
top: -glyph.y / bitmapFont.fontSize
},
atlasBounds: {
left: region.x,
bottom: region.y,
right: region.x + region.width,
top: region.y + region.height
}
});
}
return {
atlas: {
type: 'sdf', // Use simple SDF mode for bitmap
distanceRange: 0, // 0 = disable MSDF processing, use as regular texture
size: bitmapFont.fontSize,
width: atlasWidth,
height: atlasHeight,
yOrigin: 'top'
},
metrics: {
emSize: bitmapFont.fontSize,
lineHeight: bitmapFont.lineHeight / bitmapFont.fontSize,
ascender: 1,
descender: 0
},
glyphs
};
}