docs: sync api and planning docs
This commit is contained in:
@@ -1,631 +0,0 @@
|
||||
# Scene Viewport Overlay 与 Gizmo 正规化重构方案
|
||||
|
||||
日期:`2026-04-02`
|
||||
|
||||
## 0. 当前进度 Checkpoint
|
||||
|
||||
截至 `2026-04-02`,本方案已有以下落地结果:
|
||||
|
||||
- `Phase 1` 已完成:
|
||||
- `CameraRenderRequest` 已新增 `overlayPasses`
|
||||
- `CameraRenderer` 已在 builtin postprocess 之后执行 `overlayPasses`
|
||||
- `ViewportHostService` 已接入 editor overlay pass sequence
|
||||
- `Phase 2` 已完成首批迁移:
|
||||
- `camera frustum`
|
||||
- `directional light gizmo`
|
||||
- `camera/light scene icon`
|
||||
- 上述内容已不再走 ImGui world draw,而是走 renderer overlay pass
|
||||
- `scene icon` 的命中数据已开始收口:
|
||||
- `SceneViewPanel` 不再自己扫描 scene 构建 icon draw data
|
||||
- icon hit test 已改为消费 `SceneViewportOverlayBuilder::Build()` 产出的同类 frame data
|
||||
- `transform gizmo` 的统一命中已开始接线:
|
||||
- `SceneViewportEditorOverlayData.h` 已扩展为通用 `handleRecords`
|
||||
- `SceneViewportOverlayHandleBuilder.h` 已可把 move/rotate/scale gizmo draw data 转为 canonical handle records
|
||||
- `SceneViewPanel` 中 gizmo 的 hover / click-begin 已开始走统一 `HitTestSceneViewportOverlayHandles(...)`
|
||||
- `transform gizmo` 的绘制迁移已开始接线:
|
||||
- `SceneViewportEditorOverlayPass` 已支持 screen-space triangle primitive
|
||||
- `ViewportHostService` 已可在 host 侧根据 `SceneViewPanel` 提交的 overlay 与 gizmo handle build inputs 构建 transient transform overlay frame data
|
||||
- transform gizmo 的 handle build inputs 组装 helper 已开始从 `SceneViewPanel` 向 `SceneViewportOverlayHandleBuilder.h` 收口
|
||||
- transform gizmo 的 selection/context/refresh/cancel helper 已开始从 `SceneViewPanel` 向 `SceneViewportTransformGizmoFrameBuilder.h` 收口
|
||||
- move / rotate / scale gizmo 已不再直接依赖 `DrawSceneViewportOverlay()` 的 ImGui gizmo 绘制分支出图
|
||||
- `SceneViewportOverlayRenderer.cpp` 已收缩回 HUD/orientation 责任,不再承担 transform gizmo / scene icon / scene line 的 ImGui world draw
|
||||
- `SceneViewPanel` 内部交互前命中与交互后绘制的 gizmo 刷新链路已开始复用同一套 helper,重复的 context/update/submit 逻辑已明显收缩
|
||||
- interaction overlay frame 已改为 host 按传入的 transform gizmo inputs 现场组合,`SceneViewPanel` 不再为 hit test 预先写入 transient overlay 缓存
|
||||
- render 阶段使用的 transient transform gizmo frame data 也已改为 host 基于缓存的原始 overlay + inputs 现场构建
|
||||
|
||||
当前仍未完成的关键点:
|
||||
|
||||
- `transform gizmo` 的 drag solver / 变换求解仍然保留在各自 gizmo 类中
|
||||
- `SceneViewPanel` 里仍保留 transform gizmo 的 draw data 生成、交互仲裁与 transient overlay 提交逻辑
|
||||
- `SceneViewPanel` 仍直接控制 transform gizmo 的最终绘制 overlay 提交时机,host 尚未完全接管这一层 frame orchestration
|
||||
- `ViewportHostService` 的 canonical overlay frame data 仍未直接承载 transform gizmo,尚未收敛到单帧单份 canonical overlay 数据
|
||||
|
||||
当前阶段结论:
|
||||
|
||||
**方案方向已经验证正确,下一步不应该回头继续扩写 ImGui world overlay,而应该继续推进 canonical overlay data 与统一命中系统。**
|
||||
|
||||
## 1. 方案结论
|
||||
|
||||
当前 `Scene Viewport` 的问题,不是某一个 `Directional Light Gizmo` 画丑了,而是整条 editor overlay 链路本身没有收口:
|
||||
|
||||
- `grid` 已经是正规 renderer pass
|
||||
- `transform gizmo / camera icon / light icon / camera frustum / directional light gizmo` 仍然是 ImGui overlay
|
||||
- 输入命中和绘制几何不是同一份数据
|
||||
- `SceneViewPanel.cpp` 同时承担 panel UI、输入调度、世界转屏幕、overlay 构建、命中仲裁,职责已经失控
|
||||
|
||||
结论只有一个:
|
||||
|
||||
**不能再继续往 `SceneViewPanel.cpp` 和 ImGui world overlay 上堆功能。必须把场景中的 editor 可视化正式收口成一套 renderer 级 overlay pass 和统一 handle 数据。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前链路梳理
|
||||
|
||||
### 2.1 正规链路:Grid
|
||||
|
||||
当前 `grid` 的路径是正规的 renderer pass:
|
||||
|
||||
`ViewportHostService -> SceneRenderer -> CameraRenderer -> BuiltinPostProcessPassSequenceBuilder -> BuiltinInfiniteGridPass`
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/Viewport/ViewportHostService.h`
|
||||
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h`
|
||||
- `engine/src/Rendering/CameraRenderer.cpp`
|
||||
- `engine/src/Rendering/Passes/BuiltinPostProcessPassSequenceBuilder.cpp`
|
||||
- `engine/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp`
|
||||
|
||||
这条链路的特征是:
|
||||
|
||||
- 在 scene 几何渲染完成后,由 GPU pass 正式叠加
|
||||
- 有明确的 render request 输入
|
||||
- 有独立 pass 边界
|
||||
- 不依赖 ImGui draw list
|
||||
|
||||
### 2.2 非正规链路:Editor World Overlay
|
||||
|
||||
当前绝大多数 editor 可视化不是 renderer pass,而是:
|
||||
|
||||
1. `ViewportHostService` 渲出 scene viewport 纹理
|
||||
2. `RenderViewportPanelContent()` 在 ImGui 面板中显示这张纹理
|
||||
3. `SceneViewPanel.cpp` 在这张纹理之上继续用 ImGui draw list 手搓 world overlay
|
||||
|
||||
关键文件:
|
||||
|
||||
- `editor/src/panels/ViewportPanelContent.h`
|
||||
- `editor/src/panels/SceneViewPanel.cpp`
|
||||
- `editor/src/Viewport/SceneViewportOverlayRenderer.cpp`
|
||||
|
||||
当前放在这条链上的内容包括:
|
||||
|
||||
- move gizmo
|
||||
- rotate gizmo
|
||||
- scale gizmo
|
||||
- camera icon / light icon
|
||||
- camera frustum
|
||||
- directional light gizmo
|
||||
- orientation gizmo
|
||||
|
||||
其中 `orientation gizmo` 本质上是固定在右上角的 HUD,放在 ImGui 问题不大。真正失控的是那些锚定在世界空间中的 overlay。
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前架构的核心问题
|
||||
|
||||
### 3.1 绘制职责放错层
|
||||
|
||||
`SceneViewPanel.cpp` 不应该知道:
|
||||
|
||||
- camera frustum 怎么构造几何
|
||||
- directional light gizmo 怎么构造几何
|
||||
- icon 如何转屏幕矩形
|
||||
- 各种 gizmo 如何排序、如何遮挡
|
||||
|
||||
这些本质上都属于 viewport overlay 系统,不属于 panel UI。
|
||||
|
||||
### 3.2 命中和绘制分裂
|
||||
|
||||
当前很多交互是:
|
||||
|
||||
- 一套代码负责画
|
||||
- 另一套代码负责 hover / click / drag
|
||||
|
||||
这会导致:
|
||||
|
||||
- 看见的和能点的不是同一个东西
|
||||
- 改样式时经常忘改命中
|
||||
- 优先级只能靠条件链硬拼
|
||||
|
||||
### 3.3 世界空间对象被当成 2D UI 处理
|
||||
|
||||
camera/light icon、frustum、light gizmo、transform gizmo 本质上都是世界空间 editor overlay。
|
||||
|
||||
但它们现在被塞进 ImGui draw list 后,就天然失去:
|
||||
|
||||
- 正规的渲染顺序语义
|
||||
- 稳定的深度/遮挡策略
|
||||
- 统一的 primitive 渲染方式
|
||||
- GPU 级别的扩展能力
|
||||
|
||||
### 3.4 `SceneViewPanel.cpp` 已经过胖
|
||||
|
||||
当前它同时负责:
|
||||
|
||||
- tools/top bar UI
|
||||
- tool mode 切换
|
||||
- gizmo context 组装
|
||||
- gizmo hover/click 仲裁
|
||||
- icon hit test
|
||||
- overlay 世界几何构建
|
||||
- scene picking
|
||||
- scene camera 输入
|
||||
|
||||
这已经不再是“面板”,而是一个巨型调度器加半个渲染系统。
|
||||
|
||||
### 3.5 视觉风格无法稳定收敛
|
||||
|
||||
Directional Light 这次暴露得最明显:
|
||||
|
||||
- 需求是“圆形底盘上的光线分布”
|
||||
- 当前实现却是在 panel 里临时拼几根线
|
||||
|
||||
这不是调几个参数能根治的问题,而是底层 primitive 表达和系统边界不对。
|
||||
|
||||
---
|
||||
|
||||
## 4. 重构目标
|
||||
|
||||
这次重构的目标不是“顺手把几个 gizmo 再修漂亮一点”,而是把 Scene Viewport overlay 彻底正规化。
|
||||
|
||||
最终目标如下:
|
||||
|
||||
### 4.1 分离两类 overlay
|
||||
|
||||
#### A. HUD 类 overlay
|
||||
|
||||
固定在面板坐标系的内容继续留在 ImGui:
|
||||
|
||||
- 顶部工具栏
|
||||
- 左侧 tools 按钮
|
||||
- 右上角 orientation gizmo
|
||||
- 状态提示文字
|
||||
|
||||
#### B. World Anchored Overlay
|
||||
|
||||
锚定在世界空间里的 editor 可视化统一进入 renderer overlay pass:
|
||||
|
||||
- move / rotate / scale gizmo
|
||||
- camera / light scene icon
|
||||
- camera frustum
|
||||
- directional light gizmo
|
||||
- 后续 collider bounds / helper shapes / volume gizmo
|
||||
|
||||
### 4.2 统一绘制数据与命中数据
|
||||
|
||||
所有可交互 gizmo handle 必须来自同一份 canonical data:
|
||||
|
||||
- 画什么
|
||||
- 颜色是什么
|
||||
- 层级优先级是什么
|
||||
- handle id 是什么
|
||||
- 哪里可以点
|
||||
|
||||
都不能再分散在不同类里各算一套。
|
||||
|
||||
### 4.3 建立 renderer 级 editor overlay pass
|
||||
|
||||
目标顺序应为:
|
||||
|
||||
`Scene Geometry -> ObjectId -> Builtin Post Process(Grid/Outline) -> Editor Overlay Pass -> ImGui HUD`
|
||||
|
||||
也就是说,editor 世界 overlay 必须成为正式 render stage,而不是纹理上的二次手绘。
|
||||
|
||||
### 4.4 让 gizmo 类回归“控制器/求解器”角色
|
||||
|
||||
`Move / Rotate / Scale Gizmo` 类应主要负责:
|
||||
|
||||
- drag 状态机
|
||||
- 轴向约束
|
||||
- plane 约束
|
||||
- 变换求解
|
||||
- 交互反馈求解
|
||||
|
||||
不再继续兼任:
|
||||
|
||||
- 实际几何绘制器
|
||||
- 实际命中主仲裁器
|
||||
|
||||
---
|
||||
|
||||
## 5. 推荐的目标架构
|
||||
|
||||
## 5.1 Render Request 层新增 `overlayPasses`
|
||||
|
||||
当前 `CameraRenderRequest` 里有:
|
||||
|
||||
- `preScenePasses`
|
||||
- `postScenePasses`
|
||||
- `builtinPostProcess`
|
||||
|
||||
但没有真正适合 editor world overlay 的最后一层。
|
||||
|
||||
建议新增:
|
||||
|
||||
- `overlayPasses`
|
||||
|
||||
执行顺序调整为:
|
||||
|
||||
1. `preScenePasses`
|
||||
2. scene geometry
|
||||
3. object id
|
||||
4. `postScenePasses`
|
||||
5. `builtinPostProcess`
|
||||
6. `overlayPasses`
|
||||
|
||||
这样 world overlay 才能稳定压在 grid 和 outline 之上,再由 ImGui 负责最后的 HUD。
|
||||
|
||||
### 5.2 新建 `SceneViewportOverlayFrameData`
|
||||
|
||||
建议新增一个独立的 frame data 结构,承载这一帧 Scene Viewport 的 editor overlay 数据。
|
||||
|
||||
建议字段:
|
||||
|
||||
- `linePrimitives`
|
||||
- `trianglePrimitives`
|
||||
- `billboardSprites`
|
||||
- `handleRecords`
|
||||
- `renderLayer`
|
||||
- `depthMode`
|
||||
- `screenSpaceThickness`
|
||||
|
||||
其中:
|
||||
|
||||
- primitive 用于绘制
|
||||
- handle record 用于命中
|
||||
- 两者共享相同的 `handleId`
|
||||
|
||||
### 5.3 新建 `SceneViewportOverlayBuilder`
|
||||
|
||||
职责:
|
||||
|
||||
- 接收 scene overlay context
|
||||
- 收集 selected objects
|
||||
- 构建 camera frustum
|
||||
- 构建 directional light 圆形底盘 gizmo
|
||||
- 构建 scene icons
|
||||
- 构建 transform gizmo handles
|
||||
- 输出统一的 `SceneViewportOverlayFrameData`
|
||||
|
||||
建议位置:
|
||||
|
||||
- `editor/src/Viewport/SceneViewportOverlayBuilder.h`
|
||||
- `editor/src/Viewport/SceneViewportOverlayBuilder.cpp`
|
||||
|
||||
### 5.4 新建 `SceneViewportOverlayHitTester`
|
||||
|
||||
职责:
|
||||
|
||||
- 基于 `SceneViewportOverlayFrameData::handleRecords` 做统一命中
|
||||
- 输出唯一的 hovered handle
|
||||
- 同一份数据同时服务 hover / click / drag begin
|
||||
|
||||
建议位置:
|
||||
|
||||
- `editor/src/Viewport/SceneViewportOverlayHitTester.h`
|
||||
- `editor/src/Viewport/SceneViewportOverlayHitTester.cpp`
|
||||
|
||||
### 5.5 新建 `SceneViewportEditorOverlayPass`
|
||||
|
||||
职责:
|
||||
|
||||
- 读取 `SceneViewportOverlayFrameData`
|
||||
- 用 GPU 绘制 line / fill / billboard
|
||||
- 负责世界空间 editor overlay 的正式渲染
|
||||
|
||||
建议位置:
|
||||
|
||||
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.h`
|
||||
- `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp`
|
||||
|
||||
### 5.6 `SceneViewPanel` 的目标职责
|
||||
|
||||
重构后 `SceneViewPanel` 只负责:
|
||||
|
||||
- 顶部栏和 tools UI
|
||||
- tool mode / pivot / local-global 状态
|
||||
- 输入汇总
|
||||
- 与 viewport host service 交互
|
||||
- 显示固定 HUD
|
||||
|
||||
不再负责:
|
||||
|
||||
- world overlay 几何构建
|
||||
- icon 转屏幕
|
||||
- frustum / light gizmo 线框拼装
|
||||
- world overlay 主渲染
|
||||
|
||||
---
|
||||
|
||||
## 6. 模块职责重新划分
|
||||
|
||||
### 6.1 `SceneViewPanel`
|
||||
|
||||
保留:
|
||||
|
||||
- 面板 UI
|
||||
- 工具模式切换
|
||||
- 快捷键
|
||||
- 鼠标/键盘输入汇总
|
||||
- orientation gizmo
|
||||
|
||||
移出:
|
||||
|
||||
- world overlay primitive 构建
|
||||
- scene icon world/screen 几何生成
|
||||
- camera/light 线框绘制逻辑
|
||||
|
||||
### 6.2 `ViewportHostService`
|
||||
|
||||
新增职责:
|
||||
|
||||
- 组装 `SceneViewportOverlayFrameData`
|
||||
- 把 overlay pass 接到 render request
|
||||
|
||||
保留职责:
|
||||
|
||||
- scene view camera
|
||||
- viewport render target 管理
|
||||
- scene render request 提交
|
||||
- object id picking
|
||||
|
||||
### 6.3 Gizmo 求解器
|
||||
|
||||
`SceneViewportMoveGizmo / RotateGizmo / ScaleGizmo` 保留:
|
||||
|
||||
- 拖拽求解
|
||||
- 激活态
|
||||
- 交互反馈数据
|
||||
|
||||
逐步移除:
|
||||
|
||||
- 直接操作 ImGui draw data 的职责
|
||||
- 各自内部封闭的 hit test 决策权
|
||||
|
||||
### 6.4 Overlay Pass
|
||||
|
||||
只负责 GPU 绘制,不处理业务判断。
|
||||
|
||||
输入必须已经是“可直接画”的 primitive 数据,避免 pass 内部再知道 camera/light/gizmo 业务语义。
|
||||
|
||||
---
|
||||
|
||||
## 7. 推荐执行阶段
|
||||
|
||||
这次重构不能一次性大爆炸改完,但必须每一步都朝最终架构收敛,不能做过渡性屎层。
|
||||
|
||||
### Phase 0:冻结错误扩展方向
|
||||
|
||||
目标:
|
||||
|
||||
- 停止继续向 `SceneViewPanel.cpp` 添加新的 world overlay 绘制逻辑
|
||||
- 停止继续扩写 `SceneViewportOverlayRenderer.cpp` 为 ImGui world renderer
|
||||
|
||||
产出:
|
||||
|
||||
- 文档确认
|
||||
- 后续新增 world gizmo 一律走 overlay builder / pass 方向
|
||||
|
||||
### Phase 1:打通 `overlayPasses` 通道
|
||||
|
||||
目标:
|
||||
|
||||
- 给 `CameraRenderRequest` 新增 `overlayPasses`
|
||||
- 在 `CameraRenderer` 中调整执行顺序
|
||||
- 在 `ViewportHostService` 中接入 editor overlay pass sequence
|
||||
|
||||
产出:
|
||||
|
||||
- renderer 支持 scene 之后再画 editor overlay
|
||||
- 这一步允许先画空 pass,不做功能迁移
|
||||
|
||||
验收:
|
||||
|
||||
- 不影响现有 scene / grid / selection outline
|
||||
- `overlayPasses` 具备独立初始化、执行、释放边界
|
||||
|
||||
### Phase 2:迁移纯显示型 world overlay
|
||||
|
||||
优先迁移:
|
||||
|
||||
- camera frustum
|
||||
- camera/light scene icon
|
||||
- directional light gizmo
|
||||
|
||||
原因:
|
||||
|
||||
- 这些内容交互复杂度低
|
||||
- 最容易先把 `SceneViewPanel.cpp` 中世界几何拼装代码减掉
|
||||
|
||||
Directional Light 本阶段的目标形态:
|
||||
|
||||
- 圆形底盘
|
||||
- 光线分布在圆环或圆盘采样点上
|
||||
- 明确的世界朝向
|
||||
- 稳定屏幕线宽
|
||||
|
||||
验收:
|
||||
|
||||
- 这些 overlay 不再由 ImGui draw list 直接绘制
|
||||
- `SceneViewPanel.cpp` 不再负责生成对应线框
|
||||
|
||||
### Phase 3:迁移 Transform Gizmo 的绘制
|
||||
|
||||
目标:
|
||||
|
||||
- move / rotate / scale gizmo 的显示改为 overlay pass primitive
|
||||
- gizmo 类转为 handle builder + drag solver
|
||||
|
||||
当前进度:
|
||||
|
||||
- transform gizmo 已开始转成 transient overlay frame data
|
||||
- overlay pass 已可消费一批 screen-space triangle primitive 来绘制 gizmo 屏幕几何
|
||||
- 但 transient gizmo overlay 仍然由 `SceneViewPanel` 在帧末提交,尚未完全收口到 host / builder 的 canonical 路径
|
||||
|
||||
说明:
|
||||
|
||||
- 这一阶段只迁移“怎么画”
|
||||
- 可以暂时保留现有 drag 求解逻辑
|
||||
|
||||
验收:
|
||||
|
||||
- transform gizmo 已不依赖 ImGui world draw
|
||||
- gizmo 视觉反馈仍然可用
|
||||
|
||||
### Phase 4:统一命中系统
|
||||
|
||||
目标:
|
||||
|
||||
- 所有 world overlay 的 hover / click / drag begin 统一使用 `handleRecords`
|
||||
- 彻底删除 panel 里的多套 hit test 拼接逻辑
|
||||
|
||||
当前进度:
|
||||
|
||||
- `scene icon` 已完成
|
||||
- `transform gizmo` 的 hover / click-begin 已经开始接入统一 `handleRecords`
|
||||
- `drag begin` 之后的求解与 active 状态仍然保留在 gizmo 类与 `SceneViewPanel` 现有链路中
|
||||
|
||||
涵盖对象:
|
||||
|
||||
- transform gizmo
|
||||
- scene icon
|
||||
- 后续 camera/light/world helper handles
|
||||
|
||||
验收:
|
||||
|
||||
- 命中结果只由一份 canonical handle 数据决定
|
||||
- 不再依赖大量互相屏蔽的布尔条件
|
||||
|
||||
### Phase 5:删除旧世界 overlay 路径
|
||||
|
||||
目标:
|
||||
|
||||
- 删除 `SceneViewPanel.cpp` 中遗留的 world overlay 构建逻辑
|
||||
- 缩减 `SceneViewportOverlayRenderer.cpp` 到只保留 HUD 类渲染或直接拆分
|
||||
|
||||
最终保留:
|
||||
|
||||
- ImGui HUD
|
||||
- renderer world overlay
|
||||
|
||||
最终移除:
|
||||
|
||||
- ImGui world overlay
|
||||
|
||||
---
|
||||
|
||||
## 8. 第一阶段建议改动范围
|
||||
|
||||
如果按最小风险起步,第一轮只做下面这些:
|
||||
|
||||
- `engine/include/XCEngine/Rendering/CameraRenderRequest.h`
|
||||
- `engine/src/Rendering/CameraRenderer.cpp`
|
||||
- `editor/src/Viewport/ViewportHostService.h`
|
||||
- `editor/src/Viewport/ViewportHostRenderFlowUtils.h`
|
||||
- 新增 `editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.*`
|
||||
|
||||
第一轮不碰:
|
||||
|
||||
- move/rotate/scale 的求解逻辑
|
||||
- Scene icon 的交互优先级逻辑
|
||||
- SceneViewPanel 的大面积交互重写
|
||||
|
||||
这样可以先把 renderer 通道立住,再分批迁移业务内容。
|
||||
|
||||
---
|
||||
|
||||
## 9. 方案边界
|
||||
|
||||
这次重构明确不做的内容:
|
||||
|
||||
- 不顺手做 local mode 新行为
|
||||
- 不顺手做 runtime 通用 debug draw 系统
|
||||
- 不顺手把所有 editor widget 一次性改成 pass
|
||||
- 不在本轮引入 render graph
|
||||
|
||||
这次只做一件事:
|
||||
|
||||
**把 Scene Viewport 中锚定世界空间的 editor overlay,从 ImGui 手搓模式收口为正式 renderer overlay 系统。**
|
||||
|
||||
---
|
||||
|
||||
## 10. 风险与控制
|
||||
|
||||
### 10.1 风险:一次性迁移过大
|
||||
|
||||
控制方式:
|
||||
|
||||
- 先打通 pass 通道
|
||||
- 再迁静态 overlay
|
||||
- 最后迁 transform gizmo 与命中
|
||||
|
||||
### 10.2 风险:命中系统重写影响交互稳定性
|
||||
|
||||
控制方式:
|
||||
|
||||
- handle record 和旧逻辑短期并存
|
||||
- 先让新系统服务 hover
|
||||
- 再切 click / drag begin
|
||||
|
||||
### 10.3 风险:D3D12-only pass 与后端扩展
|
||||
|
||||
控制方式:
|
||||
|
||||
- 第一阶段允许 editor overlay pass 先只支持 D3D12
|
||||
- 但数据结构和 pass 边界必须 backend-neutral
|
||||
|
||||
### 10.4 风险:继续出现“画的是一个,点的是另一个”
|
||||
|
||||
控制方式:
|
||||
|
||||
- 明确规定 overlay primitive 和 hit proxy 必须同源
|
||||
- 不能再允许绘制与命中分别各算一套几何
|
||||
|
||||
---
|
||||
|
||||
## 11. 最终验收标准
|
||||
|
||||
当以下条件全部满足时,说明收口完成:
|
||||
|
||||
- `SceneViewPanel.cpp` 不再承担 world overlay 几何构建职责
|
||||
- world anchored editor overlay 全部进入 renderer pass
|
||||
- transform gizmo / scene icon / camera frustum / light gizmo 使用统一 overlay frame data
|
||||
- hover / click / drag begin 使用统一 handle record
|
||||
- ImGui 只负责 HUD,不再负责世界空间 gizmo 主绘制
|
||||
- 新增一种 world gizmo 时,不需要再把世界转屏幕逻辑写回 panel
|
||||
|
||||
---
|
||||
|
||||
## 12. 对本次 Directional Light Gizmo 的直接指导
|
||||
|
||||
在该重构方案下,Directional Light Gizmo 的正确实现方式应是:
|
||||
|
||||
- 它属于 `World Anchored Overlay`
|
||||
- 它的几何由 `SceneViewportOverlayBuilder` 负责生成
|
||||
- 它的线段/圆环由 `SceneViewportEditorOverlayPass` 负责绘制
|
||||
- 它的样式使用“圆形底盘 + 圆周分布光线”,不再在 panel 中临时拼矩形列线
|
||||
|
||||
也就是说,Directional Light Gizmo 不应该被当成一个局部修补任务继续留在 `SceneViewPanel.cpp`。
|
||||
|
||||
---
|
||||
|
||||
## 13. 本文后的执行原则
|
||||
|
||||
在本方案审核通过之前:
|
||||
|
||||
- 允许修 bug
|
||||
- 不建议继续扩写新的 ImGui world overlay 逻辑
|
||||
|
||||
在本方案审核通过之后:
|
||||
|
||||
- 新增 world overlay 功能,优先接入 overlay builder / overlay pass
|
||||
- `SceneViewPanel.cpp` 只减不增
|
||||
@@ -1,506 +0,0 @@
|
||||
# Shader 与 Material 系统下一阶段计划
|
||||
|
||||
日期:`2026-04-03`
|
||||
|
||||
## 1. 阶段结论
|
||||
|
||||
当前 Renderer 这一轮主线已经完成收口,但完成的是“基础运行时闭环”,不是“最终的 Unity 风格 shader/material 体系”。
|
||||
|
||||
已经完成并应视为当前基线的内容:
|
||||
|
||||
- `Shader` 运行时契约已具备 `properties / passes / resources / backend variants`
|
||||
- builtin shader 资源已经外置,运行时不再依赖 C++ 内嵌 fallback
|
||||
- `Material` 对 builtin forward 的基础属性解析已经优先走 shader semantic
|
||||
- `BuiltinForwardPipeline` 已按 shader pass `resources` 合约生成 pipeline layout 与 descriptor binding
|
||||
- `Shader` 已接入 `AssetDatabase / Library` 流程,shader import 会生成 `main.xcshader`
|
||||
- `ShaderLoader` 已支持加载 `.xcshader` artifact
|
||||
- shader manifest 依赖与 `Material -> Shader` 依赖已进入资产追踪链
|
||||
- `rendering_unit_tests`
|
||||
- `rendering_integration_textured_quad_scene`
|
||||
- `rendering_integration_backpack_lit_scene`
|
||||
- `shader_tests`
|
||||
- `material_tests`
|
||||
|
||||
三后端验证当前是稳定的:
|
||||
|
||||
- D3D12:通过
|
||||
- OpenGL:通过
|
||||
- Vulkan:通过
|
||||
|
||||
但这仍然只是“Shader / Material Runtime 的第一层骨架”。
|
||||
|
||||
当前真正还没有完成的是:
|
||||
|
||||
- Unity 风格的 shader authoring 入口
|
||||
- 正式的 material schema / instance contract
|
||||
- 从 shader property layout 到 GPU material layout 的通用映射
|
||||
- 从 builtin forward 扩展到更通用 pass 的正式执行模型
|
||||
|
||||
## 2. 旧计划归档说明
|
||||
|
||||
以下两份计划文档已经完成历史使命,应归入 `docs/used/`:
|
||||
|
||||
- `Renderer模块设计与实现.md`
|
||||
- `Renderer下一阶段_ShaderMaterial与Pass体系设计.md`
|
||||
|
||||
原因不是它们“写错了”,而是:
|
||||
|
||||
- 第一份解决的是 Renderer 模块从无到有的问题,当前骨架已经落地
|
||||
- 第二份解决的是“为什么下一阶段先做 shader/material/pass contract,而不是 render graph”的阶段判断;这份判断已经部分兑现,整体已过期
|
||||
|
||||
本文件接手它们之后的主线,只保留对当前 checkout 仍然有效的目标。
|
||||
|
||||
## 3. 当前真实问题
|
||||
|
||||
### 3.1 Shader 运行时有了,但 authoring 还没有正式化
|
||||
|
||||
现在的运行时已经能消费:
|
||||
|
||||
- shader property
|
||||
- pass tag
|
||||
- pass resource binding
|
||||
- backend variant
|
||||
|
||||
但作者侧仍然不是最终形态。
|
||||
|
||||
当前还缺:
|
||||
|
||||
- 面向用户的 Unity 风格 `.shader` 语法入口
|
||||
- import 阶段把 authoring 语法转换为 runtime contract 的正式流程
|
||||
- shader 资产与 Library artifact 的稳定产物边界
|
||||
|
||||
### 3.2 Material 仍偏“资源容器”,还不是正式材质实例系统
|
||||
|
||||
当前 `Material` 已有:
|
||||
|
||||
- shader 引用
|
||||
- render state
|
||||
- property / texture 覆盖
|
||||
- tag / queue
|
||||
|
||||
但它还缺少真正用于 Renderer 执行的正式约束:
|
||||
|
||||
- 基于 shader property schema 的类型验证
|
||||
- property 默认值与 override 的统一解析
|
||||
- per-pass material constant layout
|
||||
- texture / sampler / buffer 到 pass resource 的正式映射
|
||||
- renderer 侧可缓存、可失效、可复用的 material binding plan
|
||||
|
||||
### 3.3 现有 pass contract 仍偏 builtin-forward 视角
|
||||
|
||||
当前 forward 主链已经能跑,但完整的 pass contract 还没有正式化为可扩展系统。
|
||||
|
||||
后续至少要能稳定承接:
|
||||
|
||||
- `ForwardLit`
|
||||
- `Unlit`
|
||||
- `DepthOnly`
|
||||
- `ShadowCaster`
|
||||
- `ObjectId`
|
||||
|
||||
否则后面一旦开始做阴影、深度预通道、更多 editor/runtime helper pass,就会重新退化回 pipeline 内部的条件分支拼装。
|
||||
|
||||
### 3.4 三后端问题的本质不是“语法不同”,而是“资产如何统一”
|
||||
|
||||
当前真正要解决的,不是简单回答“到底用 GLSL 还是 HLSL”,而是明确三层边界:
|
||||
|
||||
1. 对外 authoring 语法是什么
|
||||
2. import 后的内部运行时资产是什么
|
||||
3. 每个 backend 最终执行的 variant 是什么
|
||||
|
||||
这三层不分开,后面一定会把 authoring、runtime、backend 编译链搅在一起。
|
||||
|
||||
## 4. 下一阶段的目标
|
||||
|
||||
下一阶段只做一件事:把 `Shader` 和 `Material` 从“能支撑当前 builtin forward 的运行时拼装”升级为“能长期承接 Unity 风格渲染架构的正式系统”。
|
||||
|
||||
### 4.1 对外 authoring 语法目标:严格向 Unity 对齐
|
||||
|
||||
最终对外公开的 shader 语法目标,必须与 Unity 的使用方式保持一致。
|
||||
|
||||
目标形态应当是:
|
||||
|
||||
- 单个 `.shader` 文件作为逻辑 shader 入口
|
||||
- `Shader / Properties / SubShader / Pass` 的层级结构
|
||||
- pass 内通过 `HLSLPROGRAM ... ENDHLSL` 或等价块组织代码
|
||||
- 通过 `#pragma vertex` / `#pragma fragment` 指定 stage 入口
|
||||
|
||||
也就是说:
|
||||
|
||||
- 对外 authoring 视角应当是“Unity 风格的一体化 shader 文件”
|
||||
- 不是要求作者直接去维护一堆 runtime JSON manifest
|
||||
- 也不是让上层逻辑直接感知 D3D12/OpenGL/Vulkan 各自的底层差异
|
||||
|
||||
### 4.2 对内 runtime 资产目标:继续保留 contract 模型
|
||||
|
||||
虽然 authoring 目标要严格向 Unity 靠拢,但 runtime 不应直接拿 authoring AST 当执行数据。
|
||||
|
||||
运行时仍应落到清晰的 contract:
|
||||
|
||||
```text
|
||||
Shader Asset
|
||||
-> Properties
|
||||
-> Passes
|
||||
-> Tags
|
||||
-> Resource Bindings
|
||||
-> Backend Variants
|
||||
```
|
||||
|
||||
原因很直接:
|
||||
|
||||
- Renderer 需要稳定、扁平、可缓存的数据结构
|
||||
- 三后端最终执行的仍然是 backend variant
|
||||
- material schema 与 pass binding 都需要基于 import 结果,而不是原始文本
|
||||
|
||||
结论是:
|
||||
|
||||
- 外部写法要像 Unity
|
||||
- 内部执行模型继续使用现在这套 runtime contract,并进一步完善
|
||||
|
||||
### 4.3 Material 目标:从资源对象升级为正式材质实例
|
||||
|
||||
Material 下一阶段的核心不是“多支持几个 SetFloat”,而是建立正式实例语义。
|
||||
|
||||
Material 至少要明确:
|
||||
|
||||
- 引用哪个 shader
|
||||
- 使用哪个 pass 或 pass 策略
|
||||
- 每个 property 的默认值、覆盖值、类型与序列化规则
|
||||
- 每个 pass 对应的 material constant block 如何布局
|
||||
- 每个 texture / sampler / buffer 如何映射到 pass resource
|
||||
|
||||
Renderer 侧则必须能把这些内容稳定编译成:
|
||||
|
||||
- material binding key
|
||||
- material constant payload
|
||||
- descriptor update plan
|
||||
- pipeline compatibility key
|
||||
|
||||
## 5. 推荐架构
|
||||
|
||||
### 5.1 分成三层,不混写
|
||||
|
||||
推荐明确拆成三层:
|
||||
|
||||
```text
|
||||
Unity-like Shader Authoring (.shader)
|
||||
-> Shader Importer
|
||||
-> Runtime Shader Contract
|
||||
-> Backend Variants / Material Binding Plan
|
||||
```
|
||||
|
||||
三层职责分别是:
|
||||
|
||||
- authoring 层:给人写、给 editor 看
|
||||
- importer 层:把 authoring 语法转成稳定运行时资产
|
||||
- runtime 层:给 renderer 执行、缓存、绑定、测试
|
||||
|
||||
### 5.2 Shader 的 public contract 与 backend contract 分离
|
||||
|
||||
下一阶段不建议把“Unity 风格语法”直接等同于“单源码自动跨平台编译已完全成熟”。
|
||||
|
||||
更务实的路线是:
|
||||
|
||||
- public contract 先统一成 Unity 风格 `.shader`
|
||||
- importer 先产出统一 runtime contract
|
||||
- backend variant 暂时仍允许按 backend 持有各自的编译输入或中间产物
|
||||
|
||||
这意味着:
|
||||
|
||||
- 作者看到的是统一 shader
|
||||
- Renderer 消费的是统一 runtime contract
|
||||
- backend 最终执行的仍然可以是不同 variant
|
||||
|
||||
这个分层既不违背 Unity 风格目标,也不会过早把工程拖进复杂的全平台 shader 编译链泥潭。
|
||||
|
||||
### 5.3 Vertex / Fragment 的外部写法按 Unity 组织,内部可拆分
|
||||
|
||||
对外语义上,vertex / fragment 应当属于同一个 pass。
|
||||
|
||||
也就是说,public authoring 角度要符合 Unity:
|
||||
|
||||
- 一个 shader
|
||||
- 一个或多个 subshader
|
||||
- 一个或多个 pass
|
||||
- 每个 pass 里通过 pragma 指定 vertex / fragment
|
||||
|
||||
但内部 import/runtime 完全可以把它们拆成:
|
||||
|
||||
- pass descriptor
|
||||
- vertex stage variant
|
||||
- fragment stage variant
|
||||
|
||||
外部合一,内部拆开,这是最稳妥的做法。
|
||||
|
||||
## 6. 下一阶段实施顺序
|
||||
|
||||
### 阶段 D0:先打通 Shader Import / Artifact 基础设施(已完成)
|
||||
|
||||
这是当前 checkout 在 `2026-04-03` 已经完成的新增里程碑。
|
||||
|
||||
完成内容:
|
||||
|
||||
- `ShaderImporter` 已接管 `.shader / .hlsl / .glsl / .vert / .frag / .geom / .comp`
|
||||
- shader import 结果会写入 `Library/Artifacts/.../main.xcshader`
|
||||
- `ShaderLoader` 已支持直接读取 `.xcshader`
|
||||
- shader manifest 中声明的 stage 源文件会进入依赖追踪
|
||||
- `Material` 对引用 shader 的直接依赖也已进入依赖追踪
|
||||
- `shader_tests` 与 `material_tests` 已覆盖 shader artifact 生成、加载与重导场景
|
||||
|
||||
这一步的意义不是“最终方案已完成”,而是先把 shader 纳入和 texture/material/mesh 一致的资产闭环。
|
||||
|
||||
没有这一步,后续不管做 Unity 风格 frontend,还是做 material schema,都会一直建立在“运行时临时解析源码”的不稳定基础上。
|
||||
|
||||
### 阶段 0:当前基线确认
|
||||
|
||||
这部分已经完成,不再作为待办:
|
||||
|
||||
- runtime shader contract 已建立
|
||||
- builtin forward 已按 pass resources 驱动
|
||||
- 三后端渲染回归通过
|
||||
|
||||
### 阶段 A:建立 Unity 风格 Shader Authoring Frontend
|
||||
|
||||
目标:
|
||||
|
||||
- 新增 Unity 风格 `.shader` authoring 入口
|
||||
- importer 能解析最小闭环子集
|
||||
|
||||
第一批建议支持的子集:
|
||||
|
||||
- `Shader`
|
||||
- `Properties`
|
||||
- `SubShader`
|
||||
- `Tags`
|
||||
- `Pass`
|
||||
- `HLSLPROGRAM / ENDHLSL`
|
||||
- `#pragma vertex`
|
||||
- `#pragma fragment`
|
||||
|
||||
交付标准:
|
||||
|
||||
- builtin `forward-lit`
|
||||
- builtin `unlit`
|
||||
- builtin `object-id`
|
||||
- builtin `infinite-grid`
|
||||
|
||||
至少迁移其中一条主线并成功跑通三后端测试。
|
||||
|
||||
### 阶段 B:建立正式的 Material Schema 与 Instance Contract
|
||||
|
||||
目标:
|
||||
|
||||
- shader importer 输出可供 material 消费的 property schema
|
||||
- material 对 property override 做类型校验与默认值回退
|
||||
- 为 pass 生成 material constant layout 与 resource mapping
|
||||
|
||||
交付标准:
|
||||
|
||||
- material 不再只靠 builtin alias 名字兜底
|
||||
- shader property semantic 变成正式主路径,而不是兼容性补丁
|
||||
- renderer 能从 shader schema 生成 material binding payload
|
||||
|
||||
当前建议把这一阶段作为下一步主线。
|
||||
|
||||
原因:
|
||||
|
||||
- shader artifact 与依赖追踪已经到位,shader 现在可以作为稳定 schema 来源
|
||||
- material 仍然缺少基于 shader property 的正式类型校验、默认值回退和资源映射
|
||||
- renderer 目前虽然能消费 pass resources,但 material binding 仍偏 builtin-forward 特判
|
||||
|
||||
当前进展(`2026-04-03`):
|
||||
|
||||
- 已完成:shader schema 驱动的 property 类型校验与默认值回退
|
||||
- 已完成:source `.material` 的 `properties` authoring 入口
|
||||
- 已完成:material constant layout runtime contract
|
||||
- `Material` 现在会生成正式的 constant layout 元数据
|
||||
- layout 字段包含 `name / type / offset / size / alignedSize`
|
||||
- renderer 读取的已不再只是裸字节 payload,而是 `layout + payload` 组合
|
||||
- 已完成:builtin pass resource mapping / material binding plan runtime contract
|
||||
- `RenderMaterialUtility` 现在统一提供 `PassResourceBindingLocation / BuiltinPassResourceBindingPlan`
|
||||
- 显式 shader pass `resources` 与 legacy builtin forward fallback 已走同一套解析与校验路径
|
||||
- `BuiltinForwardPipeline` 已改为消费通用 binding plan,而不是继续内联 forward 特判绑定逻辑
|
||||
- 已验证:`rendering_unit_tests` 57/57,`material_tests` 51/51
|
||||
- 下一步:把这套 pass binding plan 继续推到 `Unlit / ObjectId` 等 pass,收敛成真正共享的 shader/material 执行边界
|
||||
|
||||
### 阶段 C:把 Pass Binding 扩展为正式材质执行链路
|
||||
|
||||
目标:
|
||||
|
||||
- 不只是 builtin forward 能吃 pass resources
|
||||
- `Unlit`、`ObjectId` 也逐步切到同一套 shader/material contract
|
||||
- pipeline state key 与 descriptor binding plan 从“按功能写逻辑”升级到“按 shader pass contract 解析”
|
||||
|
||||
交付标准:
|
||||
|
||||
- 至少 `ForwardLit + Unlit + ObjectId` 共用同一套 shader/material 执行边界
|
||||
- 新增 pass 不再默认要求先写一套新的硬编码 binding 路径
|
||||
|
||||
当前进展(`2026-04-04`):
|
||||
|
||||
- 已完成:builtin `ObjectId` pass 接入通用 pass binding plan
|
||||
- builtin object-id shader 已显式声明 `PerObject` 资源合约
|
||||
- `BuiltinObjectIdPass` 已改为消费通用 binding plan,不再硬编码 `set0/binding0` 常量布局
|
||||
- 显式 shader `resources` 与 legacy object-id fallback 现在走同一套解析与校验路径
|
||||
- 已完成:builtin `Unlit` shader / pipeline 主线接入共享执行边界
|
||||
- 新增 builtin `unlit` shader 资产与 `BuiltinResources` 入口
|
||||
- `BuiltinForwardPipeline` 现在会在 `ForwardLit + Unlit` 之间按 material/shader metadata 解析目标 pass
|
||||
- `Unlit` 与 `ForwardLit` 现在共用同一套 input layout、material schema、binding plan 与 descriptor 组装路径
|
||||
- 已完成:抽出 `ForwardLit / Unlit / ObjectId` 共用的 pass layout / descriptor set 组装骨架
|
||||
- `RenderMaterialUtility` 现在统一提供 `BuiltinPassSetLayoutMetadata` 与 `TryBuildBuiltinPassSetLayouts(...)`
|
||||
- `BuiltinForwardPipeline` 与 `BuiltinObjectIdPass` 现在都复用同一套 `binding plan -> set layout -> pipeline layout` 组装路径
|
||||
- forward 侧只保留 set0 compatibility fallback 与 draw/update 逻辑;object-id 侧只保留自身约束校验与 per-object 常量写入
|
||||
- 已完成:builtin `DepthOnly / ShadowCaster` shader 与独立 pass skeleton 落地
|
||||
- 新增 builtin `depth-only` 与 `shadow-caster` shader 资产,以及 `BuiltinResources` 对应入口
|
||||
- 新增 `BuiltinDepthOnlyPass / BuiltinShadowCasterPass`,作为独立 `RenderPass` 复用同一套 shared pass-layout skeleton
|
||||
- 两个 pass 当前先收敛到 `PerObject` 常量路径;opaque 物体走 builtin fallback,`ShadowCaster` 额外尊重 `MeshRenderer.castShadows`
|
||||
- 这一步解决的是“pass contract 与执行骨架缺失”,还没有把 shadow map / light-space request flow 一次性做完
|
||||
- 已完成:`CameraRenderRequest + CameraRenderer` 正式接入 `DepthOnly / ShadowCaster` request 流程
|
||||
- 新增 `depthOnly / shadowCaster` request,支持独立 surface、clear flags / clear color,以及可选 `RenderCameraData` override
|
||||
- `CameraRenderer` 现在按 `ShadowCaster -> DepthOnly -> Forward -> ObjectId` 的顺序执行这些请求,`BuiltinDepthStylePassBase` 也会按 request clear flags 清理目标
|
||||
- 已验证:`rendering_unit_tests` 73/73
|
||||
- 已验证:`rendering_integration_textured_quad_scene` 3/3(D3D12 / OpenGL / Vulkan)
|
||||
- 已验证:`rendering_integration_unlit_scene` 3/3(D3D12 / OpenGL / Vulkan)
|
||||
- 已验证:`rendering_integration_object_id_scene` 3/3(D3D12 / OpenGL / Vulkan)
|
||||
- 下一步:如果继续沿 renderer 主线收口,优先补 `DepthOnly / ShadowCaster` 的真实 cross-backend integration coverage,并决定是否把 shadow-map 结果继续接回 forward lighting 消费链;如果先控制范围,request 流程这一块已经收口
|
||||
|
||||
### 阶段 D:扩展 AssetDatabase / Library Artifact 能力
|
||||
|
||||
目标:
|
||||
|
||||
- 在已完成的 shader artifact 基础上,继续扩展 import 产物边界
|
||||
- backend variant 的编译输入、中间产物或缓存策略进入 `Library/Artifacts`
|
||||
- 为后续 Unity 风格 `.shader` frontend 预留稳定 importer 输出层
|
||||
|
||||
交付标准:
|
||||
|
||||
- 资源改动能够稳定触发 shader/material 重新导入
|
||||
- editor/runtime 读取的是 import 后资产,不是源码临时解析
|
||||
- shader importer 不再只服务当前 JSON manifest 兼容路径,也能承接下一步 authoring frontend
|
||||
|
||||
### 阶段 E:测试与回归收口
|
||||
|
||||
目标:
|
||||
|
||||
- 给 shader importer、material schema、binding plan 增加 unit tests
|
||||
- 对 forward/unlit/object-id 增加 integration coverage
|
||||
- 保持 D3D12 / OpenGL / Vulkan 一致回归
|
||||
|
||||
最低验证集:
|
||||
|
||||
- `shader_tests`
|
||||
- `material_tests`
|
||||
- `rendering_unit_tests`
|
||||
- `rendering_integration_textured_quad_scene`
|
||||
- `rendering_integration_backpack_lit_scene`
|
||||
|
||||
必要时新增:
|
||||
|
||||
- `rendering_integration_unlit_scene`
|
||||
- `rendering_integration_object_id_scene`
|
||||
|
||||
当前进展(`2026-04-04`):
|
||||
|
||||
- 已完成:`rendering_integration_unlit_scene`
|
||||
- 显式使用 builtin `unlit` shader + `Unlit` pass,覆盖 `BuiltinForwardPipeline` 的 `ForwardLit / Unlit` pass 选择路径
|
||||
- 复用 `textured_quad_scene` 构图做最小差异回归,验证 shader/material 新 contract 不改变既有画面输出
|
||||
- 已验证:`rendering_integration_unlit_scene`
|
||||
- D3D12:通过
|
||||
- OpenGL:通过
|
||||
- Vulkan:通过
|
||||
- 已完成:`rendering_integration_object_id_scene`
|
||||
- 新增独立的 object-id integration scene,直接验证 object-id 输出采样点,而不是再维护一张新的大尺寸 GT 图片
|
||||
- 覆盖 `CameraRenderer + BuiltinObjectIdPass` 路径,以及 `Forward -> ObjectId -> Copy/Screenshot` 的跨 pass 回归
|
||||
- 修正了 `BuiltinObjectIdPass` 在 Vulkan 下的顶点输入步长问题,并让 object-id pass 自己清理/写入 depth,避免依赖前一 pass 的 depth 复用状态
|
||||
- 已验证:`rendering_integration_object_id_scene`
|
||||
- D3D12:通过
|
||||
- OpenGL:通过
|
||||
- Vulkan:通过
|
||||
- 阶段 E 当前状态:`unlit_scene` 与 `object_id_scene` 均已完成并通过三后端验证,本阶段可以收口
|
||||
|
||||
## 7. 当前阶段明确不做
|
||||
|
||||
下一阶段不应把范围扩散到下面这些方向:
|
||||
|
||||
- render graph
|
||||
- shader graph
|
||||
- 全平台单源码自动转译一次性做完
|
||||
- 完整 SRP scripting API
|
||||
- 大规模后处理框架
|
||||
|
||||
这些都依赖 shader/material 正式体系先稳定下来。
|
||||
|
||||
## 8. 成功标准
|
||||
|
||||
这个阶段完成时,应该满足下面几个判断:
|
||||
|
||||
- 作者侧已经可以写 Unity 风格的 `.shader`
|
||||
- runtime 已不再依赖手写 JSON manifest 才能描述 pass contract
|
||||
- material 能基于 shader schema 做正式绑定,而不是 builtin 特判兜底
|
||||
- 至少 `ForwardLit / Unlit / ObjectId` 三类 pass 共用统一 shader/material 执行边界
|
||||
- 三后端回归测试仍稳定通过
|
||||
|
||||
## 9. 一句话总结
|
||||
|
||||
下一阶段不是继续给 builtin forward 打补丁,而是把 `Shader` 和 `Material` 正式提升为 Unity 风格渲染架构中的稳定中层资产与执行契约。
|
||||
|
||||
## 10. 快速收口策略(`2026-04-04`)
|
||||
|
||||
目标收窄为只处理 `shader / material` 核心主线,不继续扩散到完整阴影功能、render graph、shader graph 或 editor 外围能力。
|
||||
|
||||
按下面顺序收口:
|
||||
|
||||
1. 先完成 Unity-like `.shader` authoring MVP importer
|
||||
- 允许最小子集:`Shader / Properties / SubShader / Tags / Pass / HLSLPROGRAM / #pragma vertex / #pragma fragment`
|
||||
- importer 输出继续复用当前 runtime shader contract:`properties / passes / resources / backend variants`
|
||||
- 这一阶段不追求完整 Unity ShaderLab,只做 builtin 与主线材质系统需要的最小闭环
|
||||
|
||||
2. 再迁移 builtin shader 到新 authoring 入口
|
||||
- 优先 `ForwardLit / Unlit / ObjectId / DepthOnly / ShadowCaster`
|
||||
- 要求 importer 产出的 runtime contract 与当前 renderer 消费路径保持一致
|
||||
|
||||
3. 然后收紧 material 主路径
|
||||
- 以 imported shader schema 为主路径完成 property 类型校验、默认值回退、constant layout 与 resource mapping
|
||||
- builtin alias / canonical-name fallback 只保留兼容兜底,不再作为主执行路径
|
||||
|
||||
4. 最后做最小回归集收口
|
||||
- `shader_tests`
|
||||
- `material_tests`
|
||||
- `rendering_unit_tests`
|
||||
- 必要的 rendering integration smoke
|
||||
|
||||
当前进展(`2026-04-04`):
|
||||
|
||||
- 已完成:Step 1 `Unity-like .shader authoring MVP importer`
|
||||
- `ShaderLoader` 新增 Unity-like `.shader` authoring 识别与解析入口,但保留现有 JSON manifest `.shader` 兼容路径不动
|
||||
- importer 继续落到现有 runtime shader contract:`properties / passes / resources / backend variants`
|
||||
- `CollectSourceDependencies` 已覆盖新 authoring 路径,`AssetDatabase` 会继续追踪各 backend stage 文件依赖并参与重导入
|
||||
- 已完成:Step 2 `builtin shader 迁到新 authoring 入口`
|
||||
- `forward-lit / unlit / object-id / depth-only / shadow-caster` 五个 builtin `.shader` 入口已全部切到 Unity-like authoring
|
||||
- stage 源文件、builtin shader 路径与 renderer 消费 contract 保持不变,迁移只发生在 authoring 入口层
|
||||
- 补充 `DepthOnly / ShadowCaster` builtin shader loader 覆盖,确保五类 builtin pass 都经过新 authoring 路径验证
|
||||
- 已完成:Step 3 `material 主路径收紧到 imported shader schema`
|
||||
- `MaterialLoader` 在存在 shader schema 时,`properties / textures` 中的旧 key 会先解析到 shader property semantic,再落到 shader 正式属性名
|
||||
- 旧的 `baseColor / baseColorTexture` 等兼容 key 仍可导入,但只作为兼容输入存在,不再直接污染 material 主执行路径
|
||||
- 当 material 绑定 shader schema 后,未知 texture binding 现在会被显式拒绝,不再静默忽略
|
||||
- 已验证:`shader_tests` 中新增 authoring 直载与 artifact/reimport 覆盖
|
||||
- 已验证:`shader_tests` 31/31 通过,builtin `ForwardLit / Unlit / ObjectId / DepthOnly / ShadowCaster` 全部通过加载与 backend variant 覆盖
|
||||
- 已验证:`material_tests` 53/53 通过,schema 驱动的 property/texture 映射与未知 binding 拒绝路径都已覆盖
|
||||
- 已完成:Step 4 `最小回归集收口`
|
||||
- `rendering_unit_tests` 73/73 通过,builtin pass contract 与 renderer 侧消费路径在当前重构后保持稳定
|
||||
- 本轮最小回归集结果:`shader_tests` 31/31,`material_tests` 53/53,`rendering_unit_tests` 73/73
|
||||
- 以当前目标范围看,`shader / material` 核心主线已经可以阶段性收口
|
||||
- 补充验收(`2026-04-04`):
|
||||
- 补跑 integration smoke 时发现并修复了一处真实回归:Unity-like `.shader` authoring 将 HLSL 的 `MainVS / MainPS` 入口错误套到了 GLSL/Vulkan variant,上层表现为 Vulkan `BuiltinForwardPipeline` 建 pipeline 失败
|
||||
- 修复后补跑 `rendering_integration_textured_quad_scene` 与 `rendering_integration_unlit_scene`、`rendering_integration_object_id_scene`,三者在 `D3D12 / OpenGL / Vulkan` 下均通过
|
||||
- 额外补跑 `rendering_integration_backpack_lit_scene` 时,暴露出一条相邻但不同范围的问题:direct `MeshLoader` 导入的 mesh/material/texture 生命周期路径存在异常退出/不干净收尾,已超出本次 `shader / material contract` 收口范围
|
||||
- 因此本计划按“核心主线已收口,附带一条相邻 residual risk”归档;若后续继续补强,优先单独开一轮处理 `MeshLoader + imported subresource lifetime`
|
||||
- 下一步:从当前目标范围出发,本计划可归档;后续如继续推进,请以新计划承接 `backpack_lit_scene` 这条相邻问题
|
||||
|
||||
当前阶段明确不做:
|
||||
|
||||
- 完整阴影贴图消费链
|
||||
- render graph
|
||||
- shader graph
|
||||
- 完整 Unity ShaderLab 全语法
|
||||
- 与 shader/material 主线无关的 editor/ui 扩展
|
||||
@@ -1,140 +0,0 @@
|
||||
# XCUI Input / Focus / Shortcut Subplan 完成归档
|
||||
|
||||
日期:`2026-04-04`
|
||||
|
||||
## 1. 归档结论
|
||||
|
||||
`Subplan-04` 在其原始定义边界内已经完成,可以归档。
|
||||
|
||||
这里的“完成”指的是:
|
||||
|
||||
- 已建立 XCUI 输入事件基础模型
|
||||
- 已建立焦点、激活路径、指针捕获路径三套状态管理
|
||||
- 已建立 capture / target / bubble 三阶段输入路由
|
||||
- 已建立 shortcut scope 与命令匹配机制
|
||||
- 已建立统一的 `UIInputDispatcher`
|
||||
- 已补齐最小单元测试并完成通过验证
|
||||
|
||||
这里的“完成”不包括:
|
||||
|
||||
- Win32 原生消息采集
|
||||
- ImGui / Editor 侧的输入桥接
|
||||
- 文本输入控件级别的 IME 细节
|
||||
|
||||
这些内容本来就不在 `Subplan-04` 的负责边界里,后续应由 `Subplan-05`、`Subplan-08`、`Subplan-09` 等继续接手。
|
||||
|
||||
## 2. 本次落地内容
|
||||
|
||||
### 2.1 输入事件模型
|
||||
|
||||
已扩展 `UIInputEvent`:
|
||||
|
||||
- `PointerEnter`
|
||||
- `PointerLeave`
|
||||
- `pointerId`
|
||||
- `timestampNanoseconds`
|
||||
- `repeat`
|
||||
- `synthetic`
|
||||
|
||||
相关文件:
|
||||
|
||||
- `engine/include/XCEngine/UI/Types.h`
|
||||
|
||||
### 2.2 焦点与路径模型
|
||||
|
||||
已补齐:
|
||||
|
||||
- `UIElementId`
|
||||
- `UIInputPath`
|
||||
- `UIFocusController`
|
||||
- `UIFocusChange`
|
||||
|
||||
相关文件:
|
||||
|
||||
- `engine/include/XCEngine/UI/Input/UIInputPath.h`
|
||||
- `engine/include/XCEngine/UI/Input/UIFocusController.h`
|
||||
- `engine/src/UI/Input/UIInputPath.cpp`
|
||||
- `engine/src/UI/Input/UIFocusController.cpp`
|
||||
|
||||
### 2.3 Shortcut 系统
|
||||
|
||||
已补齐:
|
||||
|
||||
- `UIShortcutScope`
|
||||
- `UIShortcutChord`
|
||||
- `UIShortcutBinding`
|
||||
- `UIShortcutRegistry`
|
||||
- shortcut scope 优先级匹配规则
|
||||
|
||||
相关文件:
|
||||
|
||||
- `engine/include/XCEngine/UI/Input/UIShortcutRegistry.h`
|
||||
- `engine/src/UI/Input/UIShortcutRegistry.cpp`
|
||||
|
||||
### 2.4 输入路由与统一分发器
|
||||
|
||||
已补齐:
|
||||
|
||||
- `UIInputRouter`
|
||||
- `UIInputRoutingPlan`
|
||||
- `UIInputRoutingStep`
|
||||
- `UIInputDispatcher`
|
||||
|
||||
相关文件:
|
||||
|
||||
- `engine/include/XCEngine/UI/Input/UIInputRouter.h`
|
||||
- `engine/include/XCEngine/UI/Input/UIInputDispatcher.h`
|
||||
- `engine/src/UI/Input/UIInputRouter.cpp`
|
||||
- `engine/src/UI/Input/UIInputDispatcher.cpp`
|
||||
|
||||
## 3. 测试与验证
|
||||
|
||||
新增测试:
|
||||
|
||||
- `tests/Input/test_xcui_input_dispatcher.cpp`
|
||||
|
||||
已完成验证:
|
||||
|
||||
- `cmake --build build --config Debug --target input_tests`
|
||||
- `ctest -C Debug -R "XCUI.*" --output-on-failure`
|
||||
|
||||
验证结果:
|
||||
|
||||
- `6 / 6` 通过
|
||||
|
||||
覆盖点包括:
|
||||
|
||||
- focus path 切换
|
||||
- capture path 优先级
|
||||
- keyboard routed path 顺序
|
||||
- shortcut scope 匹配优先级
|
||||
- pointer down / pointer up 对 active path 的影响
|
||||
- shortcut 命中后优先消费、跳过普通 routing
|
||||
|
||||
## 4. 对后续 subplan 的可复用输出
|
||||
|
||||
当前已经可以被后续直接依赖的稳定入口:
|
||||
|
||||
- `XCEngine::UI::UIInputPath`
|
||||
- `XCEngine::UI::UIFocusController`
|
||||
- `XCEngine::UI::UIShortcutRegistry`
|
||||
- `XCEngine::UI::UIInputRouter`
|
||||
- `XCEngine::UI::UIInputDispatcher`
|
||||
|
||||
后续建议对接方式:
|
||||
|
||||
- `Subplan-05`:负责把 ImGui/平台输入桥接进这套 dispatcher
|
||||
- `Subplan-08`:负责把 menu / dock / panel shell 的 shortcut scope 接进 registry
|
||||
- `Subplan-09`:负责把 viewport shell 的 pointer / focus / capture 接进 routing
|
||||
|
||||
## 5. 原 subplan 文件
|
||||
|
||||
原始 subplan 文件保留在:
|
||||
|
||||
- `docs/plan/xcui-subplans/Subplan-04_XCUI-Input-Focus-Shortcut.md`
|
||||
|
||||
其状态应视为:
|
||||
|
||||
- 已完成
|
||||
- 已归档
|
||||
- 不再作为活跃开发计划继续扩写
|
||||
349
docs/plan/used/XCUI_Phase_Status_2026-04-05.md
Normal file
349
docs/plan/used/XCUI_Phase_Status_2026-04-05.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# XCUI Phase Status 2026-04-05
|
||||
|
||||
## Scope
|
||||
|
||||
Current execution stays inside the XCUI module and `new_editor`.
|
||||
Old `editor` replacement is explicitly out of scope for this phase.
|
||||
|
||||
## Latest Checkpoint
|
||||
|
||||
- Phase 1 sandbox batch committed and pushed as `67a28bd` (`Add XCUI new editor sandbox phase 1`).
|
||||
- Phase 2 common/runtime batch committed and pushed as `ade5be3` (`Add XCUI runtime screen layer and demo textarea`).
|
||||
- Phase 3 has now produced a stable mixed batch across common/runtime/editor:
|
||||
- schema document definition data is now retained on `UIDocumentModel` and round-trips through the UI artifact path
|
||||
- schema self-definition validation is now stricter around enum/document-only metadata combinations
|
||||
- engine runtime coverage was tightened again around `UISystem` and concrete document-host rendering
|
||||
- `LayoutLab` continues as the editor widget proving ground for tree/list/property-section style controls
|
||||
- the demo sandbox and editor bridge APIs were tightened again without touching the old editor replacement scope
|
||||
- `new_editor` now has an explicit two-step window compositor seam through `IWindowUICompositor` / `ImGuiWindowUICompositor`, layered on top of `IEditorHostCompositor` / `ImGuiHostCompositor`
|
||||
- The native-host / hosted-preview publication follow-up is now landed in `new_editor`:
|
||||
- `NativeWindowUICompositor` is now buildable alongside the legacy ImGui compositor
|
||||
- `Application` now defaults to a native XCUI host path instead of creating the ImGui shell by default
|
||||
- the native default path now reuses shell-agnostic `XCUIDemoPanel::ComposeFrame(...)` / `XCUILayoutLabPanel::ComposeFrame(...)` results instead of keeping a second demo/layout runtime + input-bridge stack inside `Application`
|
||||
- the native compositor now publishes hosted-preview textures as SRV-backed `UITextureRegistration` / `UITextureHandle` values instead of relying on ImGui-only descriptor semantics
|
||||
- the native shell now begins the hosted-preview queue/registry lifecycle each frame, queues native preview frames, drains them during the native render pass, and consumes published hosted-surface images directly in panel cards with live/warming placeholder states
|
||||
- the old ImGui shell path remains present as an explicit compatibility host instead of the default host
|
||||
- `XCUIInputBridge.h` no longer drags `imgui.h` through the public XCUI input seam
|
||||
- The default native text path is now also de-ImGuiized inside `new_editor`:
|
||||
- `XCUIStandaloneTextAtlasProvider` now builds and owns its atlas through a Windows/GDI raster path instead of using ImGui font-atlas internals
|
||||
- the standalone atlas provider now exposes both `RGBA32` and `Alpha8` views, supports non-nominal size resolution, lazily adds non-prebaked BMP glyphs, and falls back to `?` when a glyph cannot be rasterized
|
||||
- The default native shell path now also has a cleaner translation-unit seam:
|
||||
- legacy ImGui shell chrome / HUD rendering now lives in a dedicated legacy-only `Application` translation unit instead of keeping direct `ImGui::*` calls inside the main native host TU
|
||||
- `Application.cpp` no longer directly includes `<imgui.h>`, even though the compatibility host path is still compiled into `new_editor`
|
||||
- The `new_editor` build now also has an explicit compatibility-source slice:
|
||||
- legacy ImGui shell sources and vendored ImGui backend sources are now grouped into a dedicated compatibility static library instead of being compiled directly as part of the main `XCNewEditor` source list
|
||||
- The main-target header-isolation milestone is now also landed in `new_editor`:
|
||||
- `XCNewEditor` drops direct `${IMGUI_SOURCE_DIR}` / `${IMGUI_SOURCE_DIR}/backends` include-directory requirements
|
||||
- the generated `XCNewEditor.vcxproj` no longer advertises `imgui-src` or `editor/src` on the default include surface
|
||||
- the default native compile path no longer reaches `<imgui.h>` through `editor/src/UI/ImGuiBackendBridge.h` or equivalent bridge headers
|
||||
- `XCNewEditorImGuiCompat` remains the explicit compatibility-only consumer of legacy ImGui headers and backend sources
|
||||
- The compositor/font compat boundary is now tighter as well:
|
||||
- `IWindowUICompositor.h` and `IEditorHostCompositor.h` no longer declare `CreateImGui*` factories on the generic XCUI seam
|
||||
- ImGui factory entry points now live only in `LegacyImGuiHostInterop.h`
|
||||
- `XCUIEditorFontSetup.h` no longer exposes `ImFont` / `ImFontAtlas`; the public API is now a current-context font bootstrap helper
|
||||
- `XCUIStandaloneTextAtlasProvider.h` no longer depends on the ImGui-oriented font bootstrap header
|
||||
- The generic shell command/state boundary is now narrower as well:
|
||||
- `XCUIShellChromeState` no longer carries the legacy host demo-window toggle or command id on the generic shell-state surface
|
||||
- `Application.h` no longer exposes that legacy demo command through generic `ShellCommandIds`, `ShellCommandBindings`, or `RegisterShellViewCommands(...)`
|
||||
- the legacy demo window toggle now lives as a compatibility-only command inside `ApplicationLegacyImGui.cpp`
|
||||
- `Application.h` now also uses backend-neutral compatibility-host naming for the non-native window-host path, so the generic application header no longer names `LegacyImGui` in its mode enum or private host-frame method declarations
|
||||
- generic `Application` host-mode/member naming is now also shifting from `LegacyImGui` toward `CompatibilityHost`, so the default shell surface does not have to encode ImGui into every host-facing method name
|
||||
- Old `editor` replacement remains deferred; all active execution still stays inside XCUI shared code and `new_editor`.
|
||||
|
||||
## Three-Layer Status
|
||||
|
||||
### 1. Common Core
|
||||
|
||||
- `UI::DrawData`, input event types, focus routing, style/theme resolution are in active use.
|
||||
- `UIDocumentCompiler` is buildable again after repairing the duplicated schema helper regression introduced by overlapping schema work.
|
||||
- `UIDocumentModel` / `UIDocumentResource` now retain schema definition metadata explicitly, including memory accounting and `UISchema` accessors.
|
||||
- `.xcschema` round-trip coverage is now present through compile, loader, artifact write, and artifact read paths.
|
||||
- Build-system hardening for MSVC/PDB output paths has started in root CMake, `engine/CMakeLists.txt`, `new_editor/CMakeLists.txt`, and `tests/NewEditor/CMakeLists.txt`.
|
||||
- Shared engine-side XCUI runtime scaffolding is now present under `engine/include/XCEngine/UI/Runtime` and `engine/src/UI/Runtime`.
|
||||
- Shared engine-side `UIDocumentScreenHost` now compiles `.xcui` / `.xctheme` screen documents into a runtime-facing document host path instead of leaving all document ownership in `new_editor`.
|
||||
- Shared text-editing primitives now live under `engine/include/XCEngine/UI/Text` and `engine/src/UI/Text`, so UTF-8 caret movement, line splitting, and multiline navigation are no longer trapped inside `XCUI Demo`.
|
||||
- Shared text-input controller/state now also lives under `engine/include/XCEngine/UI/Text` and `engine/src/UI/Text`, so character insertion, backspace/delete, submit, and multiline key handling no longer need to be reimplemented per host.
|
||||
- Shared editor collection primitive classification and metric helpers now also live under `engine/include/XCEngine/UI/Widgets` and `engine/src/UI/Widgets`, covering the current `ScrollView` / `TreeView` / `ListView` / `PropertySection` / `FieldRow` prototype taxonomy.
|
||||
- Shared single-selection state now also lives under `engine/include/XCEngine/UI/Widgets` and `engine/src/UI/Widgets` as `UISelectionModel`, so collection-style widget selection no longer has to stay private to `LayoutLab`.
|
||||
- Shared expansion state now also lives under `engine/include/XCEngine/UI/Widgets` and `engine/src/UI/Widgets` as `UIExpansionModel`, so collapsible tree/property-style widget state no longer has to stay private to `LayoutLab`.
|
||||
- Shared keyboard-navigation state now also lives under `engine/include/XCEngine/UI/Widgets` and `engine/src/UI/Widgets` as `UIKeyboardNavigationModel`, so list/tree/property-style widgets can share current-index, anchor, and home/end/step navigation rules instead of re-rolling them per sandbox.
|
||||
- Shared property-edit session state now also lives under `engine/include/XCEngine/UI/Widgets` and `engine/src/UI/Widgets` as `UIPropertyEditModel`, so editor-facing field rows can reuse begin/edit/commit/cancel transaction state instead of baking that directly into sandbox runtimes.
|
||||
- Core regression coverage now includes `UIContext`, layout, style, runtime screen player/system, and real document-host tests through `core_ui_tests`.
|
||||
|
||||
Current gap:
|
||||
|
||||
- Minimal schema self-definition support is landed, including consistency checks for enum/document-only schema metadata, but schema-driven validation for `.xcui` / `.xctheme` instances is still not implemented.
|
||||
- Shared widget/runtime instantiation is still thin and mostly editor-side.
|
||||
- Common widget primitives are still incomplete: shared text-input presentation/composition on top of the new text controller, multi-selection/focus-traversal/virtualized collection state on top of the new editor-primitive helpers, shared scroll/navigation-scope/caret-layout helpers, and promotion of the current native text-atlas path into a shared/cross-platform text subsystem.
|
||||
|
||||
### 2. Runtime/Game Layer
|
||||
|
||||
- The main concrete progress here is that the retained-mode demo runtime now supports a real `TextField` input path with UTF-8 text entry and backspace handling.
|
||||
- The demo runtime has moved past single-line input: multiline `TextArea` behavior is now covered in the sandbox testbed.
|
||||
- Engine-side runtime ownership is no longer zero: `UIScreenPlayer`, `UIDocumentScreenHost`, and `UISystem` now define a shared runtime contract for loading a screen document, ticking it with input, and collecting `UI::UIDrawData`.
|
||||
- `UISystem` now supports layered screen composition semantics: stacked screen players, top-interactive input routing, and modal layers that block lower screens.
|
||||
- `UIScreenStackController::ReplaceTop` now preserves the previous top screen if the replacement screen fails to load, so runtime menu flows do not silently drop their active layer on bad assets.
|
||||
- `SceneRuntime` now owns a dedicated `UISceneRuntimeContext`, so game/runtime code has a first-class place to configure viewport/focus, queue `UIInputEvent`s, drive `UISystem` each `Update`, and inspect the latest UI frame result.
|
||||
- Runtime screen emission now also carries concrete button text in the shared document host path instead of silently dropping button labels.
|
||||
- `UISystemFrameResult` now also preserves viewport rect, submitted input count, frame delta, and focus state, and both `UISystem` and `UISceneRuntimeContext` now expose `ConsumeLastFrame()` so runtime/game hosts can drain the last retained frame packet without copying editor-side concepts into the shared layer.
|
||||
- `UIScreenPlayer` now also exposes `ConsumeLastFrame()`, so player/system/context all share the same consume-vs-borrow frame ownership semantics in the runtime layer.
|
||||
|
||||
Current gap:
|
||||
|
||||
- Runtime UI is now wired into `SceneRuntime`, but render submission is still limited to producing `UIDrawData`; there is no game-view/runtime presenter path that automatically draws those frames yet.
|
||||
- The runtime widget library is still shallow and missing the editor-grade controls that will later be shared downward.
|
||||
|
||||
### 3. Editor Layer
|
||||
|
||||
- `new_editor` remains the isolated XCUI sandbox.
|
||||
- Native hosted preview is now working end-to-end as `RHI offscreen surface -> SRV-backed publication -> hosted surface image present` through the native shell path.
|
||||
- Hosted preview surface descriptors now stay on XCUI-owned value types (`UITextureHandle`, `UIPoint`, `UIRect`) instead of exposing ImGui texture/UV types through the generic preview contract.
|
||||
- Shared `UI::UIDrawData` image commands now carry explicit `uvMin` / `uvMax` source-rect semantics, and the native panel canvas host preserves those UVs when it records hosted surface-image preview commands.
|
||||
- `XCUI Demo` remains the long-lived effect and behavior testbed.
|
||||
- `XCUI Demo` now covers both single-line and multiline text authoring behavior, including click caret placement, delete/backspace, tab indentation, and optional text-area line numbers.
|
||||
- `XCUI Demo` now consumes the shared `UITextInputController` path for text editing instead of carrying a private key-handling state machine.
|
||||
- `LayoutLab` now includes a `ScrollView` prototype and a more editor-like three-column authored layout.
|
||||
- `LayoutLab` now also covers editor-facing widget prototypes: `TreeView`, `TreeItem`, `ListView`, `ListItem`, `PropertySection`, and `FieldRow`.
|
||||
- `LayoutLab` now consumes the shared `UIEditorCollectionPrimitives` helper layer for collection-widget tag classification, clipping flags, and default metric resolution instead of keeping that taxonomy private to the sandbox runtime.
|
||||
- `LayoutLab` now also consumes the shared `UISelectionModel` for click-selection persistence across collection-style widgets, and the diagnostics panel now exposes both hovered and selected element ids.
|
||||
- `LayoutLab` now also consumes the shared `UIExpansionModel` for tree expansion and property-section collapse, with reserved property headers, disclosure glyphs, and persisted click-toggle behavior in the sandbox runtime.
|
||||
- `new_editor` now also has an isolated `XCUIEditorCommandRouter` model with shortcut matching, enable predicates, and direct command invocation semantics covered by dedicated tests, ready for shell-frame integration.
|
||||
- `XCUI Demo` now exports pending per-frame command ids through `DrainPendingCommandIds()`, so editor-side hosts have a clean seam for observing demo/runtime command traffic without parsing draw data.
|
||||
- `XCUI Demo` and `LayoutLab` panel canvases are now being pulled behind a dedicated `IXCUIPanelCanvasHost` seam, so canvas surface presentation, hover/focus fallback state, and overlay draw hooks no longer have to stay hard-coded inside each ImGui panel implementation.
|
||||
- The panel-canvas seam now keeps the generic host contract on observable canvas behavior only; backend/capability identity probing has been removed from `IXCUIPanelCanvasHost`, and the minimal `NullXCUIPanelCanvasHost` remains the concrete placeholder host for non-ImGui paths.
|
||||
- `XCUI Demo` and `LayoutLab` panel input now also flows through an explicit `IXCUIInputSnapshotSource` seam, so panel/runtime code no longer reads `ImGuiIO` / `ImGui::IsKeyPressed` / `ImGui::IsMouseClicked` directly when the shell wants to use an ImGui adapter.
|
||||
- `new_editor` now also has an explicit `ImGuiXCUIInputSnapshotSource` adapter, keeping ImGui-specific input capture in the host adapter layer instead of inside panel/runtime update code.
|
||||
- `XCUI Demo` and `LayoutLab` panels now both expose shell-agnostic per-frame composition results (`ComposeFrame(...)` + `GetLastFrameComposition()`), so native/compat shells can reuse one panel-local frame pipeline instead of duplicating runtime/input/preview assembly logic.
|
||||
- `XCUIDemoPanel::ComposeFrame(...)` now also accepts an injected input snapshot plus explicit placeholder/frame options, which lets the native shell reuse the panel pipeline without falling back to the compatibility-path placeholder behavior on direct draw-data cards.
|
||||
- Panel diagnostics were expanded to clearly separate preview/runtime/input state and native vs legacy paths.
|
||||
- The editor bridge layer now has smoke coverage for swapchain after-UI rendering hooks and SRV-backed ImGui texture descriptor registration.
|
||||
- `Application` no longer owns the ImGui backend directly; window presentation now routes through `IWindowUICompositor` with an `ImGuiWindowUICompositor` implementation, which currently delegates to `IEditorHostCompositor` / `ImGuiHostCompositor`.
|
||||
- Hosted preview offscreen surfaces now keep compositor-returned `UITextureRegistration` / `UITextureHandle` data inside `Application` instead of storing `ImTextureID` directly.
|
||||
- The generic hosted-preview presenter contract no longer owns `ImGuiTransitionBackend`; the ImGui presenter now sits in a separate `ImGuiXCUIHostedPreviewPresenter` header while the native queue/surface registry remains XCUI-generic.
|
||||
- The generic hosted-preview frame contract no longer carries an ImGui draw-list pointer; the legacy ImGui presenter resolves its inline draw target from the active ImGui window context instead of pushing that type through the XCUI contract.
|
||||
- The legacy ImGui hosted-preview presenter now also accepts an explicit draw-target binding object, so presenter-side `ImGui::GetWindowDrawList()` lookup is no longer hard-coded inside the generic presenter path and can stay isolated behind the ImGui adapter layer.
|
||||
- `Application` shell menu toggles and global shortcuts now route through `XCUIEditorCommandRouter` instead of directly mutating shell booleans from menu callbacks, giving the editor layer a real command-routing seam.
|
||||
- `LayoutLab` runtime now consumes the shared `UIKeyboardNavigationModel` for abstract list/tree/property navigation actions (`previous/next/home/end/collapse/expand`), so keyboard collection traversal rules are no longer trapped in sandbox-local state.
|
||||
- `LayoutLab` panel input now also maps concrete arrow/home/end keys into those shared navigation actions, so keyboard traversal is reachable from the sandbox UI instead of staying runtime-only.
|
||||
- `XCUIDemoRuntime` now bridges pointer activation, text-edit commands, and shortcut-triggered commands through a unified command path, and `DrainPendingCommandIds()` now preserves mixed pointer/text/shortcut ordering.
|
||||
- `new_editor` now also has a pure `XCUIShellChromeState` model covering panel visibility, hosted-preview mode, and shell-level view toggles without depending on ImGui, `Application`, or the old editor.
|
||||
- `XCUIShellChromeState` hosted-preview mode naming is now backend-neutral (`HostedPresenter` / `NativeOffscreen`) instead of encoding `ImGui` into the XCUI shell model.
|
||||
- The shell chrome view-toggle model no longer carries the legacy host demo window at all on the generic XCUI seam; that command now lives only inside the compatibility-only legacy host implementation.
|
||||
- `new_editor` now also has a concrete `NativeWindowUICompositor` path and native-focused compositor tests, so the window compositor seam is no longer ImGui-only.
|
||||
- `Application` now also has a native XCUI shell path that:
|
||||
- becomes the default `new_editor` startup path
|
||||
- lays out `XCUI Demo` and `Layout Lab` as native cards directly in the swapchain window
|
||||
- routes shell shortcuts through the same command router without reading ImGui capture state in the default host path
|
||||
- reuses panel-local `ComposeFrame(...)` entry points for demo/layout runtime, input, hosted-preview, and overlay composition instead of maintaining duplicate native-shell runtime/input state in `Application`
|
||||
- composes one native `UIDrawData` packet and submits it through `NativeWindowUICompositor`
|
||||
- Native shell preview-mode reconfiguration now rebuilds the native panel bindings instead of rebinding a legacy hosted presenter, so the default host path no longer needs the ImGui presenter when a card stays on direct draw-data composition.
|
||||
- The native shell layout policy now also lives behind `XCUINativeShellLayout`, so top-bar/footer/workspace geometry, panel split rules, and active-panel transfer on pointer press are no longer hard-coded inline inside `Application.cpp`.
|
||||
- `NativeXCUIPanelCanvasHost` now backs that direct shell path as an externally driven canvas/session host for native cards instead of assuming an ImGui child-window model, and it now emits native `Image` draw commands for hosted surface-image previews while preserving per-surface UVs.
|
||||
- `NativeWindowUICompositor` now creates and frees SRV-backed texture registrations for hosted preview surfaces, so native publication no longer depends on ImGui descriptor handles.
|
||||
- `Application` now runs the hosted-preview lifecycle in both legacy and native frame paths, treats published textures as XCUI-owned `UITextureHandle` state, queues native preview frames from `BuildNativeShellDrawData(...)`, and drains them during native rendering before shell chrome overlays.
|
||||
- `XCUIInputBridge.h` no longer includes `imgui.h`, so the public XCUI input bridge seam is now host-neutral at the header boundary.
|
||||
- `XCNewEditor` builds successfully to `build/new_editor/bin/Debug/XCNewEditor.exe`.
|
||||
|
||||
Current gap:
|
||||
|
||||
- The default shell host is now native, and the legacy ImGui shell/panel path has been split out of the default executable into the standalone `XCNewEditorImGuiCompat` compatibility slice.
|
||||
- The default native shell path is now split away from direct `ImGui::*` calls at the main-target header/include level and no longer links the compatibility slice by default.
|
||||
- The default native shell now also consumes shared `XCUINativeShellLayout` and `UIEditorPanelChrome` helpers for panel split/chrome policy instead of duplicating that card layout logic entirely inside `Application.cpp`.
|
||||
- The native shell currently proves direct runtime composition, but its shell chrome is still a bespoke `Application`-side layout rather than a fully shared XCUI-authored editor shell document.
|
||||
- Editor-specialized widgets are still incomplete at the shared-module level: the authored prototypes exist, but virtualization, multi-selection/focus traversal, toolbar/menu chrome, menu interaction widgets, and icon-atlas widgets are not yet extracted into reusable XCUI modules.
|
||||
- The default native text path now uses a standalone Windows/GDI atlas through `XCUIStandaloneTextAtlasProvider`, but that provider still lives inside `new_editor` and is not yet promoted into a shared/cross-platform text subsystem.
|
||||
|
||||
## Validated This Phase
|
||||
|
||||
- `new_editor_xcui_demo_panel_tests`: `4/4`
|
||||
- `new_editor_xcui_demo_runtime_tests`: `12/12`
|
||||
- `new_editor_xcui_input_bridge_tests`: `4/4`
|
||||
- `new_editor_imgui_xcui_input_adapter_tests`: `2/2`
|
||||
- `new_editor_xcui_layout_lab_runtime_tests`: `12/12`
|
||||
- `new_editor_xcui_rhi_command_compiler_tests`: `7/7`
|
||||
- `new_editor_xcui_rhi_render_backend_tests`: `5/5`
|
||||
- `new_editor_xcui_standalone_text_atlas_provider_tests`: `6/6`
|
||||
- `new_editor_xcui_hosted_preview_presenter_tests`: `20/20`
|
||||
- `new_editor_legacy_imgui_host_interop_tests`: `4/4`
|
||||
- `new_editor_imgui_window_ui_compositor_tests`: `7/7`
|
||||
- `new_editor_native_window_ui_compositor_tests`: `8/8`
|
||||
- `new_editor_xcui_editor_command_router_tests`: `5/5`
|
||||
- `new_editor_application_shell_command_bindings_tests`: `11/11`
|
||||
- `new_editor_xcui_shell_chrome_state_tests`: `11/11`
|
||||
- `new_editor_xcui_panel_canvas_host_tests`: `4/4`
|
||||
- `new_editor_imgui_xcui_panel_canvas_host_tests`: `1/1`
|
||||
- `new_editor_native_xcui_panel_canvas_host_tests`: `4/4`
|
||||
- `new_editor_xcui_layout_lab_panel_tests`: `6/6`
|
||||
- `XCNewEditor` Debug target builds successfully
|
||||
- `XCNewEditor.exe` native-default smoke run stayed alive for `5s`
|
||||
- `core_ui_tests`: `52 total` (`50` passed, `2` skipped because `KeyCode::Delete` currently aliases `Backspace`)
|
||||
- `scene_tests`: `68/68`
|
||||
- `core_ui_style_tests`: `5/5`
|
||||
- `ui_resource_tests`: `11/11`
|
||||
- `editor_tests` targeted bridge smoke: `3/3`
|
||||
|
||||
## Landed This Phase
|
||||
|
||||
- Demo runtime `TextField` with UTF-8 text insertion, caret state, and backspace.
|
||||
- Demo runtime multiline `TextArea` path in the sandbox and test coverage for caret movement / multiline input.
|
||||
- Common-core `UITextEditing` extraction now owns UTF-8 offset stepping, codepoint counting, line splitting, and vertical caret motion with dedicated `core_ui_tests` coverage.
|
||||
- Common-core `UITextInputController` extraction now owns per-field text state, character insertion, enter-submit, and multiline keyboard editing behavior with dedicated `core_ui_tests` coverage.
|
||||
- Common-core `UIEditorCollectionPrimitives` extraction now owns the editor collection tag taxonomy and default metric resolution used by current `LayoutLab` widget prototypes, with dedicated `core_ui_tests` coverage.
|
||||
- Common-core `UISelectionModel` extraction now owns reusable single-selection state for collection-style widgets, with dedicated `core_ui_tests` coverage.
|
||||
- Common-core `UIExpansionModel` extraction now owns reusable expansion/collapse state for tree/property-style widgets, with dedicated `core_ui_tests` coverage.
|
||||
- Common-core `UIKeyboardNavigationModel` extraction now owns reusable current-index/anchor navigation state for collection-style widgets, with dedicated `core_ui_tests` coverage.
|
||||
- Common-core `UIPropertyEditModel` extraction now owns reusable property-field edit session state, including staged values and commit/cancel behavior, with dedicated `core_ui_tests` coverage.
|
||||
- Runtime frame ownership was tightened again:
|
||||
- `UIScreenPlayer::ConsumeLastFrame()` now exposes consume-style packet ownership at the player layer
|
||||
- `UISystemFrameResult` now carries viewport rect, submitted input event count, frame delta, and focus state
|
||||
- `UISystem::ConsumeLastFrame()` moves the retained packet out of the runtime layer
|
||||
- `UISceneRuntimeContext::ConsumeLastFrame()` forwards the same shared runtime seam upward
|
||||
- Demo runtime text editing was extended with:
|
||||
- click-to-place caret
|
||||
- `Delete` support
|
||||
- `Tab` / `Shift+Tab` indentation for text areas
|
||||
- optional text-area line-number gutter rendering
|
||||
- Demo authored resources updated to exercise the input field.
|
||||
- LayoutLab `ScrollView` prototype with clipping and hover rejection outside clipped content.
|
||||
- LayoutLab editor-widget prototypes for tree/list/property-style sections with dedicated runtime coverage.
|
||||
- LayoutLab click-selection now persists through the shared `UISelectionModel`, including selected-state diagnostics and reusable visual selection feedback on cards, collection rows, and field rows.
|
||||
- LayoutLab tree expansion and property-section collapse now persist through the shared `UIExpansionModel`, including reserved property headers, disclosure glyphs, and runtime coverage for collapsed/expanded visibility.
|
||||
- `XCUIDemoRuntime` now exposes `DrainPendingCommandIds()` so hosts can observe emitted runtime commands in order across pointer/text interactions without scraping UI text or draw-command payloads.
|
||||
- `XCUIDemoRuntime` command recording was tightened so pointer activation, text editing, and shortcut-triggered commands now share one bridge path and preserve mixed ordering in `DrainPendingCommandIds()`.
|
||||
- Schema document support extended with:
|
||||
- retained `UISchemaDefinition` data on `UIDocumentModel`
|
||||
- artifact schema version bump for UI documents
|
||||
- loader/resource accessors and memory accounting
|
||||
- schema compile/load/artifact regression coverage
|
||||
- schema consistency rules for:
|
||||
- `allowedValues` only on `enum`
|
||||
- `documentKind` / `restrictDocumentKind` only on `document`
|
||||
- explicit `documentKind` required when `restrictDocumentKind=true`
|
||||
- Engine runtime layer added:
|
||||
- `UIScreenPlayer`
|
||||
- `UIDocumentScreenHost`
|
||||
- `UISceneRuntimeContext`
|
||||
- `UIScreenStackController`
|
||||
- `UISystem`
|
||||
- layered screen composition and modal blocking semantics
|
||||
- Runtime/game integration scaffolding now includes reusable `HUD/menu/modal` stack helpers on top of `UISystem`.
|
||||
- `UIScreenStackController` replacement now rolls back safely on failure instead of popping the active top layer first.
|
||||
- `SceneRuntime` now exposes XCUI runtime ownership directly:
|
||||
- `GetUISystem()`
|
||||
- `GetUIScreenStackController()`
|
||||
- `GetLastUIFrame()`
|
||||
- `SetUIViewportRect(...)`
|
||||
- `SetUIFocused(...)`
|
||||
- `QueueUIInputEvent(...)`
|
||||
- `ClearQueuedUIInputEvents()`
|
||||
- automatic `UISystem` ticking during `SceneRuntime::Update(...)`
|
||||
- Runtime document-host draw emission now preserves button labels for shared screen rendering.
|
||||
- RHI image path improvements:
|
||||
- clipped image UV adjustment
|
||||
- mirrored image UV preservation
|
||||
- explicit image UV/source-rect submission through `UI::UIDrawData`
|
||||
- external texture binding reuse
|
||||
- per-batch scissor application
|
||||
- Editor bridge helpers now expose:
|
||||
- an `afterUiRender` swapchain callback hook in `D3D12WindowRenderer`
|
||||
- SRV-view based texture descriptor registration in `ImGuiBackendBridge`
|
||||
- smoke tests for window renderer, ImGui backend bridge, and console sink registration
|
||||
- `new_editor` host presentation now has a first-class compositor seam:
|
||||
- `IWindowUICompositor`
|
||||
- `ImGuiWindowUICompositor`
|
||||
- `IEditorHostCompositor`
|
||||
- `ImGuiHostCompositor`
|
||||
- `Application` frame/present flow routed through the compositor instead of direct `m_imguiBackend` ownership
|
||||
- The window-level XCUI compositor seam now also has a dedicated regression target around `ImGuiWindowUICompositor`, covering initialization, render-frame ordering, Win32 message forwarding, texture registration forwarding, and shutdown safety.
|
||||
- The legacy compatibility seam now also has dedicated regression coverage around `LegacyImGuiHostInterop`, covering compat factory wiring, ImGui input-capture forwarding, legacy font bootstrap, and the disabled demo-window path.
|
||||
- The window compositor and hosted-preview seams gained more edge-case coverage around no-UI render passes, compositor re-initialization/rebinding, partial logical-size fallback, and descriptor reuse for repeated queued-frame keys.
|
||||
- `new_editor` now has a dedicated `XCUIEditorCommandRouter` test target covering command registration, replacement, enable predicates, accelerator matching, and policy gates around focus/keyboard capture/text input.
|
||||
- `Application` now integrates `XCUIEditorCommandRouter` into the shell itself:
|
||||
- `View` menu items invoke routed commands instead of directly mutating shell state
|
||||
- shell-level shortcuts now flow from `XCUIWin32InputSource` through `XCUIInputBridge` into command matching
|
||||
- hosted-preview mode toggles still trigger presenter reconfiguration through the routed command bindings
|
||||
- `new_editor` panel canvas ownership is now being split behind `IXCUIPanelCanvasHost`, with an `ImGuiXCUIPanelCanvasHost` adapter carrying the legacy path so panel code stops directly owning `ImGui::Image` / `ImGui::InvisibleButton` / draw-list preview plumbing.
|
||||
- `XCUIDemoPanel` and `XCUILayoutLabPanel` no longer create an ImGui hosted-preview presenter or ImGui panel canvas host implicitly; default construction now stays on null/explicitly injected backends until the outer shell binds a concrete host adapter.
|
||||
- `Application` now binds `ImGuiXCUIPanelCanvasHost` explicitly at the shell composition root, so the current ImGui panel host path is visible as a host-layer decision instead of a panel-layer fallback.
|
||||
- `XCUIDemoPanel` and `XCUILayoutLabPanel` no longer read ImGui input directly; both now consume an injected `IXCUIInputSnapshotSource`, and the new `ImGuiXCUIInputSnapshotSource` keeps the current ImGui-backed input path isolated behind an explicit adapter.
|
||||
- `new_editor` now also has a pure `XCUIShellChromeState` model with dedicated tests, covering shell panel visibility, hosted-preview mode, and shell view toggles without depending on ImGui or `Application`.
|
||||
- `XCUIShellChromeState` now also exposes effective hosted-preview state helpers and shell view-toggle command-id helpers, so shell routing code no longer has to manually combine enablement and requested preview mode.
|
||||
- `XCUIShellChromeState` hosted-preview modes were renamed away from `LegacyImGui`, so XCUI shell state no longer treats ImGui as the generic fallback concept.
|
||||
- The panel-canvas seam now has dedicated null/compat/native coverage around stable debug names, passive-session safety, externally driven native snapshots, and compat-host factory creation without relying on explicit backend/capability reporting.
|
||||
- The native host follow-up is now present in `new_editor`:
|
||||
- `NativeWindowUICompositor` provides a swapchain-native XCUI packet present path beside the legacy ImGui compositor
|
||||
- `Application` now defaults to that native host path and directly composes `XCUI Demo` plus `Layout Lab` into one native shell frame
|
||||
- `NativeXCUIPanelCanvasHost` now drives externally configured native card sessions for that shell path and records hosted surface-image preview commands with preserved UVs
|
||||
- new native compositor/native canvas-host tests now cover the new host seam
|
||||
- `XCUIInputBridge.h` no longer includes `imgui.h`, so XCUI input translation is no longer coupled to ImGui at the public header boundary.
|
||||
- `SceneRuntime` layered XCUI routing now has dedicated regression coverage for:
|
||||
- top-interactive layer input ownership
|
||||
- blocking/modal layer suppression of lower layers
|
||||
- hidden top-layer pass-through back to visible underlying layers
|
||||
- Shared `UITextInputController` coverage now includes more caret-boundary / modifier branches; the remaining `Delete` distinction stays blocked on `KeyCode::Delete` and `KeyCode::Backspace` still sharing the same enum value.
|
||||
- Window compositor texture registration now also flows back into `Application` as XCUI-owned `UITextureRegistration` / `UITextureHandle` data instead of exposing raw `ImTextureID` there.
|
||||
- Hosted preview contracts were tightened again:
|
||||
- generic preview surface metadata stays on XCUI-owned value types
|
||||
- `ImGuiTransitionBackend` moved behind `ImGuiXCUIHostedPreviewPresenter`
|
||||
- generic preview frame submission no longer carries an ImGui draw-list pointer
|
||||
- the ImGui presenter now resolves inline draw targets through an explicit ImGui-only binding seam
|
||||
- panel/runtime callers still preserve the same legacy and native-preview behavior
|
||||
- Native hosted-preview publication milestone is now wired through the default shell path:
|
||||
- `NativeWindowUICompositor` publishes hosted preview textures as SRV-backed XCUI registrations and frees them through the compositor seam
|
||||
- `Application::BeginHostedPreviewFrameLifecycle(...)` now resets queue/registry state for both legacy and native frame paths
|
||||
- hosted-preview surface readiness now keys on published texture availability instead of ImGui-style descriptor validity
|
||||
- `BuildNativeShellDrawData(...)` now queues native preview frames for `XCUI Demo` / `LayoutLab`, while shell cards consume the previously published hosted-surface image with warming/live placeholder text
|
||||
- native compositor and shell-command tests now cover the new publication / lifecycle guards
|
||||
- `LayoutLab` now resolves editor collection widget taxonomy and metrics through shared `UIEditorCollectionPrimitives` helpers instead of duplicating the same tag and metric rules inside the sandbox runtime.
|
||||
- `LayoutLab` runtime now consumes shared keyboard-navigation semantics for list/tree/property traversal, while the remaining panel-level key mapping is tracked as an editor-host integration gap rather than a runtime gap.
|
||||
- `LayoutLab` panel now maps concrete arrow/home/end keys into the shared navigation model, with dedicated panel-level coverage proving that the sandbox UI can actually drive the runtime navigation seam end-to-end.
|
||||
- `new_editor` panel/shell diagnostics improvements for hosted preview state.
|
||||
- XCUI asset document loading changed to prefer direct source compilation before `ResourceManager` fallback for the sandbox path, fixing the LayoutLab crash.
|
||||
- `UIDocumentCompiler.cpp` repaired enough to restore full local builds after the duplicated schema-helper regression.
|
||||
- MSVC debug build hardening was tightened again so large parallel `engine` rebuilds stop tripping over compile-PDB contention.
|
||||
- `XCUIStandaloneTextAtlasProvider` no longer uses ImGui font-atlas/internal baking helpers:
|
||||
- atlas ownership now stays inside a standalone provider implementation built on Windows/GDI glyph rasterization
|
||||
- default editor atlas prewarms the current supported nominal sizes, exposes both `RGBA32` and `Alpha8` atlas views, lazily inserts non-prebaked BMP glyphs, and falls back to `?` for unrasterizable codepoints
|
||||
- standalone atlas coverage now includes reset/rebuild, non-nominal size resolution, lazy glyph insertion/fallback behavior, and smoke use without any ImGui context
|
||||
- Legacy shell chrome / HUD rendering is now split out of the main `Application.cpp` translation unit:
|
||||
- the direct `ImGui::*` shell rendering path now lives in a dedicated legacy-only `Application` implementation file
|
||||
- the main `Application.cpp` native host path no longer directly includes `<imgui.h>`, reducing default-path compile-time coupling while the remaining main-target header/include cleanup stays open
|
||||
- `new_editor` build composition is now split into main/native and compatibility slices:
|
||||
- the main `XCNewEditor` target no longer compiles legacy ImGui shell/panel/backend source files directly
|
||||
- legacy ImGui shell/panel/backend sources plus vendored ImGui sources now build behind a dedicated compatibility static library that the main executable links
|
||||
- the main target no longer carries ImGui include directories or older editor bridge headers on its direct compile surface; those remain confined to the compatibility slice
|
||||
- The default XCUI compile seam is now also cleaner:
|
||||
- generic compositor headers no longer advertise compat-only `CreateImGui*` factories
|
||||
- compat-only host/window compositor factories now live behind `LegacyImGuiHostInterop.*`
|
||||
- public font bootstrap headers no longer leak `ImFont` / `ImFontAtlas` types into generic XCUI consumers
|
||||
|
||||
## Phase Risks Still Open
|
||||
|
||||
- Schema instance validation is still open beyond `.xcschema` self-definition and artifact round-trip coverage.
|
||||
- `ScrollView` is still authored/static; no wheel-driven scrolling or virtualization yet.
|
||||
- `XCNewEditor` no longer depends on ImGui at the default-path header/include level and no longer links `XCNewEditorImGuiCompat`; the legacy shell/panel path now lives only in the standalone compatibility slice.
|
||||
- Legacy panel implementations such as `XCUIDemoPanel` / `XCUILayoutLabPanel` still render as ImGui windows inside the compatibility slice, so editor-layer behavior is not yet fully carried by XCUI-native shell composition.
|
||||
- The default native text path now owns its atlas without ImGui, but the provider is still Windows-only and remains trapped inside `new_editor` instead of a shared/cross-platform text layer.
|
||||
- Hosted-preview compatibility presentation still depends on an ImGui-only inline presenter path when not using the queued native surface path.
|
||||
- Editor widget coverage is still prototype-driven inside `LayoutLab`; it has not yet been promoted into a full reusable shared widget/runtime layer with command routing, virtualization, and property-edit transactions.
|
||||
|
||||
## Execution-Plan Alignment
|
||||
|
||||
- Against `XCUI完整架构设计与执行计划.md`, current `new_editor` progress should be treated as an early `Phase 8` foothold rather than full `Milestone E` completion:
|
||||
- landed: `NativeWindowUICompositor`, native shell packet composition, native hosted-preview publication, XCUI-owned texture registrations, native panel surface-image presentation, standalone native text-atlas ownership inside `new_editor`, legacy `Application` TU split, `XCNewEditorImGuiCompat`, main-target header/include isolation from ImGui, default-executable unlinking from the compatibility slice, compat-only factory/font seam tightening, shared native shell layout helpers, and shared panel-chrome/flat-hierarchy helpers
|
||||
- not yet landed: promotion of the native text-atlas path into a shared/cross-platform text subsystem, shared XCUI-authored editor shell chrome, and retirement of legacy ImGui-window panel implementations
|
||||
- That means the next de-ImGui push should not keep centering on hosted-preview publication; that milestone is now effectively closed for the default native shell path.
|
||||
- The real remaining default-path blockers are:
|
||||
- move editor-layer behavior off the legacy ImGui-window panel implementations and into native/XCUI shell composition
|
||||
- keep compat-only factories/types from drifting back into generic XCUI seams while the compatibility slice remains linked
|
||||
- harden and promote `XCUIStandaloneTextAtlasProvider` / editor font bootstrap into a shared native text subsystem
|
||||
- move native shell chrome out of bespoke `Application` layout code and into a shared XCUI shell model or authored shell document
|
||||
|
||||
## Next Phase
|
||||
|
||||
1. Expand runtime/game-layer ownership from the current `SceneRuntime` UI context into scene-declared HUD/menu bootstrapping, draw submission, and higher-level runtime UI policies.
|
||||
2. Promote the current editor-facing widget prototypes out of authored `LayoutLab` content and into reusable XCUI widget/runtime modules, then continue with toolbar/menu chrome, shell-state adoption, virtualization, and broader focus/multi-selection behavior.
|
||||
3. Push the remaining de-ImGui cleanup from build/header isolation into behavior isolation: keep ImGui confined to `XCNewEditorImGuiCompat`, keep generic XCUI seams free of compat-only factories/types, and keep shrinking the legacy shell boundary.
|
||||
4. Promote the current standalone native text/font path out of `new_editor`, harden its atlas invalidation/caching contract, and keep the remaining font/bootstrap ownership compatibility-only.
|
||||
5. Promote the native shell chrome and card layout out of bespoke `Application` code into a shared XCUI/editor-layer shell model or authored shell document, then retire the remaining ImGui-window panel path.
|
||||
6. Continue phased validation, commit, push, and plan refresh after each stable batch.
|
||||
@@ -1,93 +0,0 @@
|
||||
# XCUI Subplan 01:Core Tree / State / Invalidation
|
||||
|
||||
归档日期:
|
||||
|
||||
- `2026-04-04`
|
||||
|
||||
状态:
|
||||
|
||||
- 已完成
|
||||
|
||||
本次实际完成内容:
|
||||
|
||||
- 新增 XCUI core 基础契约:`UIElementId`、`UIDirtyFlags`、`IUIViewModel`、`RevisionedViewModelBase`
|
||||
- 新增 retained-mode build 层:`UIBuildElementDesc`、`UIBuildList`、`UIBuildContext`
|
||||
- 新增 retained-mode tree 层:`UIElementTree`、`UIElementNode`、`UIElementTreeRebuildResult`
|
||||
- 新增统一入口:`UIContext`
|
||||
- 实现最小闭环:tree rebuild、dirty flag 标记、layout dirty 向祖先传播、dirty root 收集
|
||||
- 新增并验证 UI core 测试:tree 创建、unchanged rebuild、local state invalidation、view model invalidation、structure change、未闭合 build scope 失败
|
||||
|
||||
本次涉及文件:
|
||||
|
||||
- `engine/include/XCEngine/UI/Types.h`
|
||||
- `engine/include/XCEngine/UI/Core/UIInvalidation.h`
|
||||
- `engine/include/XCEngine/UI/Core/UIViewModel.h`
|
||||
- `engine/include/XCEngine/UI/Core/UIBuildContext.h`
|
||||
- `engine/include/XCEngine/UI/Core/UIElementTree.h`
|
||||
- `engine/include/XCEngine/UI/Core/UIContext.h`
|
||||
- `engine/src/UI/Core/UIBuildContext.cpp`
|
||||
- `engine/src/UI/Core/UIElementTree.cpp`
|
||||
- `tests/core/UI/CMakeLists.txt`
|
||||
- `tests/core/UI/test_ui_core.cpp`
|
||||
|
||||
验证结果:
|
||||
|
||||
- `cmake --build . --config Debug --target core_ui_tests`
|
||||
- `ctest -C Debug --output-on-failure -R UICoreTest --test-dir .`
|
||||
- 结果:`6/6` 通过
|
||||
|
||||
当前结论:
|
||||
|
||||
- `Subplan 01` 的最小 retained-mode core 已经可用
|
||||
- 后续 `Subplan 03/05/06/07/08/09` 可以基于这套 core 继续推进
|
||||
|
||||
原始 subplan 内容归档如下:
|
||||
|
||||
# Subplan 01:XCUI Core Tree / State / Invalidation
|
||||
|
||||
目标:
|
||||
|
||||
- 搭出 XCUI 的 retained-mode 核心骨架。
|
||||
- 明确 `ElementTree`、`NodeId`、`View`、`ViewModel`、`dirty flag`、`rebuild`、`lifecycle` 的最小闭环。
|
||||
|
||||
负责人边界:
|
||||
|
||||
- 负责 `engine/include/XCEngine/UI/` 与 `engine/src/UI/Core/` 的核心树模型。
|
||||
- 不负责具体布局算法。
|
||||
- 不负责 ImGui 适配绘制。
|
||||
|
||||
建议目录:
|
||||
|
||||
- `engine/include/XCEngine/UI/Core/`
|
||||
- `engine/src/UI/Core/`
|
||||
- `tests` 中对应 XCUI core 测试文件
|
||||
|
||||
前置依赖:
|
||||
|
||||
- 依赖主线完成 `Phase 0` 的基础类型和 UI 生命周期边界清理。
|
||||
|
||||
现在就可以先做的内容:
|
||||
|
||||
- 设计 `UIElementId` / `UIElement` / `UIContext` / `UIBuildContext`
|
||||
- 设计 dirty 标记与增量重建规则
|
||||
- 设计 ViewModel 读写边界和 command 回调入口
|
||||
- 写最小 tree rebuild 测试
|
||||
|
||||
明确不做:
|
||||
|
||||
- 不接入 `.xcui` 文件
|
||||
- 不接入 editor 面板
|
||||
- 不写具体 widget 大库
|
||||
|
||||
交付物:
|
||||
|
||||
- XCUI core 基础类与生命周期定义
|
||||
- tree rebuild / invalidation / state propagation 单元测试
|
||||
- 一个最小 demo:代码构建 UI tree 并触发一次增量更新
|
||||
|
||||
验收标准:
|
||||
|
||||
- 可以构建一棵稳定的 UI tree
|
||||
- 局部状态变化时只标脏必要节点
|
||||
- 重建逻辑与布局/渲染解耦
|
||||
- 其他 subplan 可以基于该模块定义控件树和状态更新
|
||||
@@ -1,50 +0,0 @@
|
||||
# XCUI Subplan 02:Layout Engine 完成归档
|
||||
|
||||
归档日期:
|
||||
|
||||
- `2026-04-04`
|
||||
|
||||
原始来源:
|
||||
|
||||
- [../XCUI完整架构设计与执行计划.md](../XCUI完整架构设计与执行计划.md)
|
||||
|
||||
本次完成范围:
|
||||
|
||||
- 落地 XCUI 纯算法布局基础类型:
|
||||
- `UILayoutLength`
|
||||
- `UILayoutConstraints`
|
||||
- `UILayoutThickness`
|
||||
- `UILayoutItem`
|
||||
- `UIStackLayoutOptions`
|
||||
- `UIOverlayLayoutOptions`
|
||||
- 落地 measure / arrange 双阶段布局算法
|
||||
- 实现 `Horizontal Stack` / `Vertical Stack` / `Overlay` 三类 MVP 容器
|
||||
- 支持 `px / content / stretch`
|
||||
- 支持 `padding / spacing / margin / min / max / alignment`
|
||||
- 建立独立 `ui_tests` 测试目标并通过验证
|
||||
|
||||
实际代码落点:
|
||||
|
||||
- [engine/include/XCEngine/UI/Types.h](D:/Xuanchi/Main/XCEngine/engine/include/XCEngine/UI/Types.h)
|
||||
- [engine/include/XCEngine/UI/Layout/LayoutTypes.h](D:/Xuanchi/Main/XCEngine/engine/include/XCEngine/UI/Layout/LayoutTypes.h)
|
||||
- [engine/include/XCEngine/UI/Layout/LayoutEngine.h](D:/Xuanchi/Main/XCEngine/engine/include/XCEngine/UI/Layout/LayoutEngine.h)
|
||||
- [tests/Core/Math/CMakeLists.txt](D:/Xuanchi/Main/XCEngine/tests/Core/Math/CMakeLists.txt)
|
||||
- [tests/Core/Math/test_ui_layout.cpp](D:/Xuanchi/Main/XCEngine/tests/Core/Math/test_ui_layout.cpp)
|
||||
|
||||
验证结果:
|
||||
|
||||
- `cmake --build . --config Debug --target math_tests -- /m:1`
|
||||
- `ctest -C Debug --test-dir D:\\Xuanchi\\Main\\XCEngine\\build\\tests\\Core\\Math --output-on-failure -R UI_Layout`
|
||||
- 结果:`5/5 UI_Layout tests passed`
|
||||
|
||||
与原子计划相比,当前仍未覆盖:
|
||||
|
||||
- `Scroll` 容器
|
||||
- 更复杂的主轴分布策略
|
||||
- 与 XCUI tree/state 的正式对接
|
||||
- 文本测量与真实控件树集成
|
||||
|
||||
建议后续承接:
|
||||
|
||||
- 由 `Subplan-01` 提供 tree / node / invalidation 契约后,把当前布局算法接入正式 UI tree
|
||||
- 后续再补 `Scroll`、更完整容器族、文本测量桥接
|
||||
@@ -1,83 +0,0 @@
|
||||
# XCUI Subplan 05: ImGui Transition Backend
|
||||
|
||||
归档日期:
|
||||
- `2026-04-04`
|
||||
|
||||
状态:
|
||||
|
||||
- 已完成
|
||||
|
||||
本次实际完成内容:
|
||||
- 新增 XCUI 绘制数据契约:`UIColor`、`UIDrawCommandType`、`UIDrawCommand`、`UIDrawList`、`UIDrawData`
|
||||
- 新增 `ImGuiTransitionBackend` 过渡后端,支持 `FilledRect`、`RectOutline`、`Text`、`Image`、`PushClipRect`、`PopClipRect`
|
||||
- 新增最小 editor 接入样例 `XCUIDemoPanel`,用于在现有编辑器壳层中演示 XCUI draw data 到 ImGui draw call 的过渡链路
|
||||
- 将 demo panel 接入 editor workspace,并补齐 editor/tests 构建入口
|
||||
- 新增 Subplan-05 配套测试,覆盖 draw data 聚合与 backend flush 行为
|
||||
|
||||
本次涉及文件:
|
||||
- `editor/CMakeLists.txt`
|
||||
- `editor/src/Core/EditorWorkspace.h`
|
||||
- `editor/src/XCUIBackend/ImGuiTransitionBackend.h`
|
||||
- `editor/src/panels/XCUIDemoPanel.cpp`
|
||||
- `editor/src/panels/XCUIDemoPanel.h`
|
||||
- `engine/include/XCEngine/UI/DrawData.h`
|
||||
- `tests/editor/CMakeLists.txt`
|
||||
- `tests/editor/test_xcui_draw_data.cpp`
|
||||
- `tests/editor/test_xcui_imgui_transition_backend.cpp`
|
||||
|
||||
验证结果:
|
||||
- `cmake --build . --config Debug --target editor_tests -- /m:1 /p:CL_MPCount=1`
|
||||
- `ctest -C Debug -R "XCUIDrawDataTest|XCUIImGuiTransitionBackendTest" --output-on-failure`
|
||||
- 结果:`4/4` 通过
|
||||
- `cmake --build . --config Debug --target XCEditor -- /m:1 /p:UseMultiToolTask=false /p:CL_MPCount=1`
|
||||
- 结果:通过
|
||||
|
||||
提交记录:
|
||||
- `75ded6f` `Add XCUI ImGui transition backend MVP`
|
||||
|
||||
当前结论:
|
||||
- `Subplan-05` 的最小过渡后端已经可用,可以作为 XCUI 在 editor 中落地的第一层渲染适配桥
|
||||
- XCUI 逻辑层仍然不直接依赖 ImGui API,ImGui 仅存在于过渡 backend 和 editor 接入层
|
||||
- 后续 `Subplan-08`、`Subplan-09` 可以直接基于这套 draw data 和 transition backend 继续推进
|
||||
|
||||
原始 subplan 内容归档如下:
|
||||
|
||||
# Subplan 05:XCUI ImGui Transition Backend
|
||||
|
||||
目标:
|
||||
- 在过渡阶段,让 ImGui 只承担宿主窗口和 draw submission 容器的职责
|
||||
- 由 XCUI 自己生成 draw list,再交给 ImGui backend 落屏
|
||||
|
||||
负责人边界:
|
||||
- 负责 `editor/src/XCUIBackend/` 或等价新目录
|
||||
- 负责 XCUI draw primitive 到 ImGui draw call 的映射
|
||||
- 不负责 XCUI tree、布局、样式的内部规则
|
||||
|
||||
建议目录:
|
||||
- `editor/src/XCUIBackend/`
|
||||
- `editor/src/UI/` 中与 XCUI backend 直接相关的桥接代码
|
||||
- `tests/Editor` 中 backend 相关测试
|
||||
|
||||
前置依赖:
|
||||
- 需要 `Subplan-01` 给出稳定 draw data 和 frame submission 契约
|
||||
- 需要 `Subplan-03` 提供样式查询结果
|
||||
|
||||
现在就可以先做的内容:
|
||||
- 定义 `UIDrawList` / `UIDrawCommand` / `UIDrawText` / `UIDrawImage` / `UIDrawClip`
|
||||
- 先做矩形、边框、文字、图片四类 primitive
|
||||
- 设计 frame begin / submit / end 的 adapter 流程
|
||||
- 写一个最小 demo panel,用 XCUI draw list 通过 ImGui 显示
|
||||
|
||||
明确不做:
|
||||
- 不做 RHI native backend
|
||||
- 不做 docking 逻辑
|
||||
|
||||
交付物:
|
||||
- XCUI 到 ImGui 的过渡 backend
|
||||
- primitive 转换测试或快照测试
|
||||
- 最小 editor 接入样例
|
||||
|
||||
验收标准:
|
||||
- XCUI 逻辑层不直接依赖 ImGui API
|
||||
- ImGui 只出现在 backend 适配层
|
||||
- 可以渲染基础控件和文本
|
||||
Reference in New Issue
Block a user