项目背景#
最近在做一个有意思的事情:把 MonoGame 3.8.x 的运行时引擎逐行移植为 C++20,目标平台是鸿蒙 HarmonyOS,渲染后端计划采用 Vulkan。
这个项目的定位不是"做一个可用的 C++ 引擎",而是对源项目的完整 C++ 移植——代码结构与上游保持一致,不省略、不替代,最多以 TODO 标注待办。这是一份移植记录,会随进度持续更新。
技术路线#
平台层 partial 类 → 基类 + 钩子#
MonoGame 大量使用 C# 的 partial 类机制做平台适配:前端单文件(公共接口 + 逻辑)+ Platform/ 下每平台一份(辅助实现),编译期合并为同一个类。
C++ 没有 partial,对应的做法是:
- 前端 partial → C++ 基类:成员变量 + 属性 + 前端逻辑 +
Platform*虚方法钩子(如PlatformClear/PlatformPresent/PlatformDrawPrimitives) - 平台 partial → 派生类:
VulkanGraphicsDevice : public GraphicsDevice等,override 全部钩子 - 钩子语义:C# 的
private void PlatformSetup()跨 partial 文件可见(合并后是同一个类);C++ 用纯虚函数强制派生类实现,语义等价 - C++ 语言映射:构造内不能调用纯虚(UB),改由派生类构造完成后显式调用
PlatformCreate()/PlatformConstruct()
一文件一类型纪律#
移植中确立了一条纪律:每个 C# 文件对应一个 C++ 头文件(杜绝跨文件合并),唯一豁免是 MathHelper+Random 这种嵌套且平台无关的 partial 整合。枚举按 C# 源码结构独立成文件(如 VertexElementUsage 对应 vertex_element_usage.hpp)。
当前进度(2026-08-19)#
| 维度 | 状态 |
|---|---|
| 工程规模 | 145+ 头文件 + 34 cpp,编译链接验证通过 |
| 平台层类 | 21 个类全部基类化(GraphicsDevice/Texture2D/3D/Cube/RenderTarget×3/VertexBuffer/IndexBuffer/Shader/ConstantBuffer/OcclusionQuery + 4 状态类 + 2 集合类 + Adapter×3) |
| 文件结构 | 一文件一类型拆分(2026-08-19):各类型独立成文件,聚合文件改转发头 |
| 已覆盖 | 数学/几何/曲线/组件/Input 状态类/Content 核心/Audio 主体/Media 数据类/PackedVector 19/SpriteBatch 骨架/Game 循环 |
与 C# 源码的逐行比对#
- ✅ 一致:
OcclusionQuery、集合类、Shader/ConstantBuffer、GraphicsAdapter/GraphicsCapabilities/GraphicsDebug、QueryRenderTargetFormatfallback 逻辑(C# 10 项 = C++ 10 项) - ⚠️ 已盘点差异:部分类的简化重载/构造重载缺失(标注
TODO待补)、状态类枚举属性依赖未移植枚举(void*占位)
未移植盘点#
- 枚举 16 个:状态依赖 10 个(
Blend/BlendFunction/CompareFunction/StencilOperation/CullMode/FillMode/TextureAddressMode/TextureFilter/TextureFilterMode/BufferUsage,补后解除状态类占位)+GraphicsDeviceStatus+ Effect 家族 3 个 - 平台无关文件 ~50:Model 家族/异常类/事件参数类/Effect 家族/TargetBlendState/动态缓冲/顶点类型等
下一步#
- 移植 10 个状态依赖枚举(解除状态类
void*占位并补全缺失属性) TargetBlendState/GraphicsResource/Texture抽象基类- 阶段 B:窗口/生命周期(XComponent → NativeWindow)→ Vulkan 后端(
GraphicsDevice钩子实现 + MGFX→SPIR-V 工具链调研)→ 输入/音频/内容流