Compare commits

...

202 Commits

Author SHA1 Message Date
aa727202af Add managed render pipeline selection bridge 2026-04-15 01:57:14 +08:00
ec6965b0dd Add scriptable render pipeline host 2026-04-15 01:33:42 +08:00
82b8bd22cc Introduce native render pipeline host 2026-04-15 01:26:25 +08:00
d0ce2d7883 Centralize render-graph recording context builders 2026-04-15 01:18:15 +08:00
65b3078c7f Extract builtin forward main-scene graph builder 2026-04-15 01:07:59 +08:00
f6fb396a41 Move camera frame plan logic out of public header 2026-04-15 01:00:40 +08:00
f064d6ed68 Extract camera frame fullscreen stage planner 2026-04-15 00:53:51 +08:00
0afcaa0b3b Move render-graph stage policy into internal host 2026-04-15 00:36:11 +08:00
00fa6fffa0 Group camera frame fullscreen color chain intent 2026-04-15 00:32:23 +08:00
ac836ae961 Extract camera frame stage surface resolver 2026-04-15 00:25:19 +08:00
5edc4ed242 Extract camera frame render-graph stage pass runtime 2026-04-15 00:13:35 +08:00
d92afa27da Extract camera frame render-graph stage record context 2026-04-15 00:08:39 +08:00
8232f59276 Extract camera frame render-graph recording session 2026-04-15 00:01:37 +08:00
16f994b5e5 Extract camera frame render-graph stage dispatcher 2026-04-14 23:44:15 +08:00
bc6fb25ff0 Fix XCUI editor app composition source paths 2026-04-14 23:43:44 +08:00
f26b0024f2 Move camera frame render-graph lifecycle into execution module 2026-04-14 23:38:22 +08:00
3e5b7287c7 Split camera frame render-graph stage recording helpers 2026-04-14 23:33:35 +08:00
39c7ef5fdf Extract camera frame render-graph stage state module 2026-04-14 23:15:40 +08:00
abf30ecfd3 Extract camera frame render-graph stage recording module 2026-04-14 23:03:44 +08:00
61ecb7146d Extract camera frame render-graph execution module 2026-04-14 22:50:16 +08:00
599f622ba4 Extract camera frame render-graph surface utilities 2026-04-14 22:39:35 +08:00
3ea8ce81d6 Factor camera frame render-graph stage build state 2026-04-14 22:28:13 +08:00
a67f8597ba Extract camera frame render-graph stage policy helpers 2026-04-14 22:17:12 +08:00
a02ff65651 Extract camera frame render-graph resource contract header 2026-04-14 22:05:28 +08:00
a3efcda550 Unify camera frame graph resource binding helpers 2026-04-14 22:00:03 +08:00
86eb455ab9 Remove explicit feature-pass shadow graph handle 2026-04-14 21:40:02 +08:00
5b0a1743d9 Formalize camera frame render-graph blackboard resources 2026-04-14 21:34:34 +08:00
1e189ff558 Unify builtin forward phase render graph recording 2026-04-14 21:22:56 +08:00
9980aa9be5 Harden render graph pass capture and feature source-color contract 2026-04-14 21:11:04 +08:00
1d171ea61c Split builtin forward pipeline into feature and internal modules 2026-04-14 20:50:31 +08:00
e1734181a0 audio: return thread-safe state snapshots 2026-04-14 20:44:56 +08:00
c710063d92 Graph-manage camera fullscreen stage routing 2026-04-14 19:32:27 +08:00
c4fe643427 audio: remove unused state lock helpers 2026-04-14 19:24:20 +08:00
23bdf9ed48 audio: snapshot mixer state for render thread 2026-04-14 19:22:24 +08:00
78556ea683 audio: narrow render locking to snapshots 2026-04-14 19:15:23 +08:00
5a938935e1 Remove legacy camera sequence execution path 2026-04-14 19:04:55 +08:00
882df1ae5a audio: switch waveout backend to pull rendering 2026-04-14 19:04:18 +08:00
e77dbe40b1 Graph-ify camera pass sequences 2026-04-14 18:56:04 +08:00
4c79554050 Graph-ify camera stage render passes 2026-04-14 17:16:08 +08:00
4fe456c1a2 Add render-graph blackboard for camera frame resources 2026-04-14 16:59:10 +08:00
3e6e997485 Refine detached tab drag host behavior 2026-04-14 16:56:30 +08:00
2a9264cfe4 Graph-ify forward feature injection points 2026-04-14 16:49:06 +08:00
a4c48c1b3f audio: clear mixer routes on destruction 2026-04-14 16:48:39 +08:00
ee03f7035b audio: extract mix render block from update 2026-04-14 16:42:25 +08:00
3e56757910 audio: make system own master gain semantics 2026-04-14 16:39:29 +08:00
a91df8b4cd Split render-graph main scene into forward segments 2026-04-14 16:31:32 +08:00
0060a348f6 audio: clarify waveout device contract 2026-04-14 16:30:02 +08:00
2eaab2481f audio: reuse audio system scratch buffers 2026-04-14 16:25:11 +08:00
c495581878 Add render-graph main-scene pipeline recording 2026-04-14 16:22:58 +08:00
307259091e Implement multi-window detached tab host flow 2026-04-14 16:19:23 +08:00
4b58df9a61 audio: share decoded clip cache across sources 2026-04-14 16:17:17 +08:00
5de4848d70 Graph-manage single-pass fullscreen stages 2026-04-14 15:08:08 +08:00
3f871a4f45 Lay groundwork for detached editor windows 2026-04-14 15:07:52 +08:00
804e5138d7 Graph-manage main scene imported surfaces 2026-04-14 14:58:40 +08:00
af6de86647 Add render graph runtime UAV support 2026-04-14 14:46:13 +08:00
91c62c6b14 Refine new editor shell host and embedded icons 2026-04-14 14:41:45 +08:00
4ee1bcc599 Integrate graph-managed depth surfaces into camera stages 2026-04-14 14:27:30 +08:00
31a8125fc1 Add render graph runtime depth support 2026-04-14 14:05:59 +08:00
87bf83451b Add render graph depth access semantics 2026-04-14 13:56:08 +08:00
9950e0a44f Move fullscreen graph ownership out of pass transitions 2026-04-14 13:48:59 +08:00
8bd375cd24 Add render graph texture transition plans 2026-04-14 04:45:39 +08:00
c0d62dc749 Support graph-owned imported texture transitions 2026-04-14 04:41:58 +08:00
c98b41f6f4 Implement render graph compiler and transient fullscreen execution 2026-04-14 04:37:07 +08:00
72d09a1c49 Fix editor host resize and dock splitter behavior 2026-04-14 03:34:31 +08:00
ba91e0f5dd Fix borderless host resize presentation ordering 2026-04-14 01:42:44 +08:00
9064c2f5f2 Add borderless editor host chrome 2026-04-14 01:14:45 +08:00
5797a75619 Extract frame-plan fullscreen stage builder 2026-04-14 01:01:45 +08:00
e83f911aef Add borderless host migration plan 2026-04-14 00:56:23 +08:00
dd2299c8b0 Clarify frame plan compatibility adapters 2026-04-14 00:54:47 +08:00
b8d29e39f6 Migrate scene renderer callers to frame plans 2026-04-14 00:52:43 +08:00
72914b3865 Keep shadow execution state out of scene planner 2026-04-14 00:43:55 +08:00
e6950fa704 Switch scene viewport flow to frame plans 2026-04-14 00:40:11 +08:00
21b0530f7b Separate request and frame-stage execution contracts 2026-04-14 00:30:15 +08:00
c3d443eb85 Reduce host swap chain latency 2026-04-14 00:25:57 +08:00
d705cc839b Reduce redundant resize repaint passes 2026-04-13 23:38:45 +08:00
0d6b8bf7d8 Formalize directional shadow runtime contracts 2026-04-13 23:11:28 +08:00
4362008b39 Refactor new editor host resize pipeline 2026-04-13 23:09:02 +08:00
712f99e723 Refactor rendering frame execution contracts 2026-04-13 22:16:04 +08:00
48daaa1bd0 Fix Nahida toon binding and test assets 2026-04-13 21:09:40 +08:00
e462f7d6f7 Add 3DGS D3D12 composite debug checkpoint 2026-04-13 20:17:13 +08:00
5b89c2bb76 Separate viewport target and descriptor ownership 2026-04-13 19:57:25 +08:00
f3fc34898a Refactor new editor host orchestration 2026-04-13 19:37:10 +08:00
d2140bf5cc Checkpoint current new editor host iteration 2026-04-13 18:52:30 +08:00
a0d5e84516 Render 3DGS debug splats as quads 2026-04-13 13:38:41 +08:00
8ba05216fb Establish 3DGS D3D12 sorted baseline 2026-04-13 13:16:57 +08:00
0cc3d6da46 Fix new editor window resize presentation 2026-04-13 12:20:25 +08:00
adb6fe4659 rendering: improve main light shadow receiver filtering 2026-04-13 03:14:06 +08:00
95edf0435f rendering: stabilize single-map directional shadow fitting 2026-04-13 03:13:30 +08:00
82c55b3999 docs: rebuild main light shadow repair plan 2026-04-13 02:24:30 +08:00
00875e0c90 rendering: tune main light shadow bias defaults 2026-04-13 02:24:14 +08:00
b7428b0ef1 Stabilize 3DGS D3D12 phase 3 and sort key setup 2026-04-13 02:23:39 +08:00
1d6f2e290d rendering: formalize main light shadow bias settings 2026-04-13 01:40:29 +08:00
2ee74e7761 rendering: formalize main light shadow params 2026-04-13 01:06:09 +08:00
64212a53c7 Add 3DGS D3D12 MVS bootstrap and PLY loader 2026-04-13 00:36:50 +08:00
6f876678f5 editor: prefer bundled mono runtime discovery 2026-04-13 00:27:11 +08:00
2326857a43 build: remove forced MSVC multi-tool disable 2026-04-13 00:24:49 +08:00
0f60f0f657 Carry backing resource in UI texture handles 2026-04-12 23:25:18 +08:00
dd3731ba66 Execute viewport offscreen frames through D3D12 host 2026-04-12 23:21:59 +08:00
941034b387 Wire viewport shell host chain and move host under app 2026-04-12 23:13:00 +08:00
89590242bd docs(editor): sync script assembly builder api docs 2026-04-12 22:50:50 +08:00
a660fc489a Plan new editor viewport render host migration 2026-04-12 22:35:23 +08:00
e86d260d64 Fix Nahida unlit baseline isolation 2026-04-12 12:48:38 +08:00
347d08463b Fix D3D12 descriptor set staging for shader tables 2026-04-12 11:49:12 +08:00
7ee28a7969 Add gaussian splat asset caching groundwork 2026-04-12 11:15:59 +08:00
b7ce8618d2 Advance new editor hosted panels and state flow 2026-04-12 11:12:27 +08:00
7ad4bfbb1c Extract new editor host command session bridge 2026-04-12 01:49:08 +08:00
838f676fa6 Refactor new editor app context and workspace shell 2026-04-12 01:29:00 +08:00
0ff02150c0 Refine editor tree alignment and project panel events 2026-04-11 22:31:14 +08:00
8848cfd958 chore: checkpoint current workspace changes 2026-04-11 22:14:02 +08:00
3e55f8c204 fix(editor_ui): resolve splitter and tab drag gesture conflict 2026-04-11 20:33:53 +08:00
0a015b52ca feat(new_editor): add project panel and polish dock chrome 2026-04-11 20:20:30 +08:00
030230eb1f Add Nahida model import and preview pipeline 2026-04-11 20:16:49 +08:00
8f71f99de4 Fix FBX winding for Nahida preview 2026-04-11 18:45:49 +08:00
443c56ed08 Center tab labels and unify dock cursor resolution 2026-04-11 17:37:13 +08:00
2958dcc491 Refine XCEditor docking and DPI rendering 2026-04-11 17:07:37 +08:00
35d3d6328b Fix gaussian splat integration GT baseline 2026-04-11 17:07:00 +08:00
c03c7379c8 Precompute gaussian splat chunk visibility 2026-04-11 16:32:40 +08:00
0a2bdedc59 Archive outdated Library cache plans 2026-04-11 15:57:29 +08:00
2fb6eca854 Cull invisible gaussian splat chunks in prepare pass 2026-04-11 14:22:51 +08:00
c543ccf79c Preserve chunk metadata in gaussian splat subset test 2026-04-11 14:02:09 +08:00
88a71a5426 Bind gaussian splat chunk metadata in prepare pass 2026-04-11 13:55:39 +08:00
ff4e3f639a Generate gaussian splat chunks during PLY import 2026-04-11 07:13:32 +08:00
92d5cc61cf Define gaussian splat chunk data contract 2026-04-11 07:07:21 +08:00
b3acb5afc2 Derive gaussian splat SH order from resource layout 2026-04-11 06:57:47 +08:00
785377bc9b Add SH shading to gaussian splat renderer 2026-04-11 06:32:38 +08:00
5200fca82f Add GPU sorting for gaussian splat rendering 2026-04-11 06:09:53 +08:00
39632e1a04 Add gaussian splat integration baseline 2026-04-11 05:37:31 +08:00
3622bf3aa2 Fix builtin pass layout metadata lifetime 2026-04-11 03:24:32 +08:00
fac6e588a8 Formalize gaussian splat prepare-order pass 2026-04-11 03:02:30 +08:00
5191bb1149 Add formal compute pipeline creation API 2026-04-11 02:27:33 +08:00
d9bc0f1457 Add gaussian splat compute shader contracts 2026-04-11 01:30:59 +08:00
4080b2e5fe Fix D3D12 NanoVDB volume load stalls 2026-04-11 00:27:23 +08:00
be5dabd820 Support compute-only shader authoring variants 2026-04-11 00:24:55 +08:00
107b320aa7 Add builtin GaussianSplat forward pass baseline 2026-04-10 23:11:11 +08:00
15b42c248f Formalize GaussianSplat transient pass resources 2026-04-10 22:15:05 +08:00
977a4cf2a4 Unify dock leaves around single-tab stacks 2026-04-10 21:50:31 +08:00
b187c8970b Formalize GaussianSplat scene extraction 2026-04-10 21:49:53 +08:00
1119af2e38 Upgrade project asset watcher to native Win32 notifications 2026-04-10 21:36:53 +08:00
2338e306bf Add editor Assets watcher refresh loop 2026-04-10 21:16:17 +08:00
87ad489bfd Tighten new editor shell chrome and add dock convergence plan 2026-04-10 21:05:07 +08:00
503e6408ed Add model and GaussianSplat asset pipelines 2026-04-10 20:55:48 +08:00
8f5c342799 Formalize GaussianSplat render cache 2026-04-10 20:44:24 +08:00
84faa585d5 docs(plan): add incremental API doc task board 2026-04-10 18:49:37 +08:00
ac9388445c docs(plan): sync api task board completion state 2026-04-10 18:45:07 +08:00
3561bf22bb docs(ui): refresh selection model and resources umbrella docs 2026-04-10 18:42:11 +08:00
e6ac43b454 docs(rendering): refine selection and object id pass docs 2026-04-10 18:36:17 +08:00
2f3a28ec3e docs(rendering): reconcile infinite grid docs 2026-04-10 18:35:23 +08:00
737ccd2e0c docs(rendering): expand render pass foundation docs 2026-04-10 18:32:41 +08:00
bdf0b9a16b docs(rendering): sync infinite grid and depth style pass docs 2026-04-10 18:31:05 +08:00
0c52e0f640 docs(rendering): refine outline and volumetric pass docs 2026-04-10 18:28:20 +08:00
bb9a4d5ef4 docs(rendering): document color scale post-process API 2026-04-10 18:25:06 +08:00
a990553ade docs(rendering): sync outline inputs and volumetric prewarm docs 2026-04-10 18:23:40 +08:00
de2fc8be43 docs(rendering): document builtin final color pass API 2026-04-10 18:18:41 +08:00
effca78771 docs(asset): sync model and volume api docs 2026-04-10 18:17:19 +08:00
0602b34652 docs(rendering): sync render surface state and sample docs 2026-04-10 18:08:37 +08:00
85b8b3e583 docs(rhi): sync buffer init and sample quality docs 2026-04-10 17:59:59 +08:00
cba3823ea2 docs(rhi): document buffer init overload and sample quality 2026-04-10 17:51:45 +08:00
89bbad2786 docs(xceditor): deepen foundation api pages 2026-04-10 17:43:30 +08:00
00cf3850d5 docs(api): align render material resolve docs 2026-04-10 17:37:57 +08:00
81d0d92aed docs(plan): refresh API restructuring status 2026-04-10 17:36:25 +08:00
2d8ada03a1 docs(api): sync archive links and task board status 2026-04-10 17:34:19 +08:00
7fc7bb0a22 docs(api): sync archive and command guidance 2026-04-10 17:33:51 +08:00
447977214e docs(api): sync entry guidance for dual api roots 2026-04-10 17:32:04 +08:00
46fac8a215 docs(api): sync active and archived API entry docs 2026-04-10 17:27:29 +08:00
e2e4e08479 docs(api): refresh audit sync snapshot 2026-04-10 17:26:05 +08:00
e69240db49 docs(components): fix extractor links in component api docs 2026-04-10 17:21:52 +08:00
dd467d2468 docs: drop audit report from commit history 2026-04-10 17:19:45 +08:00
71a27d7c9c docs(api): sync rebuilt API audit boards 2026-04-10 17:16:11 +08:00
f401a54806 docs(rendering): tighten planning and viewport docs 2026-04-10 17:14:27 +08:00
f917040e9a docs(api): add gaussian splat pages and fix doc generators 2026-04-10 17:12:55 +08:00
66ae9ec919 docs: add xceditor api tree and new resource docs 2026-04-10 17:10:42 +08:00
6b90c2f6c3 docs(api): sync xceditor roots and model importer 2026-04-10 17:08:37 +08:00
4d8a51aee2 docs(rendering): realign api docs to module structure 2026-04-10 16:55:33 +08:00
8cde4e0649 Add new editor product shell baseline 2026-04-10 16:40:11 +08:00
1f79afba3c refactor: move builtin forward draw submission internal 2026-04-10 03:01:30 +08:00
57331c1c25 refactor: unify builtin forward scene execution 2026-04-10 02:56:36 +08:00
ff6d6d31fe refactor: isolate builtin forward skybox path 2026-04-10 02:46:17 +08:00
152997c409 refactor: extract directional shadow planning internals 2026-04-10 02:30:09 +08:00
54eb2415ff refactor: formalize directional shadow planning settings 2026-04-10 02:14:45 +08:00
f476890116 Normalize editor shell validation codes 2026-04-10 02:05:07 +08:00
f9bfd48479 Fix editor shell asset header contract 2026-04-10 02:04:24 +08:00
131f46682b test: close render object id coverage gaps 2026-04-10 02:03:45 +08:00
899442c64d refactor editor ui host and shell asset layout 2026-04-10 01:59:15 +08:00
b5ba985831 Formalize render object id contract 2026-04-10 01:57:15 +08:00
4debbbea1f Tighten final color contract 2026-04-10 01:21:00 +08:00
4111f841d4 Formalize volume shader include context 2026-04-10 01:05:03 +08:00
34a32b73dd Restore unrelated rendering docs 2026-04-10 00:42:53 +08:00
02a0e626fe Refactor XCUI editor module layout 2026-04-10 00:41:28 +08:00
4b47764f26 docs: tighten xcui backend doc boundaries 2026-04-10 00:15:55 +08:00
225f533c7c docs(api): refresh rebuild status and close recovery wave 2026-04-10 00:10:08 +08:00
9b074e3020 docs(api): record editor stale-page cleanup audit 2026-04-10 00:06:13 +08:00
3ed69aa82f docs(api): align selection outline pass docs 2026-04-10 00:00:41 +08:00
a545951a58 docs: drop retired xcui demo panel page 2026-04-09 23:56:09 +08:00
2bb511087f docs: refresh xcui panel and backend references 2026-04-09 23:54:17 +08:00
4aaac9887e docs: align widgets and editor panel notes with refactor 2026-04-09 23:52:07 +08:00
cb3d558aaa docs(api): finish volume and volumetric pass coverage 2026-04-09 23:50:33 +08:00
b0625a30bd docs: add second-round api structure refactor plan 2026-04-09 23:47:06 +08:00
d4bec254d1 fix thesis chapter 4 structure 2026-04-09 23:44:56 +08:00
7733d59ed1 Fix OpenGL shader temp file collisions 2026-04-09 23:44:01 +08:00
681452c70e docs(plan): add api doc restructure task board 2026-04-09 23:40:43 +08:00
20b5c22a6a docs: refresh editor xcui and material inspector pages 2026-04-09 23:36:19 +08:00
84db2e951d docs: rewrite README around engine capabilities 2026-04-09 23:35:30 +08:00
1356 changed files with 133568 additions and 17120 deletions

View File

@@ -20,9 +20,11 @@
- [docs/plan/Library启动预热与运行时异步加载混合重构计划_2026-04-04.md](docs/plan/Library启动预热与运行时异步加载混合重构计划_2026-04-04.md)
- [docs/plan/Library启动预热与运行时异步加载混合重构计划_进度更新_2026-04-04.md](docs/plan/Library启动预热与运行时异步加载混合重构计划_进度更新_2026-04-04.md)
- [docs/plan/Editor架构说明.md](docs/plan/Editor架构说明.md)
- [docs/plan/Renderer下一阶段_Unity风格Shader体系正式化计划_2026-04-06.md](docs/plan/Renderer下一阶段_Unity风格Shader体系正式化计划_2026-04-06.md)
- [docs/plan/Unity风格模型导入与Model资产架构重构计划_2026-04-10.md](docs/plan/Unity风格模型导入与Model资产架构重构计划_2026-04-10.md)
- [docs/plan/NanoVDB体积云加载阻塞与Runtime上传修复计划_2026-04-10.md](docs/plan/NanoVDB体积云加载阻塞与Runtime上传修复计划_2026-04-10.md)
- [docs/plan/3DGS专用PLY导入器与GaussianSplat资源缓存正式化计划_2026-04-10.md](docs/plan/3DGS专用PLY导入器与GaussianSplat资源缓存正式化计划_2026-04-10.md)
- [docs/plan/XCUI_NewEditor主线重建计划_2026-04-07.md](docs/plan/XCUI_NewEditor主线重建计划_2026-04-07.md)
- [docs/plan/XCUI完整架构设计与执行计划.md](docs/plan/XCUI完整架构设计与执行计划.md)
- [docs/plan/XCUI_Phase_Status_2026-04-05.md](docs/plan/XCUI_Phase_Status_2026-04-05.md)
- [docs/plan/C#脚本模块下一阶段计划.md](docs/plan/C%23脚本模块下一阶段计划.md)
- [tests/TEST_SPEC.md](tests/TEST_SPEC.md)
- [tests/UI/TEST_SPEC.md](tests/UI/TEST_SPEC.md)
@@ -30,22 +32,35 @@
已归档但当前仍常用的背景文档:
- [Library资产导入与缓存系统收口计划归档](docs/used/Library资产导入与缓存系统收口计划_完成归档_2026-04-03.md)
- [API 文档第三轮任务池(归档基线)](docs/used/API文档实时同步任务池_2026-04-03.md)
- [XCUI Phase Status 2026-04-05归档](docs/used/XCUI_Phase_Status_2026-04-05.md)
- [Shader与Material系统下一阶段计划归档](docs/used/Shader与Material系统下一阶段计划_完成归档_2026-04-04.md)
- [Unity 风格 Shader 体系正式化计划(归档)](docs/used/Renderer下一阶段_Unity风格Shader体系正式化计划_完成归档_2026-04-07.md)
- [Renderer 当前阶段正式收口(阶段归档)](docs/used/Renderer当前阶段正式收口计划_阶段归档_2026-04-10.md)
- [NanoVDB 后续正式化(阶段归档)](docs/used/NanoVDB稀疏体积渲染后续正式化计划_阶段归档_2026-04-10.md)
- [SceneViewport Overlay / Gizmo 重构计划(归档)](docs/used/SceneViewport_Overlay_Gizmo_Rework_Plan_完成归档_2026-04-04.md)
- [Unity式 SceneView Gizmo 正式化方案(归档)](docs/used/Unity式SceneView_Gizmo系统完整审查与正式化重构方案_完成归档_2026-04-06.md)
- [NanoVDB 第一阶段完成归档](docs/used/NanoVDB稀疏体积渲染正式集成计划_第一阶段完成归档_2026-04-09.md)
如果任务落在 API 文档:
1. 先检查 `docs/plan/`有没有日期更晚的 API 相关计划或归档;当前活跃任务池是 [docs/plan/API文档实时同步任务池_2026-04-03.md](docs/plan/API文档实时同步任务池_2026-04-03.md)。这份任务池目前已经推进到第三轮 `T01-T20` 全部完成,结构审计保持全绿,但开始新一轮前仍要先确认是否又追加了新任务块。
2. 再看 [docs/api-skill.md](docs/api-skill.md)
3. 再看 `docs/api/_meta/rebuild-status.md`
4. 一次只认领一个任务块,先改状态为 `DOING`,只写自己任务块允许的范围。
1. 先检查 `docs/plan/`最新的 API 相关计划或并行任务板。当前工作树里已经存在多份 2026-04-09 的活跃文件,例如:
- [docs/plan/API文档目录重构计划_2026-04-09.md](docs/plan/API文档目录重构计划_2026-04-09.md)
- [docs/plan/API文档目录结构重大重构并行任务板_2026-04-09.md](docs/plan/API文档目录结构重大重构并行任务板_2026-04-09.md)
- [docs/plan/API文档目录结构第二轮重构计划_2026-04-09.md](docs/plan/API文档目录结构第二轮重构计划_2026-04-09.md)
- [docs/plan/API文档目录结构第二轮并行任务板_2026-04-09.md](docs/plan/API文档目录结构第二轮并行任务板_2026-04-09.md)
- [docs/plan/API文档目录结构重构并行任务板_2026-04-09_第二轮.md](docs/plan/API文档目录结构重构并行任务板_2026-04-09_第二轮.md)
2. 如果这些活跃文件都不覆盖当前问题,再回看 [docs/used/API文档实时同步任务池_2026-04-03.md](docs/used/API文档实时同步任务池_2026-04-03.md) 作为最近一轮完成基线。
3. 再看 [docs/api-skill.md](docs/api-skill.md)。
4. 再看 `docs/api/main.md``docs/api/_meta/rebuild-status.md`,确认当前问题落在 `XCEngine` 还是 `XCEditor` 根树。
5. 一次只认领一个任务块,先改状态为 `DOING`,只写自己任务块允许的范围。
## 2. 当前工程事实
- 顶层 `CMakeLists.txt` 当前纳入 `engine/``editor/``new_editor/``managed/``mvs/RenderDoc/``tests/`
- `engine/` 构建静态库 `XCEngine``editor/` 构建 `XCEditor`,但输出文件名仍是 `editor/bin/<Config>/XCEngine.exe`
- `new_editor/` 当前构建 `XCUIEditorLib``XCUIEditorHost`;启用 `XCENGINE_BUILD_XCUI_EDITOR_APP` 时会输出 `new_editor/bin/<Config>/XCUIEditor.exe`
- `editor/` 目前继续保留为当前正式编辑器、行为对照和视觉基线来源
- `new_editor/` 当前构建 `XCUIEditorLib``XCUIEditorHost`;启用 `XCENGINE_BUILD_XCUI_EDITOR_APP` 时会输出 `new_editor/bin/<Config>/XCUIEditor.exe`,并被视为未来正式编辑器主线,而不再只是临时 sandbox。
- editor 默认把仓库内的 `project/` 识别为工程根目录,也支持 `--project <path>` 覆盖。
- 当前工程真实使用 `Assets/ + .meta + Library/` 的项目布局;`project/Library/` 是当前 workflow 的一部分,不是可随手忽略的垃圾目录。
- Mono 运行时与 editor 的脚本类发现都从 `<project>/Library/ScriptAssemblies/` 加载程序集。
@@ -81,8 +96,13 @@
- `ObjectId` 渲染与 editor picking
- `BuiltinInfiniteGridPass`
- `BuiltinObjectIdOutlinePass`
- `directional shadow`
- `skybox`
- `CameraRenderRequest::postScenePasses`
- `CameraRenderRequest::overlayPasses`
- `post-process / final color` 当前处于正式化收口阶段,不再是纯预留接口。
- `NanoVDB` 体积渲染已进入当前正式运行链路,但 Vulkan / OpenGL 的 rollout 和多后端能力边界仍在继续收口。
- 当前资源与导入主线正在继续向 `Model` 资产架构与 `3DGS GaussianSplat` 资源链扩展,不要再把 `.obj/.fbx/.ply` 简化理解为“文件直读后立刻渲染”的旧 sample 流程。
- 当前主线不是 render graph而是 shader / material contract、builtin pass contract 和 renderer-owned feature contract。
### 3.3 Editor
@@ -126,13 +146,13 @@
### 3.4 XCUI / New Editor
- `new_editor/`当前 `XCUI` editor sandbox 主线;旧 `editor/` 的整体替换仍处于延后状态,不要把 `XCUI` 计划误读成“已经整体替换现有 editor”
- `new_editor/`未来正式编辑器主线,不再只是 sandbox`editor/` 当前继续保留为正式编辑器、行为对照和视觉基线
- 当前宿主分层是:
- `XCUIEditorLib`
- `XCUIEditorHost`
- `XCUIEditorApp`(可选应用壳)
- 共享 UI core、runtime screen host 与 widget 基础能力主要沉淀在 `engine/include/XCEngine/UI/``engine/src/UI/``new_editor/` 负责 XCUI editor 壳、宿主与 widget sandbox
- XCUI / new_editor 的测试规范以 [tests/UI/TEST_SPEC.md](tests/UI/TEST_SPEC.md) 为准;根目录虽然有 `tests/NewEditor/`,但当前具体测试实现主要放在 `tests/UI/`
- 共享 UI core、runtime screen host 与 widget 基础能力主要沉淀在 `engine/include/XCEngine/UI/``engine/src/UI/``new_editor/` 负责 XCUI editor 壳、宿主与产品装配
- `tests/UI/` 是当前 XCUI `Core / Editor / Runtime` 三层的唯一正式基础层验证入口;`new_editor/` 不承担测试堆场职责
### 3.5 Scripting
@@ -262,15 +282,21 @@
只要任务涉及 `docs/api/`
1.检查 `docs/plan/` 下有没有更新日期更晚的 API 计划或归档
2. 以最新任务池和 [docs/api-skill.md](docs/api-skill.md) 为执行规范
3. 改完必须重新执行:
1. `docs/plan/API文档目录*.md` 里日期最新的 API 计划 / 并行任务板
2. 再看 [docs/api-skill.md](docs/api-skill.md) `docs/api/_meta/rebuild-status.md`
3. 如果活跃计划没有覆盖当前问题,再回看 [docs/used/API文档实时同步任务池_2026-04-03.md](docs/used/API文档实时同步任务池_2026-04-03.md) 作为最近一轮归档基线。
4. 改完必须重新执行:
```powershell
python -B docs/api/_tools/audit_api_docs.py
```
如果审计没回绿,不算完成。
当前审计口径已经同时覆盖:
- `engine/include/XCEngine/**`
- `new_editor/include/XCEditor/**`
- `editor/src/**`
## 5. 推荐构建与验证入口
@@ -321,9 +347,10 @@ ctest --test-dir build -C Debug --output-on-failure
- 资源导入与工程布局:`engine/include/XCEngine/Core/Asset/``engine/src/Core/Asset/``editor/src/Managers/ProjectManager.cpp``project/Assets/``project/Library/`
- Material / shader / artifact`engine/include/XCEngine/Resources/Material/``engine/src/Resources/Material/``engine/include/XCEngine/Core/Asset/ArtifactFormats.h``tests/Resources/Material/`
- Editor viewport / gizmo / picking`editor/src/Viewport/``editor/src/panels/SceneViewPanel.cpp``tests/Editor/`
- XCUI / new_editor`engine/include/XCEngine/UI/``engine/src/UI/``new_editor/include/XCEditor/``new_editor/src/``tests/UI/`
- Editor actions / project routing`editor/src/Actions/``editor/src/Commands/``editor/src/Core/``editor/src/Managers/``tests/Editor/test_action_routing.cpp`
- 脚本运行时与程序集:`engine/include/XCEngine/Scripting/``engine/src/Scripting/``managed/``project/Assets/Scripts/``tests/Scripting/`
- API 文档:`docs/api/XCEngine/``docs/api/_guides/``docs/api/_tools/audit_api_docs.py``docs/plan/API文档实时同步任务池_2026-04-03.md`
- API 文档:`docs/api/main.md``docs/api/XCEngine/``docs/api/XCEditor/``docs/api/_guides/``docs/api/_tools/audit_api_docs.py``docs/plan/API文档目录*.md``docs/used/API文档实时同步任务池_2026-04-03.md`
## 7. 适合当前仓库的工作方式

View File

@@ -1,15 +1,20 @@
cmake_minimum_required(VERSION 3.15)
if(MSVC)
if(POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
endif()
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
"$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
if(POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
endif()
project(XCEngine)
if(MSVC)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
"$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:/MP>")
if(CMAKE_GENERATOR MATCHES "Visual Studio")
set(CMAKE_VS_GLOBALS "UseMultiToolTask=true")
endif()
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -43,9 +48,18 @@ set(
CACHE PATH
"Path to the bundled Mono distribution used by the scripting runtime")
if(EXISTS "${CMAKE_SOURCE_DIR}/engine/third_party/mono/binary/mscorlib.dll")
set(
XCENGINE_MONO_ROOT_DIR
"${CMAKE_SOURCE_DIR}/engine/third_party/mono"
CACHE PATH
"Path to the bundled Mono distribution used by the scripting runtime"
FORCE)
endif()
add_subdirectory(engine)
add_subdirectory(managed)
add_subdirectory(editor)
add_subdirectory(new_editor)
add_subdirectory(managed)
add_subdirectory(mvs/RenderDoc)
add_subdirectory(tests)

View File

@@ -0,0 +1,158 @@
cmake_minimum_required(VERSION 3.20)
project(XC3DGSD3D12MVS LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_program(XC_DXC_EXECUTABLE NAMES dxc)
if(NOT XC_DXC_EXECUTABLE)
message(FATAL_ERROR "dxc is required to build the 3DGS D3D12 MVS sort shaders.")
endif()
get_filename_component(XCENGINE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE)
set(XCENGINE_BUILD_DIR "${XCENGINE_ROOT}/build")
set(XCENGINE_INCLUDE_DIR "${XCENGINE_ROOT}/engine/include")
set(XCENGINE_LIBRARY_DEBUG "${XCENGINE_BUILD_DIR}/engine/Debug/XCEngine.lib")
if(NOT EXISTS "${XCENGINE_LIBRARY_DEBUG}")
message(FATAL_ERROR "Prebuilt XCEngine library was not found: ${XCENGINE_LIBRARY_DEBUG}")
endif()
add_library(XCEngine STATIC IMPORTED GLOBAL)
set_target_properties(XCEngine PROPERTIES
IMPORTED_CONFIGURATIONS "Debug;Release;RelWithDebInfo;MinSizeRel"
IMPORTED_LOCATION_DEBUG "${XCENGINE_LIBRARY_DEBUG}"
IMPORTED_LOCATION_RELEASE "${XCENGINE_LIBRARY_DEBUG}"
IMPORTED_LOCATION_RELWITHDEBINFO "${XCENGINE_LIBRARY_DEBUG}"
IMPORTED_LOCATION_MINSIZEREL "${XCENGINE_LIBRARY_DEBUG}"
)
add_executable(xc_3dgs_d3d12_mvs
WIN32
src/main.cpp
src/App.cpp
src/GaussianPlyLoader.cpp
include/XC3DGSD3D12/App.h
include/XC3DGSD3D12/GaussianPlyLoader.h
shaders/PreparedSplatView.hlsli
shaders/PrepareGaussiansCS.hlsl
shaders/BuildSortKeysCS.hlsl
shaders/SortCommon.hlsl
shaders/DeviceRadixSort.hlsl
shaders/DebugPointsVS.hlsl
shaders/DebugPointsPS.hlsl
shaders/CompositeVS.hlsl
shaders/CompositePS.hlsl
)
set_source_files_properties(
shaders/PreparedSplatView.hlsli
shaders/PrepareGaussiansCS.hlsl
shaders/BuildSortKeysCS.hlsl
shaders/SortCommon.hlsl
shaders/DeviceRadixSort.hlsl
shaders/DebugPointsVS.hlsl
shaders/DebugPointsPS.hlsl
shaders/CompositeVS.hlsl
shaders/CompositePS.hlsl
PROPERTIES
HEADER_FILE_ONLY TRUE
)
target_include_directories(xc_3dgs_d3d12_mvs PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${XCENGINE_INCLUDE_DIR}
)
target_compile_definitions(xc_3dgs_d3d12_mvs PRIVATE
UNICODE
_UNICODE
NOMINMAX
WIN32_LEAN_AND_MEAN
)
if(MSVC)
target_compile_options(xc_3dgs_d3d12_mvs PRIVATE /utf-8)
endif()
target_link_libraries(xc_3dgs_d3d12_mvs PRIVATE
XCEngine
d3d12
dxgi
dxguid
d3dcompiler
winmm
delayimp
bcrypt
opengl32
)
set_target_properties(xc_3dgs_d3d12_mvs PROPERTIES
VS_DEBUGGER_WORKING_DIRECTORY "$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>"
)
add_custom_command(TARGET xc_3dgs_d3d12_mvs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/room.ply"
"$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/room.ply"
)
add_custom_command(TARGET xc_3dgs_d3d12_mvs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/shaders"
"$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/shaders"
)
add_custom_command(TARGET xc_3dgs_d3d12_mvs POST_BUILD
COMMAND "${XC_DXC_EXECUTABLE}"
-T cs_6_6
-E MainCS
-Fo "$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/shaders/BuildSortKeysCS.dxil"
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/BuildSortKeysCS.hlsl"
COMMAND "${XC_DXC_EXECUTABLE}"
-T cs_6_6
-E InitDeviceRadixSort
-D KEY_UINT=1
-D PAYLOAD_UINT=1
-D SORT_PAIRS=1
-D SHOULD_ASCEND=1
-Fo "$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/shaders/RadixInit.dxil"
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/DeviceRadixSort.hlsl"
COMMAND "${XC_DXC_EXECUTABLE}"
-T cs_6_6
-E Upsweep
-D KEY_UINT=1
-D PAYLOAD_UINT=1
-D SORT_PAIRS=1
-D SHOULD_ASCEND=1
-Fo "$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/shaders/RadixUpsweep.dxil"
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/DeviceRadixSort.hlsl"
COMMAND "${XC_DXC_EXECUTABLE}"
-T cs_6_6
-E BuildGlobalHistogram
-D KEY_UINT=1
-D PAYLOAD_UINT=1
-D SORT_PAIRS=1
-D SHOULD_ASCEND=1
-Fo "$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/shaders/RadixGlobalHistogram.dxil"
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/DeviceRadixSort.hlsl"
COMMAND "${XC_DXC_EXECUTABLE}"
-T cs_6_6
-E Scan
-D KEY_UINT=1
-D PAYLOAD_UINT=1
-D SORT_PAIRS=1
-D SHOULD_ASCEND=1
-Fo "$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/shaders/RadixScan.dxil"
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/DeviceRadixSort.hlsl"
COMMAND "${XC_DXC_EXECUTABLE}"
-T cs_6_6
-E Downsweep
-D KEY_UINT=1
-D PAYLOAD_UINT=1
-D SORT_PAIRS=1
-D SHOULD_ASCEND=1
-Fo "$<TARGET_FILE_DIR:xc_3dgs_d3d12_mvs>/shaders/RadixDownsweep.dxil"
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/DeviceRadixSort.hlsl"
)

View File

@@ -0,0 +1,162 @@
#pragma once
#include <windows.h>
#include <memory>
#include <string>
#include <vector>
#include <wrl/client.h>
#include "XC3DGSD3D12/GaussianPlyLoader.h"
#include "XCEngine/RHI/RHIEnums.h"
#include "XCEngine/RHI/RHITypes.h"
#include "XCEngine/RHI/D3D12/D3D12CommandAllocator.h"
#include "XCEngine/RHI/D3D12/D3D12Buffer.h"
#include "XCEngine/RHI/D3D12/D3D12CommandList.h"
#include "XCEngine/RHI/D3D12/D3D12CommandQueue.h"
#include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h"
#include "XCEngine/RHI/D3D12/D3D12Device.h"
#include "XCEngine/RHI/D3D12/D3D12ResourceView.h"
#include "XCEngine/RHI/D3D12/D3D12SwapChain.h"
#include "XCEngine/RHI/D3D12/D3D12Texture.h"
namespace XCEngine {
namespace RHI {
class RHIDescriptorPool;
class RHIDescriptorSet;
class RHIPipelineLayout;
class RHIPipelineState;
} // namespace RHI
} // namespace XCEngine
namespace XC3DGSD3D12 {
struct PreparedSplatView {
float clipPosition[4] = {};
float axis1[2] = {};
float axis2[2] = {};
uint32_t packedColor[2] = {};
};
class App {
public:
App();
~App();
bool Initialize(HINSTANCE instance, int showCommand);
int Run();
void SetFrameLimit(unsigned int frameLimit);
void SetGaussianScenePath(std::wstring scenePath);
void SetSummaryPath(std::wstring summaryPath);
void SetScreenshotPath(std::wstring screenshotPath);
const std::wstring& GetLastErrorMessage() const;
private:
static constexpr int kBackBufferCount = 2;
static constexpr int kDefaultWidth = 1280;
static constexpr int kDefaultHeight = 720;
static LRESULT CALLBACK StaticWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
bool RegisterWindowClass(HINSTANCE instance);
bool CreateMainWindow(HINSTANCE instance, int showCommand);
bool LoadGaussianScene();
bool InitializeRhi();
bool InitializeGaussianGpuResources();
bool InitializePreparePassResources();
bool InitializeSortResources();
bool InitializeDebugDrawResources();
bool InitializeCompositeResources();
void ShutdownGaussianGpuResources();
void ShutdownPreparePassResources();
void ShutdownSortResources();
void ShutdownDebugDrawResources();
void ShutdownCompositeResources();
void Shutdown();
bool CaptureSortSnapshot();
bool CapturePass3HistogramDebug();
void RenderFrame(bool captureScreenshot);
HWND m_hwnd = nullptr;
HINSTANCE m_instance = nullptr;
int m_width = kDefaultWidth;
int m_height = kDefaultHeight;
bool m_running = false;
bool m_isInitialized = false;
bool m_hasRenderedAtLeastOneFrame = false;
unsigned int m_frameLimit = 0;
unsigned int m_renderedFrameCount = 0;
std::wstring m_gaussianScenePath = L"room.ply";
std::wstring m_summaryPath;
std::wstring m_screenshotPath = L"phase3_debug_points.ppm";
std::wstring m_sortKeySnapshotPath = L"phase3_sortkeys.txt";
std::wstring m_lastErrorMessage;
GaussianSplatRuntimeData m_gaussianSceneData;
XCEngine::RHI::D3D12Buffer m_gaussianPositionBuffer;
XCEngine::RHI::D3D12Buffer m_gaussianOtherBuffer;
XCEngine::RHI::D3D12Buffer m_gaussianShBuffer;
XCEngine::RHI::D3D12Texture m_gaussianColorTexture;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_gaussianPositionView;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_gaussianOtherView;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_gaussianShView;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_gaussianColorView;
std::vector<Microsoft::WRL::ComPtr<ID3D12Resource>> m_gaussianUploadBuffers;
XCEngine::RHI::D3D12Buffer* m_preparedViewBuffer = nullptr;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_preparedViewSrv;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_preparedViewUav;
XCEngine::RHI::RHIPipelineLayout* m_preparePipelineLayout = nullptr;
XCEngine::RHI::RHIPipelineState* m_preparePipelineState = nullptr;
XCEngine::RHI::RHIDescriptorPool* m_prepareDescriptorPool = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_prepareDescriptorSet = nullptr;
XCEngine::RHI::D3D12Buffer* m_sortKeyBuffer = nullptr;
XCEngine::RHI::D3D12Buffer* m_sortKeyScratchBuffer = nullptr;
XCEngine::RHI::D3D12Buffer* m_orderBuffer = nullptr;
XCEngine::RHI::D3D12Buffer* m_orderScratchBuffer = nullptr;
XCEngine::RHI::D3D12Buffer* m_passHistogramBuffer = nullptr;
XCEngine::RHI::D3D12Buffer* m_globalHistogramBuffer = nullptr;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_sortKeyUav;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_sortKeyScratchUav;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_orderBufferSrv;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_orderBufferUav;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_orderScratchUav;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_passHistogramUav;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_globalHistogramUav;
XCEngine::RHI::RHIPipelineLayout* m_buildSortKeyPipelineLayout = nullptr;
XCEngine::RHI::RHIPipelineState* m_buildSortKeyPipelineState = nullptr;
XCEngine::RHI::RHIDescriptorPool* m_buildSortKeyDescriptorPool = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_buildSortKeyDescriptorSet = nullptr;
XCEngine::RHI::RHIPipelineLayout* m_radixSortPipelineLayout = nullptr;
XCEngine::RHI::RHIPipelineState* m_radixSortInitPipelineState = nullptr;
XCEngine::RHI::RHIPipelineState* m_radixSortUpsweepPipelineState = nullptr;
XCEngine::RHI::RHIPipelineState* m_radixSortGlobalHistogramPipelineState = nullptr;
XCEngine::RHI::RHIPipelineState* m_radixSortScanPipelineState = nullptr;
XCEngine::RHI::RHIPipelineState* m_radixSortDownsweepPipelineState = nullptr;
XCEngine::RHI::RHIDescriptorPool* m_radixSortDescriptorPool = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_radixSortDescriptorSetPrimaryToScratch = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_radixSortDescriptorSetScratchToPrimary = nullptr;
XCEngine::RHI::RHIPipelineLayout* m_debugPipelineLayout = nullptr;
XCEngine::RHI::RHIPipelineState* m_debugPipelineState = nullptr;
XCEngine::RHI::RHIDescriptorPool* m_debugDescriptorPool = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_debugDescriptorSet = nullptr;
XCEngine::RHI::D3D12Texture m_splatRenderTargetTexture;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_splatRenderTargetRtv;
std::unique_ptr<XCEngine::RHI::D3D12ResourceView> m_splatRenderTargetSrv;
XCEngine::RHI::RHIPipelineLayout* m_compositePipelineLayout = nullptr;
XCEngine::RHI::RHIPipelineState* m_compositePipelineState = nullptr;
XCEngine::RHI::RHIDescriptorPool* m_compositeDescriptorPool = nullptr;
XCEngine::RHI::RHIDescriptorSet* m_compositeDescriptorSet = nullptr;
XCEngine::RHI::D3D12Device m_device;
XCEngine::RHI::D3D12CommandQueue m_commandQueue;
XCEngine::RHI::D3D12SwapChain m_swapChain;
XCEngine::RHI::D3D12CommandAllocator m_commandAllocator;
XCEngine::RHI::D3D12CommandList m_commandList;
XCEngine::RHI::D3D12Texture m_depthStencil;
XCEngine::RHI::D3D12DescriptorHeap m_rtvHeap;
XCEngine::RHI::D3D12DescriptorHeap m_dsvHeap;
XCEngine::RHI::D3D12ResourceView m_rtvs[kBackBufferCount];
XCEngine::RHI::D3D12ResourceView m_dsv;
};
} // namespace XC3DGSD3D12

View File

@@ -0,0 +1,46 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <string>
#include <vector>
namespace XC3DGSD3D12 {
struct Float3 {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
};
struct GaussianSplatRuntimeData {
static constexpr uint32_t kColorTextureWidth = 2048;
static constexpr uint32_t kPositionStride = sizeof(float) * 3;
static constexpr uint32_t kOtherStride = sizeof(uint32_t) + sizeof(float) * 3;
static constexpr uint32_t kColorStride = sizeof(float) * 4;
static constexpr uint32_t kShCoefficientCount = 15;
static constexpr uint32_t kShStride = sizeof(float) * 3 * 16;
uint32_t splatCount = 0;
uint32_t colorTextureWidth = kColorTextureWidth;
uint32_t colorTextureHeight = 0;
Float3 boundsMin = {};
Float3 boundsMax = {};
std::vector<std::byte> positionData;
std::vector<std::byte> otherData;
std::vector<std::byte> colorData;
std::vector<std::byte> shData;
};
bool LoadGaussianSceneFromPly(
const std::filesystem::path& filePath,
GaussianSplatRuntimeData& outData,
std::string& outErrorMessage);
bool WriteGaussianSceneSummary(
const std::filesystem::path& filePath,
const GaussianSplatRuntimeData& data,
std::string& outErrorMessage);
} // namespace XC3DGSD3D12

View File

@@ -0,0 +1,43 @@
#define GROUP_SIZE 64
cbuffer FrameConstants : register(b0)
{
float4x4 gViewProjection;
float4x4 gView;
float4x4 gProjection;
float4 gCameraWorldPos;
float4 gScreenParams;
float4 gSettings;
};
ByteAddressBuffer gPositions : register(t0);
StructuredBuffer<uint> gOrderBuffer : register(t1);
RWStructuredBuffer<uint> gSortKeys : register(u0);
float3 LoadFloat3(ByteAddressBuffer buffer, uint byteOffset)
{
return asfloat(buffer.Load3(byteOffset));
}
uint FloatToSortableUint(float value)
{
uint bits = asuint(value);
uint mask = (0u - (bits >> 31)) | 0x80000000u;
return bits ^ mask;
}
[numthreads(GROUP_SIZE, 1, 1)]
void MainCS(uint3 dispatchThreadId : SV_DispatchThreadID)
{
uint index = dispatchThreadId.x;
uint splatCount = (uint)gSettings.x;
if (index >= splatCount)
{
return;
}
uint splatIndex = gOrderBuffer[index];
float3 position = LoadFloat3(gPositions, splatIndex * 12);
float3 viewPosition = mul(float4(position, 1.0), gView).xyz;
gSortKeys[index] = FloatToSortableUint(viewPosition.z);
}

View File

@@ -0,0 +1,12 @@
Texture2D<float4> gSplatTexture : register(t0);
struct PixelInput
{
float4 position : SV_Position;
};
float4 MainPS(PixelInput input) : SV_Target0
{
float4 color = gSplatTexture.Load(int3(int2(input.position.xy), 0));
return float4(color.rgb, color.a);
}

View File

@@ -0,0 +1,12 @@
struct VertexOutput
{
float4 position : SV_Position;
};
VertexOutput MainVS(uint vertexId : SV_VertexID)
{
VertexOutput output = (VertexOutput)0;
float2 quadPosition = float2(vertexId & 1, (vertexId >> 1) & 1) * 4.0 - 1.0;
output.position = float4(quadPosition, 1.0, 1.0);
return output;
}

View File

@@ -0,0 +1,19 @@
struct PixelInput
{
float4 position : SV_Position;
float4 color : COLOR0;
float2 localPosition : TEXCOORD0;
};
float4 MainPS(PixelInput input) : SV_Target0
{
float alpha = exp(-dot(input.localPosition, input.localPosition));
alpha = saturate(alpha * input.color.a);
if (alpha < (1.0 / 255.0))
{
discard;
}
return float4(input.color.rgb * alpha, alpha);
}

View File

@@ -0,0 +1,48 @@
#include "PreparedSplatView.hlsli"
cbuffer FrameConstants : register(b0)
{
float4x4 gViewProjection;
float4x4 gView;
float4x4 gProjection;
float4 gCameraWorldPos;
float4 gScreenParams;
float4 gSettings;
};
StructuredBuffer<PreparedSplatView> gPreparedViews : register(t0);
StructuredBuffer<uint> gOrderBuffer : register(t1);
struct VertexOutput
{
float4 position : SV_Position;
float4 color : COLOR0;
float2 localPosition : TEXCOORD0;
};
VertexOutput MainVS(uint vertexId : SV_VertexID, uint instanceId : SV_InstanceID)
{
VertexOutput output = (VertexOutput)0;
uint splatIndex = gOrderBuffer[instanceId];
PreparedSplatView view = gPreparedViews[splatIndex];
float4 color = UnpackPreparedColor(view);
if (view.clipPosition.w <= 0.0)
{
const float nanValue = asfloat(0x7fc00000);
output.position = float4(nanValue, nanValue, nanValue, nanValue);
return output;
}
float2 quadPosition = float2(vertexId & 1, (vertexId >> 1) & 1) * 2.0 - 1.0;
quadPosition *= 2.0;
float2 deltaScreenPosition =
(quadPosition.x * view.axis1 + quadPosition.y * view.axis2) * 2.0 / gScreenParams.xy;
output.position = view.clipPosition;
output.position.xy += deltaScreenPosition * view.clipPosition.w;
output.color = color;
output.localPosition = quadPosition;
return output;
}

View File

@@ -0,0 +1,477 @@
/******************************************************************************
* DeviceRadixSort
* Device Level 8-bit LSD Radix Sort using reduce then scan
*
* SPDX-License-Identifier: MIT
* Copyright Thomas Smith 5/17/2024
* https://github.com/b0nes164/GPUSorting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
#include "SortCommon.hlsl"
#define US_DIM 128U //The number of threads in a Upsweep threadblock
#define SCAN_DIM 128U //The number of threads in a Scan threadblock
RWStructuredBuffer<uint> b_globalHist : register(u5); //buffer holding device level offsets for each binning pass
RWStructuredBuffer<uint> b_passHist : register(u4); //buffer used to store reduced sums of partition tiles
groupshared uint g_us[RADIX * 2]; //Shared memory for upsweep
groupshared uint g_scan[SCAN_DIM]; //Shared memory for the scan
//*****************************************************************************
//INIT KERNEL
//*****************************************************************************
//Clear the global histogram, as we will be adding to it atomically
[numthreads(1024, 1, 1)]
void InitDeviceRadixSort(int3 id : SV_DispatchThreadID)
{
b_globalHist[id.x] = 0;
}
//*****************************************************************************
//UPSWEEP KERNEL
//*****************************************************************************
//histogram, 64 threads to a histogram
inline void HistogramDigitCounts(uint gtid, uint gid)
{
const uint histOffset = gtid / 64 * RADIX;
const uint partitionEnd = gid == e_threadBlocks - 1 ?
e_numKeys : (gid + 1) * PART_SIZE;
for (uint i = gtid + gid * PART_SIZE; i < partitionEnd; i += US_DIM)
{
#if defined(KEY_UINT)
InterlockedAdd(g_us[ExtractDigit(b_sort[i]) + histOffset], 1);
#elif defined(KEY_INT)
InterlockedAdd(g_us[ExtractDigit(IntToUint(b_sort[i])) + histOffset], 1);
#elif defined(KEY_FLOAT)
InterlockedAdd(g_us[ExtractDigit(FloatToUint(b_sort[i])) + histOffset], 1);
#endif
}
}
//reduce and pass to tile histogram
inline void ReduceWriteDigitCounts(uint gtid, uint gid)
{
for (uint i = gtid; i < RADIX; i += US_DIM)
{
g_us[i] += g_us[i + RADIX];
b_passHist[i * e_threadBlocks + gid] = g_us[i];
}
}
//Build the per-pass 256-bin exclusive prefix from the reduced pass histogram.
inline void BuildGlobalHistogramExclusive(uint gtid)
{
uint digitIndices[2];
uint digitTotals[2];
uint digitCount = 0;
for (uint i = gtid; i < RADIX; i += US_DIM)
{
uint total = 0u;
const uint baseOffset = i * e_threadBlocks;
for (uint blockIndex = 0; blockIndex < e_threadBlocks; ++blockIndex)
{
total += b_passHist[baseOffset + blockIndex];
}
g_us[i] = total;
digitIndices[digitCount] = i;
digitTotals[digitCount] = total;
++digitCount;
}
GroupMemoryBarrierWithGroupSync();
for (uint offset = 1; offset < RADIX; offset <<= 1)
{
for (uint i = gtid; i < RADIX; i += US_DIM)
{
g_us[i + RADIX] = g_us[i] + (i >= offset ? g_us[i - offset] : 0u);
}
GroupMemoryBarrierWithGroupSync();
for (uint i = gtid; i < RADIX; i += US_DIM)
{
g_us[i] = g_us[i + RADIX];
}
GroupMemoryBarrierWithGroupSync();
}
const uint globalHistOffset = GlobalHistOffset();
for (uint localIndex = 0; localIndex < digitCount; ++localIndex)
{
const uint digitIndex = digitIndices[localIndex];
b_globalHist[digitIndex + globalHistOffset] = g_us[digitIndex] - digitTotals[localIndex];
}
}
[numthreads(US_DIM, 1, 1)]
void Upsweep(uint3 gtid : SV_GroupThreadID, uint3 gid : SV_GroupID)
{
//get the wave size
const uint waveSize = getWaveSize();
//clear shared memory
const uint histsEnd = RADIX * 2;
for (uint i = gtid.x; i < histsEnd; i += US_DIM)
g_us[i] = 0;
GroupMemoryBarrierWithGroupSync();
HistogramDigitCounts(gtid.x, gid.x);
GroupMemoryBarrierWithGroupSync();
ReduceWriteDigitCounts(gtid.x, gid.x);
}
[numthreads(US_DIM, 1, 1)]
void BuildGlobalHistogram(uint3 gtid : SV_GroupThreadID)
{
const uint histsEnd = RADIX * 2;
for (uint i = gtid.x; i < histsEnd; i += US_DIM)
g_us[i] = 0;
GroupMemoryBarrierWithGroupSync();
BuildGlobalHistogramExclusive(gtid.x);
}
//*****************************************************************************
//SCAN KERNEL
//*****************************************************************************
inline void ExclusiveThreadBlockScanFullWGE16(
uint gtid,
uint laneMask,
uint circularLaneShift,
uint partEnd,
uint deviceOffset,
uint waveSize,
inout uint reduction)
{
for (uint i = gtid; i < partEnd; i += SCAN_DIM)
{
g_scan[gtid] = b_passHist[i + deviceOffset];
g_scan[gtid] += WavePrefixSum(g_scan[gtid]);
GroupMemoryBarrierWithGroupSync();
if (gtid < SCAN_DIM / waveSize)
{
g_scan[(gtid + 1) * waveSize - 1] +=
WavePrefixSum(g_scan[(gtid + 1) * waveSize - 1]);
}
GroupMemoryBarrierWithGroupSync();
uint t = (WaveGetLaneIndex() != laneMask ? g_scan[gtid] : 0) + reduction;
if (gtid >= waveSize)
t += WaveReadLaneAt(g_scan[gtid - 1], 0);
b_passHist[circularLaneShift + (i & ~laneMask) + deviceOffset] = t;
reduction += g_scan[SCAN_DIM - 1];
GroupMemoryBarrierWithGroupSync();
}
}
inline void ExclusiveThreadBlockScanPartialWGE16(
uint gtid,
uint laneMask,
uint circularLaneShift,
uint partEnd,
uint deviceOffset,
uint waveSize,
uint reduction)
{
uint i = gtid + partEnd;
if (i < e_threadBlocks)
g_scan[gtid] = b_passHist[deviceOffset + i];
g_scan[gtid] += WavePrefixSum(g_scan[gtid]);
GroupMemoryBarrierWithGroupSync();
if (gtid < SCAN_DIM / waveSize)
{
g_scan[(gtid + 1) * waveSize - 1] +=
WavePrefixSum(g_scan[(gtid + 1) * waveSize - 1]);
}
GroupMemoryBarrierWithGroupSync();
const uint index = circularLaneShift + (i & ~laneMask);
if (index < e_threadBlocks)
{
uint t = (WaveGetLaneIndex() != laneMask ? g_scan[gtid] : 0) + reduction;
if (gtid >= waveSize)
t += g_scan[(gtid & ~laneMask) - 1];
b_passHist[index + deviceOffset] = t;
}
}
inline void ExclusiveThreadBlockScanWGE16(uint gtid, uint gid, uint waveSize)
{
uint reduction = 0;
const uint laneMask = waveSize - 1;
const uint circularLaneShift = WaveGetLaneIndex() + 1 & laneMask;
const uint partionsEnd = e_threadBlocks / SCAN_DIM * SCAN_DIM;
const uint deviceOffset = gid * e_threadBlocks;
ExclusiveThreadBlockScanFullWGE16(
gtid,
laneMask,
circularLaneShift,
partionsEnd,
deviceOffset,
waveSize,
reduction);
ExclusiveThreadBlockScanPartialWGE16(
gtid,
laneMask,
circularLaneShift,
partionsEnd,
deviceOffset,
waveSize,
reduction);
}
inline void ExclusiveThreadBlockScanFullWLT16(
uint gtid,
uint partitions,
uint deviceOffset,
uint laneLog,
uint circularLaneShift,
uint waveSize,
inout uint reduction)
{
for (uint k = 0; k < partitions; ++k)
{
g_scan[gtid] = b_passHist[gtid + k * SCAN_DIM + deviceOffset];
g_scan[gtid] += WavePrefixSum(g_scan[gtid]);
GroupMemoryBarrierWithGroupSync();
if (gtid < waveSize)
{
b_passHist[circularLaneShift + k * SCAN_DIM + deviceOffset] =
(circularLaneShift ? g_scan[gtid] : 0) + reduction;
}
uint offset = laneLog;
uint j = waveSize;
for (; j < (SCAN_DIM >> 1); j <<= laneLog)
{
if (gtid < (SCAN_DIM >> offset))
{
g_scan[((gtid + 1) << offset) - 1] +=
WavePrefixSum(g_scan[((gtid + 1) << offset) - 1]);
}
GroupMemoryBarrierWithGroupSync();
if ((gtid & ((j << laneLog) - 1)) >= j)
{
if (gtid < (j << laneLog))
{
b_passHist[gtid + k * SCAN_DIM + deviceOffset] =
WaveReadLaneAt(g_scan[((gtid >> offset) << offset) - 1], 0) +
((gtid & (j - 1)) ? g_scan[gtid - 1] : 0) + reduction;
}
else
{
if ((gtid + 1) & (j - 1))
{
g_scan[gtid] +=
WaveReadLaneAt(g_scan[((gtid >> offset) << offset) - 1], 0);
}
}
}
offset += laneLog;
}
GroupMemoryBarrierWithGroupSync();
//If SCAN_DIM is not a power of lanecount
for (uint i = gtid + j; i < SCAN_DIM; i += SCAN_DIM)
{
b_passHist[i + k * SCAN_DIM + deviceOffset] =
WaveReadLaneAt(g_scan[((i >> offset) << offset) - 1], 0) +
((i & (j - 1)) ? g_scan[i - 1] : 0) + reduction;
}
reduction += WaveReadLaneAt(g_scan[SCAN_DIM - 1], 0) +
WaveReadLaneAt(g_scan[(((SCAN_DIM - 1) >> offset) << offset) - 1], 0);
GroupMemoryBarrierWithGroupSync();
}
}
inline void ExclusiveThreadBlockScanParitalWLT16(
uint gtid,
uint partitions,
uint deviceOffset,
uint laneLog,
uint circularLaneShift,
uint waveSize,
uint reduction)
{
const uint finalPartSize = e_threadBlocks - partitions * SCAN_DIM;
if (gtid < finalPartSize)
{
g_scan[gtid] = b_passHist[gtid + partitions * SCAN_DIM + deviceOffset];
g_scan[gtid] += WavePrefixSum(g_scan[gtid]);
}
GroupMemoryBarrierWithGroupSync();
if (gtid < waveSize && circularLaneShift < finalPartSize)
{
b_passHist[circularLaneShift + partitions * SCAN_DIM + deviceOffset] =
(circularLaneShift ? g_scan[gtid] : 0) + reduction;
}
uint offset = laneLog;
for (uint j = waveSize; j < finalPartSize; j <<= laneLog)
{
if (gtid < (finalPartSize >> offset))
{
g_scan[((gtid + 1) << offset) - 1] +=
WavePrefixSum(g_scan[((gtid + 1) << offset) - 1]);
}
GroupMemoryBarrierWithGroupSync();
if ((gtid & ((j << laneLog) - 1)) >= j && gtid < finalPartSize)
{
if (gtid < (j << laneLog))
{
b_passHist[gtid + partitions * SCAN_DIM + deviceOffset] =
WaveReadLaneAt(g_scan[((gtid >> offset) << offset) - 1], 0) +
((gtid & (j - 1)) ? g_scan[gtid - 1] : 0) + reduction;
}
else
{
if ((gtid + 1) & (j - 1))
{
g_scan[gtid] +=
WaveReadLaneAt(g_scan[((gtid >> offset) << offset) - 1], 0);
}
}
}
offset += laneLog;
}
}
inline void ExclusiveThreadBlockScanWLT16(uint gtid, uint gid, uint waveSize)
{
uint reduction = 0;
const uint partitions = e_threadBlocks / SCAN_DIM;
const uint deviceOffset = gid * e_threadBlocks;
const uint laneLog = countbits(waveSize - 1);
const uint circularLaneShift = WaveGetLaneIndex() + 1 & waveSize - 1;
ExclusiveThreadBlockScanFullWLT16(
gtid,
partitions,
deviceOffset,
laneLog,
circularLaneShift,
waveSize,
reduction);
ExclusiveThreadBlockScanParitalWLT16(
gtid,
partitions,
deviceOffset,
laneLog,
circularLaneShift,
waveSize,
reduction);
}
//Scan does not need flattening of gids
[numthreads(SCAN_DIM, 1, 1)]
void Scan(uint3 gtid : SV_GroupThreadID, uint3 gid : SV_GroupID)
{
if (gtid.x != 0u)
{
return;
}
const uint deviceOffset = gid.x * e_threadBlocks;
uint runningOffset = 0u;
for (uint blockIndex = 0u; blockIndex < e_threadBlocks; ++blockIndex)
{
const uint index = deviceOffset + blockIndex;
const uint count = b_passHist[index];
b_passHist[index] = runningOffset;
runningOffset += count;
}
}
//*****************************************************************************
//DOWNSWEEP KERNEL
//*****************************************************************************
inline void LoadThreadBlockReductions(uint gtid, uint gid, uint exclusiveHistReduction)
{
if (gtid < RADIX)
{
g_d[gtid + PART_SIZE] = b_globalHist[gtid + GlobalHistOffset()] +
b_passHist[gtid * e_threadBlocks + gid] - exclusiveHistReduction;
}
}
[numthreads(D_DIM, 1, 1)]
void Downsweep(uint3 gtid : SV_GroupThreadID, uint3 gid : SV_GroupID)
{
if (gtid.x != 0u)
{
return;
}
const uint partitionStart = gid.x * PART_SIZE;
const uint partitionEnd = min(partitionStart + PART_SIZE, e_numKeys);
uint digitOffsets[RADIX];
const uint globalHistOffset = GlobalHistOffset();
for (uint digit = 0u; digit < RADIX; ++digit)
{
digitOffsets[digit] =
b_globalHist[globalHistOffset + digit] +
b_passHist[digit * e_threadBlocks + gid.x];
}
for (uint index = partitionStart; index < partitionEnd; ++index)
{
uint key;
#if defined(KEY_UINT)
key = b_sort[index];
#elif defined(KEY_INT)
key = IntToUint(b_sort[index]);
#elif defined(KEY_FLOAT)
key = FloatToUint(b_sort[index]);
#endif
const uint digit = ExtractDigit(key);
const uint destinationIndex = digitOffsets[digit]++;
#if defined(KEY_UINT)
b_alt[destinationIndex] = key;
#elif defined(KEY_INT)
b_alt[destinationIndex] = UintToInt(key);
#elif defined(KEY_FLOAT)
b_alt[destinationIndex] = UintToFloat(key);
#endif
#if defined(SORT_PAIRS)
#if defined(PAYLOAD_UINT)
b_altPayload[destinationIndex] = b_sortPayload[index];
#elif defined(PAYLOAD_INT)
b_altPayload[destinationIndex] = b_sortPayload[index];
#elif defined(PAYLOAD_FLOAT)
b_altPayload[destinationIndex] = b_sortPayload[index];
#endif
#endif
}
}

View File

@@ -0,0 +1,272 @@
#include "PreparedSplatView.hlsli"
#define GROUP_SIZE 64
cbuffer FrameConstants : register(b0)
{
float4x4 gViewProjection;
float4x4 gView;
float4x4 gProjection;
float4 gCameraWorldPos;
float4 gScreenParams;
float4 gSettings;
};
ByteAddressBuffer gPositions : register(t0);
ByteAddressBuffer gOther : register(t1);
Texture2D<float4> gColor : register(t2);
ByteAddressBuffer gSh : register(t3);
RWStructuredBuffer<PreparedSplatView> gPreparedViews : register(u0);
static const float SH_C1 = 0.4886025;
static const float SH_C2[] = { 1.0925484, -1.0925484, 0.3153916, -1.0925484, 0.5462742 };
static const float SH_C3[] = { -0.5900436, 2.8906114, -0.4570458, 0.3731763, -0.4570458, 1.4453057, -0.5900436 };
static const uint kColorTextureWidth = 2048;
static const uint kOtherStride = 16;
static const uint kShStride = 192;
struct SplatSHData
{
float3 col;
float3 sh[15];
};
float3 LoadFloat3(ByteAddressBuffer buffer, uint byteOffset)
{
return asfloat(buffer.Load3(byteOffset));
}
uint EncodeMorton2D_16x16(uint2 c)
{
uint t = ((c.y & 0xF) << 8) | (c.x & 0xF);
t = (t ^ (t << 2)) & 0x3333;
t = (t ^ (t << 1)) & 0x5555;
return (t | (t >> 7)) & 0xFF;
}
uint2 DecodeMorton2D_16x16(uint t)
{
t = (t & 0xFF) | ((t & 0xFE) << 7);
t &= 0x5555;
t = (t ^ (t >> 1)) & 0x3333;
t = (t ^ (t >> 2)) & 0x0F0F;
return uint2(t & 0xF, t >> 8);
}
uint3 SplatIndexToPixelIndex(uint index)
{
uint2 xy = DecodeMorton2D_16x16(index);
uint tileWidth = kColorTextureWidth / 16;
index >>= 8;
uint3 result;
result.x = (index % tileWidth) * 16 + xy.x;
result.y = (index / tileWidth) * 16 + xy.y;
result.z = 0;
return result;
}
float4 DecodePacked_10_10_10_2(uint encoded)
{
return float4(
(encoded & 1023) / 1023.0,
((encoded >> 10) & 1023) / 1023.0,
((encoded >> 20) & 1023) / 1023.0,
((encoded >> 30) & 3) / 3.0);
}
float4 DecodeRotation(float4 packedRotation)
{
uint droppedIndex = (uint)round(packedRotation.w * 3.0);
float4 rotation;
rotation.xyz = packedRotation.xyz * sqrt(2.0) - (1.0 / sqrt(2.0));
rotation.w = sqrt(1.0 - saturate(dot(rotation.xyz, rotation.xyz)));
if (droppedIndex == 0)
{
rotation = rotation.wxyz;
}
if (droppedIndex == 1)
{
rotation = rotation.xwyz;
}
if (droppedIndex == 2)
{
rotation = rotation.xywz;
}
return rotation;
}
float3x3 CalcMatrixFromRotationScale(float4 rotation, float3 scale)
{
float3x3 scaleMatrix = float3x3(
scale.x, 0, 0,
0, scale.y, 0,
0, 0, scale.z);
float x = rotation.x;
float y = rotation.y;
float z = rotation.z;
float w = rotation.w;
float3x3 rotationMatrix = float3x3(
1 - 2 * (y * y + z * z), 2 * (x * y - w * z), 2 * (x * z + w * y),
2 * (x * y + w * z), 1 - 2 * (x * x + z * z), 2 * (y * z - w * x),
2 * (x * z - w * y), 2 * (y * z + w * x), 1 - 2 * (x * x + y * y));
return mul(rotationMatrix, scaleMatrix);
}
void CalcCovariance3D(float3x3 rotationScaleMatrix, out float3 sigma0, out float3 sigma1)
{
float3x3 sigma = mul(rotationScaleMatrix, transpose(rotationScaleMatrix));
sigma0 = float3(sigma._m00, sigma._m01, sigma._m02);
sigma1 = float3(sigma._m11, sigma._m12, sigma._m22);
}
float3 CalcCovariance2D(float3 worldPosition, float3 covariance0, float3 covariance1)
{
float3 viewPosition = mul(float4(worldPosition, 1.0), gView).xyz;
float aspect = gProjection._m00 / gProjection._m11;
float tanFovX = rcp(gProjection._m00);
float tanFovY = rcp(gProjection._m11 * aspect);
float clampX = 1.3 * tanFovX;
float clampY = 1.3 * tanFovY;
viewPosition.x = clamp(viewPosition.x / viewPosition.z, -clampX, clampX) * viewPosition.z;
viewPosition.y = clamp(viewPosition.y / viewPosition.z, -clampY, clampY) * viewPosition.z;
float focal = gScreenParams.x * gProjection._m00 * 0.5;
float3x3 jacobian = float3x3(
focal / viewPosition.z, 0, -(focal * viewPosition.x) / (viewPosition.z * viewPosition.z),
0, focal / viewPosition.z, -(focal * viewPosition.y) / (viewPosition.z * viewPosition.z),
0, 0, 0);
float3x3 worldToView = transpose((float3x3)gView);
float3x3 transform = mul(jacobian, worldToView);
float3x3 covariance = float3x3(
covariance0.x, covariance0.y, covariance0.z,
covariance0.y, covariance1.x, covariance1.y,
covariance0.z, covariance1.y, covariance1.z);
float3x3 projected = mul(transform, mul(covariance, transpose(transform)));
projected._m00 += 0.3;
projected._m11 += 0.3;
return float3(projected._m00, projected._m01, projected._m11);
}
void DecomposeCovariance(float3 covariance2D, out float2 axis1, out float2 axis2)
{
float diagonal0 = covariance2D.x;
float diagonal1 = covariance2D.z;
float offDiagonal = covariance2D.y;
float mid = 0.5 * (diagonal0 + diagonal1);
float radius = length(float2((diagonal0 - diagonal1) * 0.5, offDiagonal));
float lambda0 = mid + radius;
float lambda1 = max(mid - radius, 0.1);
float2 diagonalVector = normalize(float2(offDiagonal, lambda0 - diagonal0));
diagonalVector.y = -diagonalVector.y;
const float maxSize = 4096.0;
axis1 = min(sqrt(2.0 * lambda0), maxSize) * diagonalVector;
axis2 = min(sqrt(2.0 * lambda1), maxSize) * float2(diagonalVector.y, -diagonalVector.x);
}
SplatSHData LoadSplatSH(uint index)
{
SplatSHData sh;
const uint shBaseOffset = index * kShStride;
sh.col = gColor.Load(int3(SplatIndexToPixelIndex(index).xy, 0)).rgb;
[unroll]
for (uint coefficientIndex = 0; coefficientIndex < 15; ++coefficientIndex)
{
sh.sh[coefficientIndex] = LoadFloat3(gSh, shBaseOffset + coefficientIndex * 12);
}
return sh;
}
float3 ShadeSH(SplatSHData sh, float3 direction, int shOrder)
{
direction *= -1.0;
float x = direction.x;
float y = direction.y;
float z = direction.z;
float3 result = sh.col;
if (shOrder >= 1)
{
result += SH_C1 * (-sh.sh[0] * y + sh.sh[1] * z - sh.sh[2] * x);
if (shOrder >= 2)
{
float xx = x * x;
float yy = y * y;
float zz = z * z;
float xy = x * y;
float yz = y * z;
float xz = x * z;
result +=
(SH_C2[0] * xy) * sh.sh[3] +
(SH_C2[1] * yz) * sh.sh[4] +
(SH_C2[2] * (2 * zz - xx - yy)) * sh.sh[5] +
(SH_C2[3] * xz) * sh.sh[6] +
(SH_C2[4] * (xx - yy)) * sh.sh[7];
if (shOrder >= 3)
{
result +=
(SH_C3[0] * y * (3 * xx - yy)) * sh.sh[8] +
(SH_C3[1] * xy * z) * sh.sh[9] +
(SH_C3[2] * y * (4 * zz - xx - yy)) * sh.sh[10] +
(SH_C3[3] * z * (2 * zz - 3 * xx - 3 * yy)) * sh.sh[11] +
(SH_C3[4] * x * (4 * zz - xx - yy)) * sh.sh[12] +
(SH_C3[5] * z * (xx - yy)) * sh.sh[13] +
(SH_C3[6] * x * (xx - 3 * yy)) * sh.sh[14];
}
}
}
return max(result, 0.0);
}
[numthreads(GROUP_SIZE, 1, 1)]
void MainCS(uint3 dispatchThreadId : SV_DispatchThreadID)
{
uint index = dispatchThreadId.x;
uint splatCount = (uint)gSettings.x;
if (index >= splatCount)
{
return;
}
PreparedSplatView view = (PreparedSplatView)0;
float3 position = LoadFloat3(gPositions, index * 12);
uint packedRotation = gOther.Load(index * kOtherStride);
float4 rotation = DecodeRotation(DecodePacked_10_10_10_2(packedRotation));
float3 scale = LoadFloat3(gOther, index * kOtherStride + 4);
float4 colorOpacity = gColor.Load(int3(SplatIndexToPixelIndex(index).xy, 0));
view.clipPosition = mul(float4(position, 1.0), gViewProjection);
if (view.clipPosition.w > 0.0)
{
float3x3 rotationScale = CalcMatrixFromRotationScale(rotation, scale);
float3 covariance0;
float3 covariance1;
CalcCovariance3D(rotationScale, covariance0, covariance1);
float splatScaleSquared = gSettings.w * gSettings.w;
covariance0 *= splatScaleSquared;
covariance1 *= splatScaleSquared;
float3 covariance2D = CalcCovariance2D(position, covariance0, covariance1);
DecomposeCovariance(covariance2D, view.axis1, view.axis2);
SplatSHData sh = LoadSplatSH(index);
float3 viewDirection = normalize(gCameraWorldPos.xyz - position);
float3 shadedColor = ShadeSH(sh, viewDirection, (int)gSettings.z);
float opacity = saturate(colorOpacity.a * gSettings.y);
view.packedColor.x = (f32tof16(shadedColor.r) << 16) | f32tof16(shadedColor.g);
view.packedColor.y = (f32tof16(shadedColor.b) << 16) | f32tof16(opacity);
}
gPreparedViews[index] = view;
}

View File

@@ -0,0 +1,22 @@
#ifndef PREPARED_SPLAT_VIEW_HLSLI
#define PREPARED_SPLAT_VIEW_HLSLI
struct PreparedSplatView
{
float4 clipPosition;
float2 axis1;
float2 axis2;
uint2 packedColor;
};
float4 UnpackPreparedColor(PreparedSplatView view)
{
float4 color;
color.r = f16tof32((view.packedColor.x >> 16) & 0xFFFF);
color.g = f16tof32(view.packedColor.x & 0xFFFF);
color.b = f16tof32((view.packedColor.y >> 16) & 0xFFFF);
color.a = f16tof32(view.packedColor.y & 0xFFFF);
return color;
}
#endif

View File

@@ -0,0 +1,959 @@
/******************************************************************************
* SortCommon
* Common functions for GPUSorting
*
* SPDX-License-Identifier: MIT
* Copyright Thomas Smith 5/17/2024
* https://github.com/b0nes164/GPUSorting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
#define KEYS_PER_THREAD 15U
#define D_DIM 256U
#define PART_SIZE 3840U
#define D_TOTAL_SMEM 4096U
#define RADIX 256U //Number of digit bins
#define RADIX_MASK 255U //Mask of digit bins
#define HALF_RADIX 128U //For smaller waves where bit packing is necessary
#define HALF_MASK 127U // ''
#define RADIX_LOG 8U //log2(RADIX)
#define RADIX_PASSES 4U //(Key width) / RADIX_LOG
cbuffer cbGpuSorting : register(b0)
{
uint e_numKeys;
uint e_radixShift;
uint e_threadBlocks;
uint padding;
};
#if defined(KEY_UINT)
RWStructuredBuffer<uint> b_sort : register(u0);
RWStructuredBuffer<uint> b_alt : register(u1);
#elif defined(KEY_INT)
RWStructuredBuffer<int> b_sort : register(u0);
RWStructuredBuffer<int> b_alt : register(u1);
#elif defined(KEY_FLOAT)
RWStructuredBuffer<float> b_sort : register(u0);
RWStructuredBuffer<float> b_alt : register(u1);
#endif
#if defined(PAYLOAD_UINT)
RWStructuredBuffer<uint> b_sortPayload : register(u2);
RWStructuredBuffer<uint> b_altPayload : register(u3);
#elif defined(PAYLOAD_INT)
RWStructuredBuffer<int> b_sortPayload : register(u2);
RWStructuredBuffer<int> b_altPayload : register(u3);
#elif defined(PAYLOAD_FLOAT)
RWStructuredBuffer<float> b_sortPayload : register(u2);
RWStructuredBuffer<float> b_altPayload : register(u3);
#endif
groupshared uint g_d[D_TOTAL_SMEM]; //Shared memory for DigitBinningPass and DownSweep kernels
struct KeyStruct
{
uint k[KEYS_PER_THREAD];
};
struct OffsetStruct
{
#if defined(ENABLE_16_BIT)
uint16_t o[KEYS_PER_THREAD];
#else
uint o[KEYS_PER_THREAD];
#endif
};
struct DigitStruct
{
#if defined(ENABLE_16_BIT)
uint16_t d[KEYS_PER_THREAD];
#else
uint d[KEYS_PER_THREAD];
#endif
};
//*****************************************************************************
//HELPER FUNCTIONS
//*****************************************************************************
//Due to a bug with SPIRV pre 1.6, we cannot use WaveGetLaneCount() to get the currently active wavesize
inline uint getWaveSize()
{
#if defined(VULKAN)
GroupMemoryBarrierWithGroupSync(); //Make absolutely sure the wave is not diverged here
return dot(countbits(WaveActiveBallot(true)), uint4(1, 1, 1, 1));
#else
return WaveGetLaneCount();
#endif
}
inline uint getWaveIndex(uint gtid, uint waveSize)
{
return gtid / waveSize;
}
//Radix Tricks by Michael Herf
//http://stereopsis.com/radix.html
inline uint FloatToUint(float f)
{
uint mask = -((int) (asuint(f) >> 31)) | 0x80000000;
return asuint(f) ^ mask;
}
inline float UintToFloat(uint u)
{
uint mask = ((u >> 31) - 1) | 0x80000000;
return asfloat(u ^ mask);
}
inline uint IntToUint(int i)
{
return asuint(i ^ 0x80000000);
}
inline int UintToInt(uint u)
{
return asint(u ^ 0x80000000);
}
inline uint getWaveCountPass(uint waveSize)
{
return D_DIM / waveSize;
}
inline uint ExtractDigit(uint key)
{
return key >> e_radixShift & RADIX_MASK;
}
inline uint ExtractDigit(uint key, uint shift)
{
return key >> shift & RADIX_MASK;
}
inline uint ExtractPackedIndex(uint key)
{
return key >> (e_radixShift + 1) & HALF_MASK;
}
inline uint ExtractPackedShift(uint key)
{
return (key >> e_radixShift & 1) ? 16 : 0;
}
inline uint ExtractPackedValue(uint packed, uint key)
{
return packed >> ExtractPackedShift(key) & 0xffff;
}
inline uint SubPartSizeWGE16(uint waveSize)
{
return KEYS_PER_THREAD * waveSize;
}
inline uint SharedOffsetWGE16(uint gtid, uint waveSize)
{
return WaveGetLaneIndex() + getWaveIndex(gtid, waveSize) * SubPartSizeWGE16(waveSize);
}
inline uint SubPartSizeWLT16(uint waveSize, uint _serialIterations)
{
return KEYS_PER_THREAD * waveSize * _serialIterations;
}
inline uint SharedOffsetWLT16(uint gtid, uint waveSize, uint _serialIterations)
{
return WaveGetLaneIndex() +
(getWaveIndex(gtid, waveSize) / _serialIterations * SubPartSizeWLT16(waveSize, _serialIterations)) +
(getWaveIndex(gtid, waveSize) % _serialIterations * waveSize);
}
inline uint DeviceOffsetWGE16(uint gtid, uint waveSize, uint partIndex)
{
return SharedOffsetWGE16(gtid, waveSize) + partIndex * PART_SIZE;
}
inline uint DeviceOffsetWLT16(uint gtid, uint waveSize, uint partIndex, uint serialIterations)
{
return SharedOffsetWLT16(gtid, waveSize, serialIterations) + partIndex * PART_SIZE;
}
inline uint GlobalHistOffset()
{
return e_radixShift << 5;
}
inline uint WaveHistsSizeWGE16(uint waveSize)
{
return D_DIM / waveSize * RADIX;
}
inline uint WaveHistsSizeWLT16()
{
return D_TOTAL_SMEM;
}
//*****************************************************************************
//FUNCTIONS COMMON TO THE DOWNSWEEP / DIGIT BINNING PASS
//*****************************************************************************
//If the size of a wave is too small, we do not have enough space in
//shared memory to assign a histogram to each wave, so instead,
//some operations are peformed serially.
inline uint SerialIterations(uint waveSize)
{
return (D_DIM / waveSize + 31) >> 5;
}
inline void ClearWaveHists(uint gtid, uint waveSize)
{
const uint histsEnd = waveSize >= 16 ?
WaveHistsSizeWGE16(waveSize) : WaveHistsSizeWLT16();
for (uint i = gtid; i < histsEnd; i += D_DIM)
g_d[i] = 0;
}
inline void LoadKey(inout uint key, uint index)
{
#if defined(KEY_UINT)
key = b_sort[index];
#elif defined(KEY_INT)
key = UintToInt(b_sort[index]);
#elif defined(KEY_FLOAT)
key = FloatToUint(b_sort[index]);
#endif
}
inline void LoadDummyKey(inout uint key)
{
key = 0xffffffff;
}
inline KeyStruct LoadKeysWGE16(uint gtid, uint waveSize, uint partIndex)
{
KeyStruct keys;
[unroll]
for (uint i = 0, t = DeviceOffsetWGE16(gtid, waveSize, partIndex);
i < KEYS_PER_THREAD;
++i, t += waveSize)
{
LoadKey(keys.k[i], t);
}
return keys;
}
inline KeyStruct LoadKeysWLT16(uint gtid, uint waveSize, uint partIndex, uint serialIterations)
{
KeyStruct keys;
[unroll]
for (uint i = 0, t = DeviceOffsetWLT16(gtid, waveSize, partIndex, serialIterations);
i < KEYS_PER_THREAD;
++i, t += waveSize * serialIterations)
{
LoadKey(keys.k[i], t);
}
return keys;
}
inline KeyStruct LoadKeysPartialWGE16(uint gtid, uint waveSize, uint partIndex)
{
KeyStruct keys;
[unroll]
for (uint i = 0, t = DeviceOffsetWGE16(gtid, waveSize, partIndex);
i < KEYS_PER_THREAD;
++i, t += waveSize)
{
if (t < e_numKeys)
LoadKey(keys.k[i], t);
else
LoadDummyKey(keys.k[i]);
}
return keys;
}
inline KeyStruct LoadKeysPartialWLT16(uint gtid, uint waveSize, uint partIndex, uint serialIterations)
{
KeyStruct keys;
[unroll]
for (uint i = 0, t = DeviceOffsetWLT16(gtid, waveSize, partIndex, serialIterations);
i < KEYS_PER_THREAD;
++i, t += waveSize * serialIterations)
{
if (t < e_numKeys)
LoadKey(keys.k[i], t);
else
LoadDummyKey(keys.k[i]);
}
return keys;
}
inline uint WaveFlagsWGE16(uint waveSize)
{
return (waveSize & 31) ? (1U << waveSize) - 1 : 0xffffffff;
}
inline uint WaveFlagsWLT16(uint waveSize)
{
return (1U << waveSize) - 1;;
}
inline void WarpLevelMultiSplitWGE16(uint key, inout uint4 waveFlags)
{
[unroll]
for (uint k = 0; k < RADIX_LOG; ++k)
{
const uint currentBit = 1U << (k + e_radixShift);
const bool t = (key & currentBit) != 0;
GroupMemoryBarrierWithGroupSync(); //Play on the safe side, throw in a barrier for convergence
const uint4 ballot = WaveActiveBallot(t);
if(t)
waveFlags &= ballot;
else
waveFlags &= (~ballot);
}
}
inline uint2 CountBitsWGE16(uint waveSize, uint ltMask, uint4 waveFlags)
{
uint2 count = uint2(0, 0);
for(uint wavePart = 0; wavePart < waveSize; wavePart += 32)
{
uint t = countbits(waveFlags[wavePart >> 5]);
if (WaveGetLaneIndex() >= wavePart)
{
if (WaveGetLaneIndex() >= wavePart + 32)
count.x += t;
else
count.x += countbits(waveFlags[wavePart >> 5] & ltMask);
}
count.y += t;
}
return count;
}
inline void WarpLevelMultiSplitWLT16(uint key, inout uint waveFlags)
{
[unroll]
for (uint k = 0; k < RADIX_LOG; ++k)
{
const bool t = key >> (k + e_radixShift) & 1;
waveFlags &= (t ? 0 : 0xffffffff) ^ (uint) WaveActiveBallot(t);
}
}
inline OffsetStruct RankKeysWGE16(
uint waveSize,
uint waveOffset,
KeyStruct keys)
{
OffsetStruct offsets;
const uint initialFlags = WaveFlagsWGE16(waveSize);
const uint ltMask = (1U << (WaveGetLaneIndex() & 31)) - 1;
[unroll]
for (uint i = 0; i < KEYS_PER_THREAD; ++i)
{
uint4 waveFlags = initialFlags;
WarpLevelMultiSplitWGE16(keys.k[i], waveFlags);
const uint index = ExtractDigit(keys.k[i]) + waveOffset;
const uint2 bitCount = CountBitsWGE16(waveSize, ltMask, waveFlags);
offsets.o[i] = g_d[index] + bitCount.x;
GroupMemoryBarrierWithGroupSync();
if (bitCount.x == 0)
g_d[index] += bitCount.y;
GroupMemoryBarrierWithGroupSync();
}
return offsets;
}
inline OffsetStruct RankKeysWLT16(uint waveSize, uint waveIndex, KeyStruct keys, uint serialIterations)
{
OffsetStruct offsets;
const uint ltMask = (1U << WaveGetLaneIndex()) - 1;
const uint initialFlags = WaveFlagsWLT16(waveSize);
[unroll]
for (uint i = 0; i < KEYS_PER_THREAD; ++i)
{
uint waveFlags = initialFlags;
WarpLevelMultiSplitWLT16(keys.k[i], waveFlags);
const uint index = ExtractPackedIndex(keys.k[i]) +
(waveIndex / serialIterations * HALF_RADIX);
const uint peerBits = countbits(waveFlags & ltMask);
for (uint k = 0; k < serialIterations; ++k)
{
if (waveIndex % serialIterations == k)
offsets.o[i] = ExtractPackedValue(g_d[index], keys.k[i]) + peerBits;
GroupMemoryBarrierWithGroupSync();
if (waveIndex % serialIterations == k && peerBits == 0)
{
InterlockedAdd(g_d[index],
countbits(waveFlags) << ExtractPackedShift(keys.k[i]));
}
GroupMemoryBarrierWithGroupSync();
}
}
return offsets;
}
inline uint WaveHistInclusiveScanCircularShiftWGE16(uint gtid, uint waveSize)
{
uint histReduction = g_d[gtid];
for (uint i = gtid + RADIX; i < WaveHistsSizeWGE16(waveSize); i += RADIX)
{
histReduction += g_d[i];
g_d[i] = histReduction - g_d[i];
}
return histReduction;
}
inline uint WaveHistInclusiveScanCircularShiftWLT16(uint gtid)
{
uint histReduction = g_d[gtid];
for (uint i = gtid + HALF_RADIX; i < WaveHistsSizeWLT16(); i += HALF_RADIX)
{
histReduction += g_d[i];
g_d[i] = histReduction - g_d[i];
}
return histReduction;
}
inline void WaveHistReductionExclusiveScanWGE16(uint gtid, uint waveSize, uint histReduction)
{
if (gtid < RADIX)
{
const uint laneMask = waveSize - 1;
g_d[((WaveGetLaneIndex() + 1) & laneMask) + (gtid & ~laneMask)] = histReduction;
}
GroupMemoryBarrierWithGroupSync();
if (gtid < RADIX / waveSize)
{
g_d[gtid * waveSize] =
WavePrefixSum(g_d[gtid * waveSize]);
}
GroupMemoryBarrierWithGroupSync();
uint t = WaveReadLaneAt(g_d[gtid], 0);
if (gtid < RADIX && WaveGetLaneIndex())
g_d[gtid] += t;
}
//inclusive/exclusive prefix sum up the histograms,
//use a blelloch scan for in place packed exclusive
inline void WaveHistReductionExclusiveScanWLT16(uint gtid)
{
uint shift = 1;
for (uint j = RADIX >> 2; j > 0; j >>= 1)
{
GroupMemoryBarrierWithGroupSync();
if (gtid < j)
{
g_d[((((gtid << 1) + 2) << shift) - 1) >> 1] +=
g_d[((((gtid << 1) + 1) << shift) - 1) >> 1] & 0xffff0000;
}
shift++;
}
GroupMemoryBarrierWithGroupSync();
if (gtid == 0)
g_d[HALF_RADIX - 1] &= 0xffff;
for (uint j = 1; j < RADIX >> 1; j <<= 1)
{
--shift;
GroupMemoryBarrierWithGroupSync();
if (gtid < j)
{
const uint t = ((((gtid << 1) + 1) << shift) - 1) >> 1;
const uint t2 = ((((gtid << 1) + 2) << shift) - 1) >> 1;
const uint t3 = g_d[t];
g_d[t] = (g_d[t] & 0xffff) | (g_d[t2] & 0xffff0000);
g_d[t2] += t3 & 0xffff0000;
}
}
GroupMemoryBarrierWithGroupSync();
if (gtid < HALF_RADIX)
{
const uint t = g_d[gtid];
g_d[gtid] = (t >> 16) + (t << 16) + (t & 0xffff0000);
}
}
inline void UpdateOffsetsWGE16(
uint gtid,
uint waveSize,
inout OffsetStruct offsets,
KeyStruct keys)
{
if (gtid >= waveSize)
{
const uint t = getWaveIndex(gtid, waveSize) * RADIX;
[unroll]
for (uint i = 0; i < KEYS_PER_THREAD; ++i)
{
const uint t2 = ExtractDigit(keys.k[i]);
offsets.o[i] += g_d[t2 + t] + g_d[t2];
}
}
else
{
[unroll]
for (uint i = 0; i < KEYS_PER_THREAD; ++i)
offsets.o[i] += g_d[ExtractDigit(keys.k[i])];
}
}
inline void UpdateOffsetsWLT16(
uint gtid,
uint waveSize,
uint serialIterations,
inout OffsetStruct offsets,
KeyStruct keys)
{
if (gtid >= waveSize * serialIterations)
{
const uint t = getWaveIndex(gtid, waveSize) / serialIterations * HALF_RADIX;
[unroll]
for (uint i = 0; i < KEYS_PER_THREAD; ++i)
{
const uint t2 = ExtractPackedIndex(keys.k[i]);
offsets.o[i] += ExtractPackedValue(g_d[t2 + t] + g_d[t2], keys.k[i]);
}
}
else
{
[unroll]
for (uint i = 0; i < KEYS_PER_THREAD; ++i)
offsets.o[i] += ExtractPackedValue(g_d[ExtractPackedIndex(keys.k[i])], keys.k[i]);
}
}
inline void ScatterKeysShared(OffsetStruct offsets, KeyStruct keys)
{
[unroll]
for (uint i = 0; i < KEYS_PER_THREAD; ++i)
g_d[offsets.o[i]] = keys.k[i];
}
inline uint DescendingIndex(uint deviceIndex)
{
return e_numKeys - deviceIndex - 1;
}
inline void WriteKey(uint deviceIndex, uint groupSharedIndex)
{
#if defined(KEY_UINT)
b_alt[deviceIndex] = g_d[groupSharedIndex];
#elif defined(KEY_INT)
b_alt[deviceIndex] = UintToInt(g_d[groupSharedIndex]);
#elif defined(KEY_FLOAT)
b_alt[deviceIndex] = UintToFloat(g_d[groupSharedIndex]);
#endif
}
inline void LoadPayload(inout uint payload, uint deviceIndex)
{
#if defined(PAYLOAD_UINT)
payload = b_sortPayload[deviceIndex];
#elif defined(PAYLOAD_INT) || defined(PAYLOAD_FLOAT)
payload = asuint(b_sortPayload[deviceIndex]);
#endif
}
inline void ScatterPayloadsShared(OffsetStruct offsets, KeyStruct payloads)
{
ScatterKeysShared(offsets, payloads);
}
inline void WritePayload(uint deviceIndex, uint groupSharedIndex)
{
#if defined(PAYLOAD_UINT)
b_altPayload[deviceIndex] = g_d[groupSharedIndex];
#elif defined(PAYLOAD_INT)
b_altPayload[deviceIndex] = asint(g_d[groupSharedIndex]);
#elif defined(PAYLOAD_FLOAT)
b_altPayload[deviceIndex] = asfloat(g_d[groupSharedIndex]);
#endif
}
//*****************************************************************************
//SCATTERING: FULL PARTITIONS
//*****************************************************************************
//KEYS ONLY
inline void ScatterKeysOnlyDeviceAscending(uint gtid)
{
for (uint i = gtid; i < PART_SIZE; i += D_DIM)
WriteKey(g_d[ExtractDigit(g_d[i]) + PART_SIZE] + i, i);
}
inline void ScatterKeysOnlyDeviceDescending(uint gtid)
{
if (e_radixShift == 24)
{
for (uint i = gtid; i < PART_SIZE; i += D_DIM)
WriteKey(DescendingIndex(g_d[ExtractDigit(g_d[i]) + PART_SIZE] + i), i);
}
else
{
ScatterKeysOnlyDeviceAscending(gtid);
}
}
inline void ScatterKeysOnlyDevice(uint gtid)
{
#if defined(SHOULD_ASCEND)
ScatterKeysOnlyDeviceAscending(gtid);
#else
ScatterKeysOnlyDeviceDescending(gtid);
#endif
}
//KEY VALUE PAIRS
inline void ScatterPairsKeyPhaseAscending(
uint gtid,
inout DigitStruct digits)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
{
digits.d[i] = ExtractDigit(g_d[t]);
WriteKey(g_d[digits.d[i] + PART_SIZE] + t, t);
}
}
inline void ScatterPairsKeyPhaseDescending(
uint gtid,
inout DigitStruct digits)
{
if (e_radixShift == 24)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
{
digits.d[i] = ExtractDigit(g_d[t]);
WriteKey(DescendingIndex(g_d[digits.d[i] + PART_SIZE] + t), t);
}
}
else
{
ScatterPairsKeyPhaseAscending(gtid, digits);
}
}
inline void LoadPayloadsWGE16(
uint gtid,
uint waveSize,
uint partIndex,
inout KeyStruct payloads)
{
[unroll]
for (uint i = 0, t = DeviceOffsetWGE16(gtid, waveSize, partIndex);
i < KEYS_PER_THREAD;
++i, t += waveSize)
{
LoadPayload(payloads.k[i], t);
}
}
inline void LoadPayloadsWLT16(
uint gtid,
uint waveSize,
uint partIndex,
uint serialIterations,
inout KeyStruct payloads)
{
[unroll]
for (uint i = 0, t = DeviceOffsetWLT16(gtid, waveSize, partIndex, serialIterations);
i < KEYS_PER_THREAD;
++i, t += waveSize * serialIterations)
{
LoadPayload(payloads.k[i], t);
}
}
inline void ScatterPayloadsAscending(uint gtid, DigitStruct digits)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
WritePayload(g_d[digits.d[i] + PART_SIZE] + t, t);
}
inline void ScatterPayloadsDescending(uint gtid, DigitStruct digits)
{
if (e_radixShift == 24)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
WritePayload(DescendingIndex(g_d[digits.d[i] + PART_SIZE] + t), t);
}
else
{
ScatterPayloadsAscending(gtid, digits);
}
}
inline void ScatterPairsDevice(
uint gtid,
uint waveSize,
uint partIndex,
OffsetStruct offsets)
{
DigitStruct digits;
#if defined(SHOULD_ASCEND)
ScatterPairsKeyPhaseAscending(gtid, digits);
#else
ScatterPairsKeyPhaseDescending(gtid, digits);
#endif
GroupMemoryBarrierWithGroupSync();
KeyStruct payloads;
if (waveSize >= 16)
LoadPayloadsWGE16(gtid, waveSize, partIndex, payloads);
else
LoadPayloadsWLT16(gtid, waveSize, partIndex, SerialIterations(waveSize), payloads);
ScatterPayloadsShared(offsets, payloads);
GroupMemoryBarrierWithGroupSync();
#if defined(SHOULD_ASCEND)
ScatterPayloadsAscending(gtid, digits);
#else
ScatterPayloadsDescending(gtid, digits);
#endif
}
inline void ScatterDevice(
uint gtid,
uint waveSize,
uint partIndex,
OffsetStruct offsets)
{
#if defined(SORT_PAIRS)
ScatterPairsDevice(
gtid,
waveSize,
partIndex,
offsets);
#else
ScatterKeysOnlyDevice(gtid);
#endif
}
//*****************************************************************************
//SCATTERING: PARTIAL PARTITIONS
//*****************************************************************************
//KEYS ONLY
inline void ScatterKeysOnlyDevicePartialAscending(uint gtid, uint finalPartSize)
{
for (uint i = gtid; i < PART_SIZE; i += D_DIM)
{
if (i < finalPartSize)
WriteKey(g_d[ExtractDigit(g_d[i]) + PART_SIZE] + i, i);
}
}
inline void ScatterKeysOnlyDevicePartialDescending(uint gtid, uint finalPartSize)
{
if (e_radixShift == 24)
{
for (uint i = gtid; i < PART_SIZE; i += D_DIM)
{
if (i < finalPartSize)
WriteKey(DescendingIndex(g_d[ExtractDigit(g_d[i]) + PART_SIZE] + i), i);
}
}
else
{
ScatterKeysOnlyDevicePartialAscending(gtid, finalPartSize);
}
}
inline void ScatterKeysOnlyDevicePartial(uint gtid, uint partIndex)
{
const uint finalPartSize = e_numKeys - partIndex * PART_SIZE;
#if defined(SHOULD_ASCEND)
ScatterKeysOnlyDevicePartialAscending(gtid, finalPartSize);
#else
ScatterKeysOnlyDevicePartialDescending(gtid, finalPartSize);
#endif
}
//KEY VALUE PAIRS
inline void ScatterPairsKeyPhaseAscendingPartial(
uint gtid,
uint finalPartSize,
inout DigitStruct digits)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
{
if (t < finalPartSize)
{
digits.d[i] = ExtractDigit(g_d[t]);
WriteKey(g_d[digits.d[i] + PART_SIZE] + t, t);
}
}
}
inline void ScatterPairsKeyPhaseDescendingPartial(
uint gtid,
uint finalPartSize,
inout DigitStruct digits)
{
if (e_radixShift == 24)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
{
if (t < finalPartSize)
{
digits.d[i] = ExtractDigit(g_d[t]);
WriteKey(DescendingIndex(g_d[digits.d[i] + PART_SIZE] + t), t);
}
}
}
else
{
ScatterPairsKeyPhaseAscendingPartial(gtid, finalPartSize, digits);
}
}
inline void LoadPayloadsPartialWGE16(
uint gtid,
uint waveSize,
uint partIndex,
inout KeyStruct payloads)
{
[unroll]
for (uint i = 0, t = DeviceOffsetWGE16(gtid, waveSize, partIndex);
i < KEYS_PER_THREAD;
++i, t += waveSize)
{
if (t < e_numKeys)
LoadPayload(payloads.k[i], t);
}
}
inline void LoadPayloadsPartialWLT16(
uint gtid,
uint waveSize,
uint partIndex,
uint serialIterations,
inout KeyStruct payloads)
{
[unroll]
for (uint i = 0, t = DeviceOffsetWLT16(gtid, waveSize, partIndex, serialIterations);
i < KEYS_PER_THREAD;
++i, t += waveSize * serialIterations)
{
if (t < e_numKeys)
LoadPayload(payloads.k[i], t);
}
}
inline void ScatterPayloadsAscendingPartial(
uint gtid,
uint finalPartSize,
DigitStruct digits)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
{
if (t < finalPartSize)
WritePayload(g_d[digits.d[i] + PART_SIZE] + t, t);
}
}
inline void ScatterPayloadsDescendingPartial(
uint gtid,
uint finalPartSize,
DigitStruct digits)
{
if (e_radixShift == 24)
{
[unroll]
for (uint i = 0, t = gtid; i < KEYS_PER_THREAD; ++i, t += D_DIM)
{
if (t < finalPartSize)
WritePayload(DescendingIndex(g_d[digits.d[i] + PART_SIZE] + t), t);
}
}
else
{
ScatterPayloadsAscendingPartial(gtid, finalPartSize, digits);
}
}
inline void ScatterPairsDevicePartial(
uint gtid,
uint waveSize,
uint partIndex,
OffsetStruct offsets)
{
DigitStruct digits;
const uint finalPartSize = e_numKeys - partIndex * PART_SIZE;
#if defined(SHOULD_ASCEND)
ScatterPairsKeyPhaseAscendingPartial(gtid, finalPartSize, digits);
#else
ScatterPairsKeyPhaseDescendingPartial(gtid, finalPartSize, digits);
#endif
GroupMemoryBarrierWithGroupSync();
KeyStruct payloads;
if (waveSize >= 16)
LoadPayloadsPartialWGE16(gtid, waveSize, partIndex, payloads);
else
LoadPayloadsPartialWLT16(gtid, waveSize, partIndex, SerialIterations(waveSize), payloads);
ScatterPayloadsShared(offsets, payloads);
GroupMemoryBarrierWithGroupSync();
#if defined(SHOULD_ASCEND)
ScatterPayloadsAscendingPartial(gtid, finalPartSize, digits);
#else
ScatterPayloadsDescendingPartial(gtid, finalPartSize, digits);
#endif
}
inline void ScatterDevicePartial(
uint gtid,
uint waveSize,
uint partIndex,
OffsetStruct offsets)
{
#if defined(SORT_PAIRS)
ScatterPairsDevicePartial(
gtid,
waveSize,
partIndex,
offsets);
#else
ScatterKeysOnlyDevicePartial(gtid, partIndex);
#endif
}

2193
MVS/3DGS-D3D12/src/App.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,617 @@
#include "XC3DGSD3D12/GaussianPlyLoader.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstring>
#include <fstream>
#include <limits>
#include <sstream>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace XC3DGSD3D12 {
namespace {
constexpr float kSHC0 = 0.2820948f;
enum class PlyPropertyType {
None,
Float32,
Float64,
UInt8,
};
struct PlyProperty {
std::string name;
PlyPropertyType type = PlyPropertyType::None;
uint32_t offset = 0;
uint32_t size = 0;
};
struct PlyHeader {
uint32_t vertexCount = 0;
uint32_t vertexStride = 0;
std::vector<PlyProperty> properties;
};
struct Float4 {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
float w = 0.0f;
};
struct RawGaussianSplat {
Float3 position = {};
Float3 dc0 = {};
std::array<Float3, GaussianSplatRuntimeData::kShCoefficientCount> sh = {};
float opacity = 0.0f;
Float3 scale = {};
Float4 rotation = {};
};
struct GaussianPlyPropertyLayout {
const PlyProperty* position[3] = {};
const PlyProperty* dc0[3] = {};
const PlyProperty* opacity = nullptr;
const PlyProperty* scale[3] = {};
const PlyProperty* rotation[4] = {};
std::array<const PlyProperty*, GaussianSplatRuntimeData::kShCoefficientCount * 3> sh = {};
};
std::string TrimTrailingCarriageReturn(std::string line) {
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
return line;
}
uint32_t PropertyTypeSize(PlyPropertyType type) {
switch (type) {
case PlyPropertyType::Float32:
return 4;
case PlyPropertyType::Float64:
return 8;
case PlyPropertyType::UInt8:
return 1;
default:
return 0;
}
}
bool ParsePropertyType(const std::string& token, PlyPropertyType& outType) {
if (token == "float") {
outType = PlyPropertyType::Float32;
return true;
}
if (token == "double") {
outType = PlyPropertyType::Float64;
return true;
}
if (token == "uchar") {
outType = PlyPropertyType::UInt8;
return true;
}
outType = PlyPropertyType::None;
return false;
}
bool ParsePlyHeader(std::ifstream& input, PlyHeader& outHeader, std::string& outErrorMessage) {
std::string line;
if (!std::getline(input, line)) {
outErrorMessage = "Failed to read PLY magic line.";
return false;
}
if (TrimTrailingCarriageReturn(line) != "ply") {
outErrorMessage = "Input file is not a valid PLY file.";
return false;
}
bool sawFormat = false;
std::string currentElement;
while (std::getline(input, line)) {
line = TrimTrailingCarriageReturn(line);
if (line == "end_header") {
break;
}
if (line.empty()) {
continue;
}
std::istringstream stream(line);
std::string token;
stream >> token;
if (token == "comment") {
continue;
}
if (token == "format") {
std::string formatName;
std::string version;
stream >> formatName >> version;
if (formatName != "binary_little_endian") {
outErrorMessage = "Only binary_little_endian PLY files are supported.";
return false;
}
sawFormat = true;
continue;
}
if (token == "element") {
stream >> currentElement;
if (currentElement == "vertex") {
stream >> outHeader.vertexCount;
}
continue;
}
if (token == "property" && currentElement == "vertex") {
std::string typeToken;
std::string name;
stream >> typeToken >> name;
PlyPropertyType propertyType = PlyPropertyType::None;
if (!ParsePropertyType(typeToken, propertyType)) {
outErrorMessage = "Unsupported PLY vertex property type: " + typeToken;
return false;
}
PlyProperty property;
property.name = name;
property.type = propertyType;
property.offset = outHeader.vertexStride;
property.size = PropertyTypeSize(propertyType);
outHeader.vertexStride += property.size;
outHeader.properties.push_back(property);
}
}
if (!sawFormat) {
outErrorMessage = "PLY header is missing a valid format declaration.";
return false;
}
if (outHeader.vertexCount == 0) {
outErrorMessage = "PLY file does not contain any vertex data.";
return false;
}
if (outHeader.vertexStride == 0 || outHeader.properties.empty()) {
outErrorMessage = "PLY vertex layout is empty.";
return false;
}
return true;
}
bool ReadPropertyAsFloat(
const std::byte* vertexBytes,
const PlyProperty& property,
float& outValue) {
const std::byte* propertyPtr = vertexBytes + property.offset;
switch (property.type) {
case PlyPropertyType::Float32: {
std::memcpy(&outValue, propertyPtr, sizeof(float));
return true;
}
case PlyPropertyType::Float64: {
double value = 0.0;
std::memcpy(&value, propertyPtr, sizeof(double));
outValue = static_cast<float>(value);
return true;
}
case PlyPropertyType::UInt8: {
uint8_t value = 0;
std::memcpy(&value, propertyPtr, sizeof(uint8_t));
outValue = static_cast<float>(value);
return true;
}
default:
return false;
}
}
bool BuildPropertyMap(
const PlyHeader& header,
std::unordered_map<std::string_view, const PlyProperty*>& outMap,
std::string& outErrorMessage) {
outMap.clear();
outMap.reserve(header.properties.size());
for (const PlyProperty& property : header.properties) {
const auto [it, inserted] = outMap.emplace(property.name, &property);
if (!inserted) {
outErrorMessage = "Duplicate PLY vertex property found: " + property.name;
return false;
}
}
return true;
}
bool RequireProperty(
const std::unordered_map<std::string_view, const PlyProperty*>& propertyMap,
std::string_view name,
const PlyProperty*& outProperty,
std::string& outErrorMessage) {
const auto iterator = propertyMap.find(name);
if (iterator == propertyMap.end()) {
outErrorMessage = "Missing required PLY property: " + std::string(name);
return false;
}
outProperty = iterator->second;
return true;
}
bool BuildGaussianPlyPropertyLayout(
const std::unordered_map<std::string_view, const PlyProperty*>& propertyMap,
GaussianPlyPropertyLayout& outLayout,
std::string& outErrorMessage) {
outLayout = {};
if (!RequireProperty(propertyMap, "x", outLayout.position[0], outErrorMessage) ||
!RequireProperty(propertyMap, "y", outLayout.position[1], outErrorMessage) ||
!RequireProperty(propertyMap, "z", outLayout.position[2], outErrorMessage) ||
!RequireProperty(propertyMap, "f_dc_0", outLayout.dc0[0], outErrorMessage) ||
!RequireProperty(propertyMap, "f_dc_1", outLayout.dc0[1], outErrorMessage) ||
!RequireProperty(propertyMap, "f_dc_2", outLayout.dc0[2], outErrorMessage) ||
!RequireProperty(propertyMap, "opacity", outLayout.opacity, outErrorMessage) ||
!RequireProperty(propertyMap, "scale_0", outLayout.scale[0], outErrorMessage) ||
!RequireProperty(propertyMap, "scale_1", outLayout.scale[1], outErrorMessage) ||
!RequireProperty(propertyMap, "scale_2", outLayout.scale[2], outErrorMessage) ||
!RequireProperty(propertyMap, "rot_0", outLayout.rotation[0], outErrorMessage) ||
!RequireProperty(propertyMap, "rot_1", outLayout.rotation[1], outErrorMessage) ||
!RequireProperty(propertyMap, "rot_2", outLayout.rotation[2], outErrorMessage) ||
!RequireProperty(propertyMap, "rot_3", outLayout.rotation[3], outErrorMessage)) {
return false;
}
for (uint32_t index = 0; index < outLayout.sh.size(); ++index) {
const std::string propertyName = "f_rest_" + std::to_string(index);
if (!RequireProperty(propertyMap, propertyName, outLayout.sh[index], outErrorMessage)) {
return false;
}
}
return true;
}
Float3 Min(const Float3& a, const Float3& b) {
return {
std::min(a.x, b.x),
std::min(a.y, b.y),
std::min(a.z, b.z),
};
}
Float3 Max(const Float3& a, const Float3& b) {
return {
std::max(a.x, b.x),
std::max(a.y, b.y),
std::max(a.z, b.z),
};
}
float Dot(const Float4& a, const Float4& b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
Float4 NormalizeSwizzleRotation(const Float4& wxyz) {
const float lengthSquared = Dot(wxyz, wxyz);
if (lengthSquared <= std::numeric_limits<float>::epsilon()) {
return { 0.0f, 0.0f, 0.0f, 1.0f };
}
const float inverseLength = 1.0f / std::sqrt(lengthSquared);
return {
wxyz.y * inverseLength,
wxyz.z * inverseLength,
wxyz.w * inverseLength,
wxyz.x * inverseLength,
};
}
Float4 PackSmallest3Rotation(Float4 rotation) {
const Float4 absoluteRotation = {
std::fabs(rotation.x),
std::fabs(rotation.y),
std::fabs(rotation.z),
std::fabs(rotation.w),
};
int largestIndex = 0;
float largestValue = absoluteRotation.x;
if (absoluteRotation.y > largestValue) {
largestIndex = 1;
largestValue = absoluteRotation.y;
}
if (absoluteRotation.z > largestValue) {
largestIndex = 2;
largestValue = absoluteRotation.z;
}
if (absoluteRotation.w > largestValue) {
largestIndex = 3;
largestValue = absoluteRotation.w;
}
if (largestIndex == 0) {
rotation = { rotation.y, rotation.z, rotation.w, rotation.x };
} else if (largestIndex == 1) {
rotation = { rotation.x, rotation.z, rotation.w, rotation.y };
} else if (largestIndex == 2) {
rotation = { rotation.x, rotation.y, rotation.w, rotation.z };
}
const float sign = rotation.w >= 0.0f ? 1.0f : -1.0f;
const float invSqrt2 = std::sqrt(2.0f) * 0.5f;
const Float3 encoded = {
(rotation.x * sign * std::sqrt(2.0f)) * 0.5f + 0.5f,
(rotation.y * sign * std::sqrt(2.0f)) * 0.5f + 0.5f,
(rotation.z * sign * std::sqrt(2.0f)) * 0.5f + 0.5f,
};
(void)invSqrt2;
return { encoded.x, encoded.y, encoded.z, static_cast<float>(largestIndex) / 3.0f };
}
uint32_t EncodeQuatToNorm10(const Float4& packedRotation) {
const auto saturate = [](float value) {
return std::clamp(value, 0.0f, 1.0f);
};
const uint32_t x = static_cast<uint32_t>(saturate(packedRotation.x) * 1023.5f);
const uint32_t y = static_cast<uint32_t>(saturate(packedRotation.y) * 1023.5f);
const uint32_t z = static_cast<uint32_t>(saturate(packedRotation.z) * 1023.5f);
const uint32_t w = static_cast<uint32_t>(saturate(packedRotation.w) * 3.5f);
return x | (y << 10) | (z << 20) | (w << 30);
}
Float3 LinearScale(const Float3& logarithmicScale) {
return {
std::fabs(std::exp(logarithmicScale.x)),
std::fabs(std::exp(logarithmicScale.y)),
std::fabs(std::exp(logarithmicScale.z)),
};
}
Float3 SH0ToColor(const Float3& dc0) {
return {
dc0.x * kSHC0 + 0.5f,
dc0.y * kSHC0 + 0.5f,
dc0.z * kSHC0 + 0.5f,
};
}
float Sigmoid(float value) {
return 1.0f / (1.0f + std::exp(-value));
}
std::array<uint32_t, 2> DecodeMorton2D16x16(uint32_t value) {
value = (value & 0xFFu) | ((value & 0xFEu) << 7u);
value &= 0x5555u;
value = (value ^ (value >> 1u)) & 0x3333u;
value = (value ^ (value >> 2u)) & 0x0F0Fu;
return { value & 0xFu, value >> 8u };
}
uint32_t SplatIndexToTextureIndex(uint32_t index) {
const std::array<uint32_t, 2> morton = DecodeMorton2D16x16(index);
const uint32_t widthInBlocks = GaussianSplatRuntimeData::kColorTextureWidth / 16u;
index >>= 8u;
const uint32_t x = (index % widthInBlocks) * 16u + morton[0];
const uint32_t y = (index / widthInBlocks) * 16u + morton[1];
return y * GaussianSplatRuntimeData::kColorTextureWidth + x;
}
template <typename T>
void WriteValue(std::vector<std::byte>& bytes, size_t offset, const T& value) {
std::memcpy(bytes.data() + offset, &value, sizeof(T));
}
void WriteFloat3(std::vector<std::byte>& bytes, size_t offset, const Float3& value) {
WriteValue(bytes, offset + 0, value.x);
WriteValue(bytes, offset + 4, value.y);
WriteValue(bytes, offset + 8, value.z);
}
void WriteFloat4(std::vector<std::byte>& bytes, size_t offset, float x, float y, float z, float w) {
WriteValue(bytes, offset + 0, x);
WriteValue(bytes, offset + 4, y);
WriteValue(bytes, offset + 8, z);
WriteValue(bytes, offset + 12, w);
}
bool ReadGaussianSplat(
const std::byte* vertexBytes,
const GaussianPlyPropertyLayout& propertyLayout,
RawGaussianSplat& outSplat,
std::string& outErrorMessage) {
auto readFloat = [&](const PlyProperty* property, float& outValue) -> bool {
if (property == nullptr) {
outErrorMessage = "Gaussian PLY property layout is incomplete.";
return false;
}
return ReadPropertyAsFloat(vertexBytes, *property, outValue);
};
if (!readFloat(propertyLayout.position[0], outSplat.position.x) ||
!readFloat(propertyLayout.position[1], outSplat.position.y) ||
!readFloat(propertyLayout.position[2], outSplat.position.z) ||
!readFloat(propertyLayout.dc0[0], outSplat.dc0.x) ||
!readFloat(propertyLayout.dc0[1], outSplat.dc0.y) ||
!readFloat(propertyLayout.dc0[2], outSplat.dc0.z) ||
!readFloat(propertyLayout.opacity, outSplat.opacity) ||
!readFloat(propertyLayout.scale[0], outSplat.scale.x) ||
!readFloat(propertyLayout.scale[1], outSplat.scale.y) ||
!readFloat(propertyLayout.scale[2], outSplat.scale.z) ||
!readFloat(propertyLayout.rotation[0], outSplat.rotation.x) ||
!readFloat(propertyLayout.rotation[1], outSplat.rotation.y) ||
!readFloat(propertyLayout.rotation[2], outSplat.rotation.z) ||
!readFloat(propertyLayout.rotation[3], outSplat.rotation.w)) {
if (outErrorMessage.empty()) {
outErrorMessage = "Failed to read required Gaussian splat PLY properties.";
}
return false;
}
std::array<float, GaussianSplatRuntimeData::kShCoefficientCount * 3> shRaw = {};
for (uint32_t index = 0; index < shRaw.size(); ++index) {
if (!readFloat(propertyLayout.sh[index], shRaw[index])) {
if (outErrorMessage.empty()) {
outErrorMessage = "Failed to read SH rest coefficients from PLY.";
}
return false;
}
}
for (uint32_t coefficientIndex = 0; coefficientIndex < GaussianSplatRuntimeData::kShCoefficientCount; ++coefficientIndex) {
outSplat.sh[coefficientIndex] = {
shRaw[coefficientIndex + 0],
shRaw[coefficientIndex + GaussianSplatRuntimeData::kShCoefficientCount],
shRaw[coefficientIndex + GaussianSplatRuntimeData::kShCoefficientCount * 2],
};
}
return true;
}
void LinearizeGaussianSplat(RawGaussianSplat& splat) {
const Float4 normalizedQuaternion = NormalizeSwizzleRotation(splat.rotation);
const Float4 packedQuaternion = PackSmallest3Rotation(normalizedQuaternion);
splat.rotation = packedQuaternion;
splat.scale = LinearScale(splat.scale);
splat.dc0 = SH0ToColor(splat.dc0);
splat.opacity = Sigmoid(splat.opacity);
}
} // namespace
bool LoadGaussianSceneFromPly(
const std::filesystem::path& filePath,
GaussianSplatRuntimeData& outData,
std::string& outErrorMessage) {
outData = {};
outErrorMessage.clear();
std::ifstream input(filePath, std::ios::binary);
if (!input.is_open()) {
outErrorMessage = "Failed to open PLY file: " + filePath.string();
return false;
}
PlyHeader header;
if (!ParsePlyHeader(input, header, outErrorMessage)) {
return false;
}
std::unordered_map<std::string_view, const PlyProperty*> propertyMap;
if (!BuildPropertyMap(header, propertyMap, outErrorMessage)) {
return false;
}
GaussianPlyPropertyLayout propertyLayout;
if (!BuildGaussianPlyPropertyLayout(propertyMap, propertyLayout, outErrorMessage)) {
return false;
}
outData.splatCount = header.vertexCount;
outData.colorTextureWidth = GaussianSplatRuntimeData::kColorTextureWidth;
outData.colorTextureHeight =
std::max<uint32_t>(1u, (header.vertexCount + outData.colorTextureWidth - 1u) / outData.colorTextureWidth);
outData.colorTextureHeight = (outData.colorTextureHeight + 15u) / 16u * 16u;
outData.positionData.resize(static_cast<size_t>(header.vertexCount) * GaussianSplatRuntimeData::kPositionStride);
outData.otherData.resize(static_cast<size_t>(header.vertexCount) * GaussianSplatRuntimeData::kOtherStride);
outData.colorData.resize(
static_cast<size_t>(outData.colorTextureWidth) *
static_cast<size_t>(outData.colorTextureHeight) *
GaussianSplatRuntimeData::kColorStride);
outData.shData.resize(static_cast<size_t>(header.vertexCount) * GaussianSplatRuntimeData::kShStride);
outData.boundsMin = {
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity(),
};
outData.boundsMax = {
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
};
std::vector<std::byte> vertexBytes(header.vertexStride);
for (uint32_t splatIndex = 0; splatIndex < header.vertexCount; ++splatIndex) {
input.read(reinterpret_cast<char*>(vertexBytes.data()), static_cast<std::streamsize>(vertexBytes.size()));
if (input.gcount() != static_cast<std::streamsize>(vertexBytes.size())) {
outErrorMessage =
"Unexpected end of file while reading Gaussian splat vertex " + std::to_string(splatIndex) + ".";
return false;
}
RawGaussianSplat splat;
if (!ReadGaussianSplat(vertexBytes.data(), propertyLayout, splat, outErrorMessage)) {
return false;
}
LinearizeGaussianSplat(splat);
outData.boundsMin = Min(outData.boundsMin, splat.position);
outData.boundsMax = Max(outData.boundsMax, splat.position);
const size_t positionOffset = static_cast<size_t>(splatIndex) * GaussianSplatRuntimeData::kPositionStride;
WriteFloat3(outData.positionData, positionOffset, splat.position);
const size_t otherOffset = static_cast<size_t>(splatIndex) * GaussianSplatRuntimeData::kOtherStride;
const uint32_t packedRotation = EncodeQuatToNorm10(splat.rotation);
WriteValue(outData.otherData, otherOffset, packedRotation);
WriteFloat3(outData.otherData, otherOffset + sizeof(uint32_t), splat.scale);
const size_t shOffset = static_cast<size_t>(splatIndex) * GaussianSplatRuntimeData::kShStride;
for (uint32_t coefficientIndex = 0; coefficientIndex < GaussianSplatRuntimeData::kShCoefficientCount; ++coefficientIndex) {
const size_t coefficientOffset = shOffset + static_cast<size_t>(coefficientIndex) * sizeof(float) * 3u;
WriteFloat3(outData.shData, coefficientOffset, splat.sh[coefficientIndex]);
}
const uint32_t textureIndex = SplatIndexToTextureIndex(splatIndex);
const size_t colorOffset = static_cast<size_t>(textureIndex) * GaussianSplatRuntimeData::kColorStride;
WriteFloat4(outData.colorData, colorOffset, splat.dc0.x, splat.dc0.y, splat.dc0.z, splat.opacity);
}
return true;
}
bool WriteGaussianSceneSummary(
const std::filesystem::path& filePath,
const GaussianSplatRuntimeData& data,
std::string& outErrorMessage) {
outErrorMessage.clear();
std::ofstream output(filePath, std::ios::binary | std::ios::trunc);
if (!output.is_open()) {
outErrorMessage = "Failed to open summary output file: " + filePath.string();
return false;
}
output << "splat_count=" << data.splatCount << '\n';
output << "color_texture_width=" << data.colorTextureWidth << '\n';
output << "color_texture_height=" << data.colorTextureHeight << '\n';
output << "bounds_min=" << data.boundsMin.x << "," << data.boundsMin.y << "," << data.boundsMin.z << '\n';
output << "bounds_max=" << data.boundsMax.x << "," << data.boundsMax.y << "," << data.boundsMax.z << '\n';
output << "position_bytes=" << data.positionData.size() << '\n';
output << "other_bytes=" << data.otherData.size() << '\n';
output << "color_bytes=" << data.colorData.size() << '\n';
output << "sh_bytes=" << data.shData.size() << '\n';
return output.good();
}
} // namespace XC3DGSD3D12

View File

@@ -0,0 +1,42 @@
#include <windows.h>
#include <shellapi.h>
#include <string>
#include "XC3DGSD3D12/App.h"
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int showCommand) {
XC3DGSD3D12::App app;
int argumentCount = 0;
LPWSTR* arguments = CommandLineToArgvW(GetCommandLineW(), &argumentCount);
for (int index = 1; index + 1 < argumentCount; ++index) {
if (std::wstring(arguments[index]) == L"--frame-limit") {
app.SetFrameLimit(static_cast<unsigned int>(_wtoi(arguments[index + 1])));
++index;
} else if (std::wstring(arguments[index]) == L"--scene") {
app.SetGaussianScenePath(arguments[index + 1]);
++index;
} else if (std::wstring(arguments[index]) == L"--summary-file") {
app.SetSummaryPath(arguments[index + 1]);
++index;
} else if (std::wstring(arguments[index]) == L"--screenshot-file") {
app.SetScreenshotPath(arguments[index + 1]);
++index;
}
}
if (arguments != nullptr) {
LocalFree(arguments);
}
if (!app.Initialize(instance, showCommand)) {
const std::wstring message =
app.GetLastErrorMessage().empty()
? L"Failed to initialize XC 3DGS D3D12 MVS."
: app.GetLastErrorMessage();
MessageBoxW(nullptr, message.c_str(), L"Initialization Error", MB_OK | MB_ICONERROR);
return -1;
}
return app.Run();
}

View File

@@ -670,4 +670,4 @@ ID3D12Resource* CreateTexture2D(ID3D12GraphicsCommandList* inCommandList,
}
ID3D12Device* GetD3DDevice() {
return gD3D12Device;
}
}

View File

@@ -305,4 +305,4 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
}
}
return 0;
}
}

460
README.md
View File

@@ -1,123 +1,186 @@
# XCEngine
`XCEngine` 是一个 Windows-first、editor-first 的 C++20 游戏引擎工作区。当前主线围绕 `RHI -> Rendering -> Editor -> Asset Pipeline -> Mono Scripting` 演进,目标不是堆 sample而是把可运行的引擎与编辑器主链持续收口成型
`XCEngine` 是一个 Windows-first、editor-first 的 `C++20` 游戏引擎工作区。当前代码中已经形成 `RHI``Rendering``Scene``Resources``Editor``Mono C# Scripting` `XCUI` 相关主线;本 README 只描述当前已经实现、已经接入或已经成为正式工作流一部分的能力
## 项目定位
## 核心特性
- `engine/` 提供核心静态库 `XCEngine`,包含 `RHI``Rendering``Resources``Scene``Input``Audio``Scripting` 等模块。
- `editor/` 是当前正式桌面编辑器,宿主基于 Win32 + D3D12编辑器 target 名为 `XCEditor`,输出文件名为 `XCEngine.exe`
- `new_editor/` 是基于 `XCUI` 的新编辑器主线,当前仍在并行演进。
- `project/` 是随仓库维护的示例工程,已经采用 `Assets + .meta + Library` 布局。
- `tests/` 覆盖 Engine、Rendering、RHI、Editor、Scripting、UI 等主线模块。
### 渲染
## 当前能力
- 内置跨后端 `RHI` 抽象层,当前支持 `D3D12``OpenGL``Vulkan`
- 当前主渲染链为 `SceneRenderer -> CameraRenderer -> BuiltinForwardPipeline`
- 已接入前向渲染主路径、透明路径和 skybox 路径
- 已具备方向光阴影通路
- 已具备 `object-id` pass可用于编辑器拾取
- 已具备选中描边、最终颜色合成和颜色缩放后处理 pass
- 已具备无限网格 pass可用于 Scene View
- 已接入 `NanoVDB` 体积渲染 pass
- `RenderSurface` 允许同一条渲染链服务于窗口输出、编辑器视口和离屏目标
- `RHI` 当前维护 `D3D12 / OpenGL / Vulkan` 三个后端。
- `Rendering` 已形成 `SceneRenderer -> CameraRenderer -> RenderPipeline` 主链。
- Scene View 已接通 object-id picking、selection outline、grid、overlay 与 gizmo 渲染。
- 资源系统已采用 `AssetDatabase + Artifact + Library` 工作流,而不是简单文件直读。
- `Material / Shader / Texture / Mesh` 已接入正式资源导入与运行时加载链路。
- 编辑器已支持项目加载、Scene/Game viewport、Inspector、Hierarchy、Project 面板等基础闭环。
- Mono C# 脚本运行时与项目脚本程序集构建链路已接入当前工作区。
- `new_editor/` 正在推进 `XCUI` 宿主、控件与 shell 体系。
### 场景与运行时
## 仓库结构
- 采用 `Scene / GameObject / Component` 结构
- 已具备场景更新、运行时驱动和场景序列化能力
- 内置常用组件,包括:
- `TransformComponent`
- `CameraComponent`
- `LightComponent`
- `MeshFilterComponent`
- `MeshRendererComponent`
- `VolumeRendererComponent`
- `AudioSourceComponent`
- `AudioListenerComponent`
- `ScriptComponent`
- `engine/`:引擎核心实现与公共头文件。
- `editor/`:当前正式编辑器与 viewport 接线。
- `new_editor/`XCUI 新编辑器主线。
- `managed/``XCEngine.ScriptCore` 与示例托管程序集。
- `project/`:示例工程与随仓库维护的资产。
- `tests/`:单元测试、集成测试与阶段性回归入口。
- `docs/`架构说明、API 文档、计划与历史归档。
- `mvs/`:原型、实验工程与外部参考材料。
### 资源系统
## 环境要求
- 资源主线不是简单文件直读,而是 `AssetDatabase + Artifact + Library` 工作流
- 已具备项目资产索引、导入、重导入和缓存维护链路
- 已接入的资源类型包括:
- `Mesh`
- `Texture`
- `Shader`
- `Material`
- `AudioClip`
- `VolumeField`
- `UI Document`
- 内置 `builtin://` 资源入口,可直接使用基础 mesh、材质等内置资源
当前推荐在 Windows 上构建和运行。
### 脚本系统
- 可选启用基于 `Mono``C#` 脚本运行时
- 托管程序集分为:
- `XCEngine.ScriptCore`
- `GameScripts`
- 脚本组件由 `ScriptComponent` 承载
- 引擎当前支持脚本类发现、字段元数据读取、默认值读取和字段存储
- 支持脚本字段 override 持久化与运行时同步
- 编辑器已接入项目脚本程序集重建与脚本运行时重载
### 编辑器
- 当前正式编辑器是基于 `Win32 + D3D12 + ImGui` 的桌面编辑器
- 当前已具备以下基础工作流:
- `Hierarchy`
- `Inspector`
- `Project`
- `Console`
- `Scene View`
- `Game View`
- `Scene View` 已接入:
- object-id picking
- selection outline
- overlay
- transform gizmo
- infinite grid
- `Inspector` 已能处理常规组件检查,也已接入 `ScriptComponent` 与材质资源检查路径
- 编辑器能够识别项目目录、加载项目资源、接通 `Library/ScriptAssemblies` 中的脚本程序集
### UI 与 XCUI
- 引擎内部包含 retained-mode UI 基础设施
- 已具备:
- 布局系统
- 样式系统
- 焦点控制
- 输入分发
- 快捷键分发
- 文本输入编辑
- 选择模型
- 拖拽交互模型
- 运行时 UI 主链包括:
- `UIScreenDocumentHost`
- `UIScreenPlayer`
- `UISystem`
- `tests/UI/` 是当前 XCUI `Core / Editor / Runtime` 三层的正式基础层验证入口
- `new_editor/` 是未来正式编辑器主线不再只是临时沙盒当前已经包含树视图、列表视图、菜单、标签条、属性网格、字段控件、workspace / dock / viewport shell 等基础组件
### 音频
- 已具备 `AudioSystem`
- 已接入 `AudioSourceComponent``AudioListenerComponent`
- 当前代码中已包含 `AudioMixer` 和多种效果器/分析器实现入口:
- `Equalizer`
- `FFTFilter`
- `Reverbation`
- `HRTF`
### 测试
- 引擎不是“只靠手工点点看”的状态,当前已具备大规模测试树
- 覆盖范围包括:
- Engine 基础模块
- Rendering
- RHI
- Editor
- Scripting
- UI
- `RHI` 集成测试使用统一基准图做 golden-image 对比
- `XCUI` 当前也有独立的 unit / integration 验证链路
## 当前实现范围
- 当前正式编辑器为基于 `Win32 + D3D12 + ImGui` 的桌面编辑器
- 当前 `RHI` 后端为 `D3D12``OpenGL``Vulkan`
- 当前项目资产工作流已经接入 `AssetDatabase + Artifact + Library`
- 当前 `Mono C#` 脚本程序集与运行时链路已经接入
- 当前 `XCUI` 新编辑器路线以 `new_editor/` 为正式主线继续推进
## 快速开始
推荐环境:
- Windows 10/11
- Visual Studio 2022 / MSVC v143
- CMake 3.15+
- Vulkan SDK
- .NET SDK
- Git LFS
脚本运行时启用时,还需要
- 可用的 Mono 依赖,默认路径来自 `参考/Fermion/Fermion/external/mono`
补充说明:
- 当前根 CMake 配置里,`Vulkan SDK` 仍是硬依赖。
- NanoVDB 头文件是可选能力,仅影响 `.nvdb` 体积资源支持。
- 如果仓库里的大资源依赖 Git LFS请先执行 `git lfs pull`
## 快速开始
### 1. 配置
配置工程
```powershell
cmake -S . -B build -A x64
```
如果本地暂时没有 Mono 依赖,可以先关闭脚本运行时:
如果当前不需要 Mono 脚本运行时:
```powershell
cmake -S . -B build -A x64 -DXCENGINE_ENABLE_MONO_SCRIPTING=OFF
```
### 2. 构建当前编辑器
构建当前正式编辑器
```powershell
cmake --build build --config Debug --target XCEditor
```
编辑器产物路径
- `editor/bin/Debug/XCEngine.exe`
### 3. 运行编辑器
运行
```powershell
.\editor\bin\Debug\XCEngine.exe
```
显式指定工程目录
```powershell
.\editor\bin\Debug\XCEngine.exe --project D:\Path\To\Project
```
### 4. 构建项目脚本程序集
如果你要验证 `ScriptComponent`、脚本类发现或 Inspector 字段编辑,先构建:
如需构建项目脚本程序集
```powershell
cmake --build build --config Debug --target xcengine_project_managed_assemblies
```
### 5. 可选构建 XCUI 新编辑器
如需构建 XCUI 新编辑器宿主:
```powershell
cmake --build build --config Debug --target XCUIEditorApp
```
产物路径通常为
运行 XCUI 新编辑器宿主
- `new_editor/bin/Debug/XCUIEditor.exe`
```powershell
.\new_editor\bin\Debug\XCUIEditor.exe
```
## 测试
列出测试:
## 测试入口
```powershell
ctest --test-dir build -N -C Debug
```
运行测试:
```powershell
ctest --test-dir build -C Debug --output-on-failure
```
@@ -128,24 +191,253 @@ cmake --build build --config Debug --target editor_tests
cmake --build build --config Debug --target rendering_all_tests
cmake --build build --config Debug --target rhi_all_tests
cmake --build build --config Debug --target scripting_tests
cmake --build build --config Debug --target core_ui_all_tests
cmake --build build --config Debug --target editor_ui_all_tests
cmake --build build --config Debug --target runtime_ui_all_tests
```
更细的测试组织与约定见 [tests/TEST_SPEC.md](tests/TEST_SPEC.md)。
## 完整目录结构
以下目录树按当前工作树整理,保留了真实使用的生成目录与关键子树;省略了 `.git/``build/_deps/`、部分重复资源文件,以及 `docs/used/` 中大量历史归档的长尾条目。
```text
XCEngine/
|- .gitattributes
|- .gitignore
|- AGENT.md
|- CMakeLists.txt
|- README.md
|- build/ # 本地 CMake 构建输出
|- docs/
| |- api/
| | |- XCEngine/
| | |- _guides/
| | |- _meta/
| | |- _tools/
| | `- main.md
| |- issues/
| | `- Editor模块_Console面板错误绑定fallback sink导致运行时日志不显示4.3.md
| |- plan/
| | |- end/
| | | |- RHI模块设计与实现/
| | | | |- RHIFence.md
| | | | `- RHI模块总览.md
| | | `- 编辑器与运行时分层架构设计.md
| | |- 开题报告和任务书/
| | |- 旧版题目/
| | |- 3DGS专用PLY导入器与GaussianSplat资源缓存正式化计划_2026-04-10.md
| | |- API文档目录结构第二轮并行任务板_2026-04-09.md
| | |- API文档目录结构第二轮重构计划_2026-04-09.md
| | |- API文档目录结构重大重构并行任务板_2026-04-09.md
| | |- API文档目录结构重构并行任务板_2026-04-09_第二轮.md
| | |- API文档目录重构计划_2026-04-09.md
| | |- C#脚本模块下一阶段计划.md
| | |- Editor架构说明.md
| | |- Library启动预热与运行时异步加载混合重构计划_2026-04-04.md
| | |- Library启动预热与运行时异步加载混合重构计划_进度更新_2026-04-04.md
| | |- NanoVDB体积云加载阻塞与Runtime上传修复计划_2026-04-10.md
| | |- Unity SRP API参考文档.md
| | |- Unity绝区零开发文档还原版.md
| | |- Unity风格模型导入与Model资产架构重构计划_2026-04-10.md
| | |- XCUI_NewEditor主线重建计划_2026-04-07.md
| | `- XCUI完整架构设计与执行计划.md
| |- used/ # 历史材料、阶段归档和旧计划背景
| | |- API文档实时同步任务池_2026-04-03.md
| | |- Library资产导入与缓存系统收口计划_完成归档_2026-04-03.md
| | |- NanoVDB稀疏体积渲染后续正式化计划_阶段归档_2026-04-10.md
| | |- NanoVDB稀疏体积渲染正式集成计划_第一阶段完成归档_2026-04-09.md
| | |- Renderer当前阶段正式收口计划_阶段归档_2026-04-10.md
| | |- Renderer剩余收口与体积渲染多后端正式化计划_完成归档_2026-04-10.md
| | |- Renderer下一阶段_Unity风格Shader体系正式化计划_完成归档_2026-04-07.md
| | |- SceneViewport_Overlay_Gizmo_Rework_Plan_完成归档_2026-04-04.md
| | |- Unity式SceneView_Gizmo系统完整审查与正式化重构方案_完成归档_2026-04-06.md
| | `- XCUI_Phase_Status_2026-04-05.md
| |- api-skill.md
| |- blueprint-skill.md
| `- blueprint.md
|- editor/
| |- CMakeLists.txt
| |- README.md
| |- bin/
| |- resources/
| | `- Icons/
| `- src/
| |- Actions/
| |- Commands/
| |- ComponentEditors/
| |- Core/
| |- Layers/
| |- Layout/
| |- Managers/
| |- panels/
| |- Platform/
| |- Scripting/
| |- UI/
| |- Utils/
| |- Viewport/
| | |- Passes/
| | |- SceneViewportChrome.*
| | |- SceneViewportInteractionFrame.h
| | |- SceneViewportNavigation.h
| | |- SceneViewportOverlayBuilder.*
| | |- SceneViewportOverlayFrameCache.*
| | |- SceneViewportOverlaySpriteResources.*
| | |- SceneViewportPassSpecs.h
| | |- SceneViewportPicker.*
| | |- SceneViewportResourcePaths.h
| | |- SceneViewportTransformGizmoCoordinator.*
| | `- ViewportHostService.h
| |- Application.cpp
| |- Application.h
| |- Theme.cpp
| `- main.cpp
|- engine/
| |- CMakeLists.txt
| |- include/
| | `- XCEngine/
| | |- Audio/
| | |- Components/
| | |- Core/
| | |- Debug/
| | |- Input/
| | |- Memory/
| | |- Platform/
| | |- Rendering/
| | | |- Caches/
| | | |- Execution/
| | | |- Extraction/
| | | |- FrameData/
| | | |- Materials/
| | | |- Passes/
| | | |- Picking/
| | | |- Pipelines/
| | | `- Planning/
| | |- Resources/
| | | |- AudioClip/
| | | |- Material/
| | | |- Mesh/
| | | |- Shader/
| | | |- Texture/
| | | `- Volume/
| | |- RHI/
| | | |- D3D12/
| | | |- OpenGL/
| | | `- Vulkan/
| | |- Scene/
| | |- Scripting/
| | |- Threading/
| | `- UI/
| |- src/
| |- third_party/
| `- tools/
|- managed/
| |- CMakeLists.txt
| |- GameScripts/
| `- XCEngine.ScriptCore/
|- mvs/
| |- 3DGS-Unity/
| |- D3D12/
| |- OpenGL/
| |- RenderDoc/
| |- ui/
| `- VolumeRenderer/
|- new_editor/
| |- app/
| | |- Host/
| | |- Application.cpp
| | |- Application.h
| | `- main.cpp
| |- bin/
| |- include/
| | `- XCEditor/
| | |- Collections/
| | |- Fields/
| | |- Foundation/
| | |- Shell/
| | `- Widgets/
| |- src/
| | |- Collections/
| | |- Fields/
| | |- Foundation/
| | |- Shell/
| | `- Widgets/
| |- ui/
| | |- themes/
| | `- views/
| `- CMakeLists.txt
|- project/
| |- .xceditor/
| | |- imgui_layout.ini
| | `- thumbs/
| |- Assets/
| | |- Materials/
| | |- Models/
| | |- Scenes/
| | `- Scripts/
| |- Library/
| | |- ArtifactDB/
| | |- Artifacts/
| | |- ScriptAssemblies/
| | `- SourceAssetDB/
| |- Assets.meta
| `- Project.xcproject
|- scripts/
| `- Run-RendererPhaseRegression.ps1
|- tests/
| |- CMakeLists.txt
| |- TEST_SPEC.md
| |- Components/
| |- Core/
| |- Debug/
| |- Editor/
| |- Fixtures/
| |- Input/
| |- Memory/
| |- NewEditor/ # 当前为空的预留测试根目录
| |- Rendering/
| | |- integration/
| | | |- alpha_cutout_scene/
| | | |- camera_post_process_scene/
| | | |- directional_shadow_scene/
| | | |- final_color_scene/
| | | |- multi_light_scene/
| | | |- skybox_scene/
| | | |- volume_occlusion_scene/
| | | |- volume_scene/
| | | `- volume_transform_scene/
| | `- unit/
| |- Resources/
| |- RHI/
| |- Scene/
| |- Scripting/
| |- Threading/
| `- UI/
| |- Core/
| |- Editor/
| |- Runtime/
| `- TEST_SPEC.md
|- 参考/
| |- Fermion/
| |- TransformGizmo/
| |- unity editor/
| |- unity-editor-icons/
| |- unity-icons/
| `- UnityRuntimeSceneGizmo-master/
`- .vscode/
```
## 文档入口
- 编辑器说明:[editor/README.md](editor/README.md)
- API 文档入口:[docs/api/main.md](docs/api/main.md)
- 架构蓝图:[docs/blueprint.md](docs/blueprint.md)
- Editor 架构说明:[docs/plan/Editor架构说明.md](docs/plan/Editor架构说明.md)
- 测试规范:[tests/TEST_SPEC.md](tests/TEST_SPEC.md)
- 协作约定:[AGENT.md](AGENT.md)
## 当前状态
`XCEngine` 仍处于高频迭代阶段,但当前仓库已经不是“零散原型集合”,而是一个以编辑器工作流为中心持续收口的引擎工作区。接口、目录和构建细节仍可能调整,但主线方向已经比较明确:
- 稳定 `RHI / Rendering / Asset Pipeline / Editor` 主链。
- 继续推进 `Mono Scripting` 与项目脚本工作流。
- 推进 `XCUI` 新编辑器主线从组件库走向完整宿主。
- `docs/api/main.md`
- `editor/README.md`
- `AGENT.md`
- `docs/blueprint.md`
- `tests/TEST_SPEC.md`
- `tests/UI/TEST_SPEC.md`
- `docs/plan/Editor架构说明.md`
- `docs/plan/Library启动预热与运行时异步加载混合重构计划_2026-04-04.md`
- `docs/plan/XCUI_NewEditor主线重建计划_2026-04-07.md`
- `docs/plan/XCUI完整架构设计与执行计划.md`
- `docs/plan/NanoVDB体积云加载阻塞与Runtime上传修复计划_2026-04-10.md`
- `docs/plan/Unity风格模型导入与Model资产架构重构计划_2026-04-10.md`
- `docs/plan/3DGS专用PLY导入器与GaussianSplat资源缓存正式化计划_2026-04-10.md`

View File

@@ -1,8 +1,9 @@
# XCEngine API Documentation Skill
# XCEngine / XCEditor API Documentation Skill
## 目标
这份规范面向维护 `XCEngine` API 文档的 coding agent。它的目标不是“批量生成一套看起来完整的文档”而是持续把当前源码、测试和真实调用链路同步到唯一的 canonical API 文档树里。
这份规范面向维护 `XCEngine` / `XCEditor` API 文档的 coding agent。它的目标不是“批量生成一套看起来完整的文档”而是持续把当前源码、测试和真实调用链路同步到当前活跃的 canonical API 文档树里。
当前仓库已经进入“增量同步”阶段。重点不再是补骨架,而是:
@@ -12,11 +13,14 @@
## 当前范围
API 文档的正式范围包含部分:
API 文档的正式范围包含部分:
1. 引擎 public API
- 对齐 `engine/include/XCEngine/**`
2. Editor source-backed API
2. Editor public API
- 对齐 `new_editor/include/XCEditor/**`
- canonical 文档入口放在 `docs/api/XCEditor/**`
3. Editor source-backed API
- 对齐 `editor/src/**`
- canonical 文档入口仍放在 `docs/api/XCEngine/Editor/**`
@@ -28,35 +32,46 @@ API 文档的正式范围包含两部分:
- 审计结果、阶段性状态
- `docs/api/_tools/**`
- 审计、生成、修链脚本
- `docs/plan/API文档实时同步任务池_2026-04-03.md`
- 当前多任务并行同步池
- `docs/plan/API文档目录*.md`
- 当前活跃 API 计划、重构计划与并行任务板
- `docs/plan/API文档目录结构阶段进度_XCEditor与Model收口_2026-04-10.md`
- 最近一轮 `XCEditor / Model / GaussianSplat` 收口记录
- `docs/used/API文档实时同步任务池_2026-04-03.md`
- 最近一轮已完成的归档基线
- `README.md` / `editor/README.md` / `AGENT.md`
- 这些不是 canonical API 页,但一旦它们引用 API 模块结构、测试目录或 Editor helper 分层,就属于必须同步的活跃协作文档
## 硬约束
1. `docs/api/XCEngine/**` 是唯一 canonical API 树
1. `docs/api/XCEngine/**` `docs/api/XCEditor/**` 是当前两棵 canonical API 树;`docs/api/XCEngine/Editor/**` 继续承载 `editor/src/**` 的 source-backed 文档入口
2. 文档必须以“当前 header + 当前实现 + 当前测试 + 当前真实调用点”为依据,不能按旧文档或命名猜行为。
3. 删除的 API 页面要一起删除,相关交叉链接也必须一起清理。
4. 方法页优先使用源码中的原始函数名;不要擅自改成 kebab-case 或小写别名。
5. 不要把“设计意图”写成“当前实现行为”。
6. 不要为已经删除的 API 保留默认兼容入口页,除非任务明确要求。
7. `rebuild-status.md` 以审计脚本输出为准并发场景下stdout 比旧文件内容更可信。
8. 收口活跃文档;`docs/plan/used/**``docs/used/**` 等归档材料默认保留历史写法,不要为了“顺手统一”去重写归档
8. 默认先收口活跃文档;只有当任务明确涉及归档链、入口路径或历史基线说明时,才修改 `docs/used/**`
9. Windows 工作树里的路径大小写按真实目录名写,例如 `tests/Editor/``tests/Core/``tests/Scripting/`,不要继续传播 `tests/editor/``tests/core/` 之类的历史噪音。
## 工作流
### 1. 开工前先看两文件
### 1. 开工前先看两文件
- 任务池
- `docs/plan/API文档实时同步任务池_2026-04-03.md`
- 最新活跃计划
- `docs/plan/API文档目录*.md`
- `docs/plan/API文档目录结构阶段进度_XCEditor与Model收口_2026-04-10.md`
- 最新审计:
- `docs/api/_meta/rebuild-status.md`
如果任务池和工作树不一致,以当前源码和重新执行审计后的结果为准。
如果活跃计划和工作树不一致,以当前源码和重新执行审计后的结果为准。
如果 `docs/plan/` 下出现日期更晚的 API 相关计划或归档文件,优先读取更新日期更晚的文件,再判断当前任务池是否已经转入 `docs/plan/used/`
如果当前活跃计划没有覆盖你的问题,再回看:
- `docs/used/API文档实时同步任务池_2026-04-03.md`
作为最近一轮完成归档的基线。
如果 `docs/plan/` 下出现日期更晚的 API 相关计划,优先读取日期更晚的活跃文件;当前仓库里的归档根目录是 `docs/used/**`,不要再假设存在 `docs/plan/used/**`
如果工作内容会改到 `README.md``editor/README.md``AGENT.md`
@@ -121,10 +136,13 @@ python -B docs/api/_tools/audit_api_docs.py
- `docs/api/main.md`
- API 根页:
- `docs/api/XCEngine/XCEngine.md`
- `docs/api/XCEditor/XCEditor.md`
- 模块页:
- `docs/api/XCEngine/{ModuleName}/{ModuleName}.md`
- `docs/api/XCEditor/{ModuleName}/{ModuleName}.md`
- 子模块页:
- `docs/api/XCEngine/{ModuleName}/{SubmoduleName}/{SubmoduleName}.md`
- `docs/api/XCEditor/{ModuleName}/{SubmoduleName}/{SubmoduleName}.md`
示例:
@@ -132,6 +150,8 @@ python -B docs/api/_tools/audit_api_docs.py
- `docs/api/XCEngine/Core/Asset/Asset.md`
- `docs/api/XCEngine/Rendering/Passes/Passes.md`
- `docs/api/XCEngine/Editor/Viewport/Viewport.md`
- `docs/api/XCEditor/Foundation/Foundation.md`
- `docs/api/XCEditor/Shell/Shell.md`
### 2. Header / source-backed 目录
@@ -324,7 +344,7 @@ docs/api/XCEngine/Editor/Viewport/SceneViewportRenderPlan/
## 推荐命令
```powershell
rg --files docs/api/XCEngine
rg --files docs/api/XCEngine docs/api/XCEditor
rg --files tests/Editor
rg -n "SymbolName" engine/include engine/src editor/src tests docs/api
python -B docs/api/_tools/audit_api_docs.py

View File

@@ -0,0 +1,47 @@
# Collections
**命名空间**: `XCEngine::UI::Editor::Widgets`
**类型**: `submodule`
**描述**: 编辑器集合类控件子模块,覆盖列表、树、标签栏、滚动视图及其交互辅助。
## 概述
`Collections` 主要提供“多项内容如何排布、命中、滚动与选择”的公共 UI 原语。按当前头文件与实现分工:
- `UIEditorListView*`
- 双行列表项布局、命中测试与交互
- `UIEditorTreeView*`
- 树节点可见性、展开/折叠与行命中
- `UIEditorScrollView*`
- 视口、内容范围与滚动条交互
- `UIEditorTabStrip*`
- 面板标签切换
- `UIEditorInlineRenameSession`
- 就地重命名会话状态
这些类型大多位于 `XCEngine::UI::Editor::Widgets` 命名空间下,并且被 `Fields``Shell` 复用。
## 公开头文件
- `UIEditorInlineRenameSession.h`
- `UIEditorListView.h`
- `UIEditorListViewInteraction.h`
- `UIEditorScrollView.h`
- `UIEditorScrollViewInteraction.h`
- `UIEditorTabStrip.h`
- `UIEditorTabStripInteraction.h`
- `UIEditorTreeView.h`
- `UIEditorTreeViewInteraction.h`
## 当前实现边界
- 当前这里只建立目录索引页,具体头文件页仍需后续分批补齐。
- 该模块依赖 `XCEngine/UI/Widgets` 的选择、展开、输入模型,而不是自行维护通用状态容器。
## 相关文档
- [XCEditor](../XCEditor.md)
- [Fields](../Fields/Fields.md)
- [Widgets](../Widgets/Widgets.md)

View File

@@ -0,0 +1,36 @@
# UIEditorInlineRenameSession
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Collections/UIEditorInlineRenameSession.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorInlineRenameSession` public API。
## 概述
`UIEditorInlineRenameSession.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorInlineRenameSessionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorInlineRenameSessionRequest` | `struct` | 头文件中的公开声明。 |
| `UIEditorInlineRenameSessionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorInlineRenameSessionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `active` | `bool` | 结构体公开字段。 | `false` |
| `itemId` | `std::string` | 结构体公开字段。 | `{}` |
| `textFieldSpec` | `Widgets::UIEditorTextFieldSpec` | 结构体公开字段。 | `{}` |
| `textFieldInteraction` | `UIEditorTextFieldInteractionState` | 结构体公开字段。 | `{}` |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,37 @@
# UIEditorListView
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Collections/UIEditorListView.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorListView` public API。
## 概述
`UIEditorListView.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorListViewHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorListViewItem` | `struct` | 头文件中的公开声明。 |
| `UIEditorListViewState` | `struct` | 头文件中的公开声明。 |
| `UIEditorListViewMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorListViewPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorListViewLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorListViewHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorListViewInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Collections/UIEditorListViewInteraction.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorListViewInteraction` public API。
## 概述
`UIEditorListViewInteraction.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorListViewInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorListViewInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorListViewInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `listViewState` | `Widgets::UIEditorListViewState` | 结构体公开字段。 | `{}` |
| `keyboardNavigation` | `::XCEngine::UI::Widgets::UIKeyboardNavigationModel` | 结构体公开字段。 | `{}` |
| `selectionAnchorId` | `std::string` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorScrollView
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Collections/UIEditorScrollView.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorScrollView` public API。
## 概述
`UIEditorScrollView.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorScrollViewHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorScrollViewState` | `struct` | 头文件中的公开声明。 |
| `UIEditorScrollViewMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorScrollViewPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorScrollViewLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorScrollViewHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Content` | - | 枚举项。 |
| `ScrollbarTrack` | - | 枚举项。 |
| `ScrollbarThumb` | - | 枚举项。 |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorScrollViewInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Collections/UIEditorScrollViewInteraction.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorScrollViewInteraction` public API。
## 概述
`UIEditorScrollViewInteraction.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorScrollViewInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorScrollViewInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorScrollViewInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `scrollViewState` | `Widgets::UIEditorScrollViewState` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `thumbDragStartPointerY` | `float` | 结构体公开字段。 | `0.0f` |
| `thumbDragStartOffset` | `float` | 结构体公开字段。 | `0.0f` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,39 @@
# UIEditorTabStrip
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Collections/UIEditorTabStrip.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorTabStrip` public API。
## 概述
`UIEditorTabStrip.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorTabStripItem` | `struct` | 头文件中的公开声明。 |
| `UIEditorTabStripState` | `struct` | 头文件中的公开声明。 |
| `UIEditorTabStripMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorTabStripPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorTabStripLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorTabStripHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorTabStripHitTarget` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `tabId` | `std::string` | 结构体公开字段。 | `{}` |
| `title` | `std::string` | 结构体公开字段。 | `{}` |
| `closable` | `bool` | 结构体公开字段。 | `true` |
| `desiredHeaderLabelWidth` | `float` | 结构体公开字段。 | `0.0f` |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorTabStripInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Collections/UIEditorTabStripInteraction.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorTabStripInteraction` public API。
## 概述
`UIEditorTabStripInteraction.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorTabStripInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorTabStripInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorTabStripInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `tabStripState` | `Widgets::UIEditorTabStripState` | 结构体公开字段。 | `{}` |
| `navigationModel` | `::XCEngine::UI::Widgets::UITabStripModel` | 结构体公开字段。 | `{}` |
| `pressedTarget` | `Widgets::UIEditorTabStripHitTarget` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorTreeView
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Collections/UIEditorTreeView.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorTreeView` public API。
## 概述
`UIEditorTreeView.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorTreeViewHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorTreeViewItem` | `struct` | 头文件中的公开声明。 |
| `UIEditorTreeViewState` | `struct` | 头文件中的公开声明。 |
| `UIEditorTreeViewMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorTreeViewPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorTreeViewLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorTreeViewHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `Disclosure` | - | 枚举项。 |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorTreeViewInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Collections/UIEditorTreeViewInteraction.h`
**描述**: 定义 `XCEditor/Collections` 子目录中的 `UIEditorTreeViewInteraction` public API。
## 概述
`UIEditorTreeViewInteraction.h``XCEditor/Collections` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorTreeViewInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorTreeViewInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorTreeViewInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `treeViewState` | `Widgets::UIEditorTreeViewState` | 结构体公开字段。 | `{}` |
| `keyboardNavigation` | `::XCEngine::UI::Widgets::UIKeyboardNavigationModel` | 结构体公开字段。 | `{}` |
| `selectionAnchorId` | `std::string` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Collections.md) - 返回 `Collections` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,68 @@
# Fields
**命名空间**: `XCEngine::UI::Editor::Widgets`
**类型**: `submodule`
**描述**: 编辑器字段控件子模块,覆盖布尔、数字、文本、颜色、对象、资源与属性网格等值编辑控件。
## 概述
`Fields` 面向“属性编辑”场景。当前头文件可以分成两层:
- 单字段控件
- `UIEditorBoolField*`
- `UIEditorNumberField*`
- `UIEditorTextField*`
- `UIEditorEnumField*`
- `UIEditorColorField*`
- `UIEditorObjectField*`
- `UIEditorAssetField*`
- `UIEditorVector2/3/4Field*`
- 聚合编辑控件
- `UIEditorPropertyGrid*`
- 把 section、field row、弹窗菜单和颜色字段等组合成统一 inspector 布局
按当前 `UIEditorPropertyGrid.h`,这一层会复用:
- `Collections` 中的滚动/列表布局能力
- `Shell/UIEditorMenuPopup.h` 提供的弹出菜单能力
- `Widgets/UIEditorFieldRowLayout.h``UIEditorTextLayout.h` 等基础布局工具
## 公开头文件
- `UIEditorAssetField.h`
- `UIEditorAssetFieldInteraction.h`
- `UIEditorBoolField.h`
- `UIEditorBoolFieldInteraction.h`
- `UIEditorColorField.h`
- `UIEditorColorFieldInteraction.h`
- `UIEditorEnumField.h`
- `UIEditorEnumFieldInteraction.h`
- `UIEditorFieldStyle.h`
- `UIEditorNumberField.h`
- `UIEditorNumberFieldInteraction.h`
- `UIEditorObjectField.h`
- `UIEditorObjectFieldInteraction.h`
- `UIEditorPropertyGrid.h`
- `UIEditorPropertyGridInteraction.h`
- `UIEditorTextField.h`
- `UIEditorTextFieldInteraction.h`
- `UIEditorVector2Field.h`
- `UIEditorVector2FieldInteraction.h`
- `UIEditorVector3Field.h`
- `UIEditorVector3FieldInteraction.h`
- `UIEditorVector4Field.h`
- `UIEditorVector4FieldInteraction.h`
## 当前实现边界
- 当前这里只建立目录索引页,具体头文件页仍需后续逐个补齐。
- 这一层当前偏重 UI 表达与交互状态,不负责真正的资产解析、对象生命周期或命令持久化。
## 相关文档
- [XCEditor](../XCEditor.md)
- [Collections](../Collections/Collections.md)
- [Shell](../Shell/Shell.md)
- [Widgets](../Widgets/Widgets.md)

View File

@@ -0,0 +1,40 @@
# UIEditorAssetField
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorAssetField.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorAssetField` public API。
## 概述
`UIEditorAssetField.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorAssetFieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorAssetFieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorAssetFieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorAssetFieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorAssetFieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorAssetFieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorAssetFieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `ValueBox` | - | 枚举项。 |
| `PickerButton` | - | 枚举项。 |
| `ClearButton` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,34 @@
# UIEditorAssetFieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorAssetFieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorAssetFieldInteraction` public API。
## 概述
`UIEditorAssetFieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorAssetFieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorAssetFieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorAssetFieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `fieldState` | `Widgets::UIEditorAssetFieldState` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorBoolField
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorBoolField.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorBoolField` public API。
## 概述
`UIEditorBoolField.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorBoolFieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorBoolFieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorBoolFieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorBoolFieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorBoolFieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorBoolFieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorBoolFieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `Checkbox` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,34 @@
# UIEditorBoolFieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorBoolFieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorBoolFieldInteraction` public API。
## 概述
`UIEditorBoolFieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorBoolFieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorBoolFieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorBoolFieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `fieldState` | `Widgets::UIEditorBoolFieldState` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,46 @@
# UIEditorColorField
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorColorField.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorColorField` public API。
## 概述
`UIEditorColorField.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorColorFieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorColorFieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorColorFieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorColorFieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorColorFieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorColorFieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorColorFieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `Swatch` | - | 枚举项。 |
| `PopupSurface` | - | 枚举项。 |
| `PopupCloseButton` | - | 枚举项。 |
| `HueWheel` | - | 枚举项。 |
| `SaturationValue` | - | 枚举项。 |
| `RedChannel` | - | 枚举项。 |
| `GreenChannel` | - | 枚举项。 |
| `BlueChannel` | - | 枚举项。 |
| `AlphaChannel` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,34 @@
# UIEditorColorFieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorColorFieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorColorFieldInteraction` public API。
## 概述
`UIEditorColorFieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorColorFieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorColorFieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorColorFieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `colorFieldState` | `Widgets::UIEditorColorFieldState` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,39 @@
# UIEditorEnumField
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorEnumField.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorEnumField` public API。
## 概述
`UIEditorEnumField.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorEnumFieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorEnumFieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorEnumFieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorEnumFieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorEnumFieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorEnumFieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorEnumFieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `ValueBox` | - | 枚举项。 |
| `DropdownArrow` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,37 @@
# UIEditorEnumFieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorEnumFieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorEnumFieldInteraction` public API。
## 概述
`UIEditorEnumFieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorEnumFieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorEnumFieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorEnumFieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `fieldState` | `Widgets::UIEditorEnumFieldState` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `highlightedIndex` | `std::size_t` | 结构体公开字段。 | `Widgets::UIEditorMenuPopupInvalidIndex` |
| `pressedPopupIndex` | `std::size_t` | 结构体公开字段。 | `Widgets::UIEditorMenuPopupInvalidIndex` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
| `popupOpen` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,18 @@
# UIEditorFieldStyle
**命名空间**: `XCEngine`
**类型**: `header`
**头文件**: `XCEditor/Fields/UIEditorFieldStyle.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorFieldStyle` public API。
## 概述
`UIEditorFieldStyle.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorNumberField
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorNumberField.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorNumberField` public API。
## 概述
`UIEditorNumberField.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorNumberFieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorNumberFieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorNumberFieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorNumberFieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorNumberFieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorNumberFieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorNumberFieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `ValueBox` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorNumberFieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorNumberFieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorNumberFieldInteraction` public API。
## 概述
`UIEditorNumberFieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorNumberFieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorNumberFieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorNumberFieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `numberFieldState` | `Widgets::UIEditorNumberFieldState` | 结构体公开字段。 | `{}` |
| `textInputState` | `::XCEngine::UI::Text::UITextInputState` | 结构体公开字段。 | `{}` |
| `editModel` | `::XCEngine::UI::Widgets::UIPropertyEditModel` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,40 @@
# UIEditorObjectField
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorObjectField.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorObjectField` public API。
## 概述
`UIEditorObjectField.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorObjectFieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorObjectFieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorObjectFieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorObjectFieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorObjectFieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorObjectFieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorObjectFieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `ValueBox` | - | 枚举项。 |
| `ClearButton` | - | 枚举项。 |
| `PickerButton` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,34 @@
# UIEditorObjectFieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorObjectFieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorObjectFieldInteraction` public API。
## 概述
`UIEditorObjectFieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorObjectFieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorObjectFieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorObjectFieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `fieldState` | `Widgets::UIEditorObjectFieldState` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,53 @@
# UIEditorPropertyGrid
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorPropertyGrid.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorPropertyGrid` public API。
## 概述
`UIEditorPropertyGrid.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorPropertyGridFieldKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorPropertyGridHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorPropertyGridFieldLocation` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridNumberFieldValue` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridEnumFieldValue` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridColorFieldValue` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridVector2FieldValue` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridVector3FieldValue` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridVector4FieldValue` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridField` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridSection` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridColorFieldVisualState` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridState` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `Text` | `0` | 枚举项。 |
| `Bool` | - | 枚举项。 |
| `Number` | - | 枚举项。 |
| `Enum` | - | 枚举项。 |
| `Color` | - | 枚举项。 |
| `Vector2` | - | 枚举项。 |
| `Vector3` | - | 枚举项。 |
| `Vector4` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,37 @@
# UIEditorPropertyGridInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorPropertyGridInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorPropertyGridInteraction` public API。
## 概述
`UIEditorPropertyGridInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorPropertyGridInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorPropertyGridInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `propertyGridState` | `Widgets::UIEditorPropertyGridState` | 结构体公开字段。 | `{}` |
| `keyboardNavigation` | `::XCEngine::UI::Widgets::UIKeyboardNavigationModel` | 结构体公开字段。 | `{}` |
| `textInputState` | `::XCEngine::UI::Text::UITextInputState` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `pressedPopupIndex` | `std::size_t` | 结构体公开字段。 | `Widgets::UIEditorPropertyGridInvalidIndex` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorTextField
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorTextField.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorTextField` public API。
## 概述
`UIEditorTextField.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorTextFieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorTextFieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorTextFieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorTextFieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorTextFieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorTextFieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorTextFieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `ValueBox` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorTextFieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorTextFieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorTextFieldInteraction` public API。
## 概述
`UIEditorTextFieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorTextFieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorTextFieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorTextFieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `textFieldState` | `Widgets::UIEditorTextFieldState` | 结构体公开字段。 | `{}` |
| `textInputState` | `::XCEngine::UI::Text::UITextInputState` | 结构体公开字段。 | `{}` |
| `editModel` | `::XCEngine::UI::Widgets::UIPropertyEditModel` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorVector2Field
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorVector2Field.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorVector2Field` public API。
## 概述
`UIEditorVector2Field.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorVector2FieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorVector2FieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector2FieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector2FieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector2FieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector2FieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector2FieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `Component` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorVector2FieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorVector2FieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorVector2FieldInteraction` public API。
## 概述
`UIEditorVector2FieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorVector2FieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector2FieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector2FieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `vector2FieldState` | `Widgets::UIEditorVector2FieldState` | 结构体公开字段。 | `{}` |
| `textInputState` | `::XCEngine::UI::Text::UITextInputState` | 结构体公开字段。 | `{}` |
| `editModel` | `::XCEngine::UI::Widgets::UIPropertyEditModel` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorVector3Field
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorVector3Field.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorVector3Field` public API。
## 概述
`UIEditorVector3Field.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorVector3FieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorVector3FieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector3FieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector3FieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector3FieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector3FieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector3FieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `Component` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorVector3FieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorVector3FieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorVector3FieldInteraction` public API。
## 概述
`UIEditorVector3FieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorVector3FieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector3FieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector3FieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `vector3FieldState` | `Widgets::UIEditorVector3FieldState` | 结构体公开字段。 | `{}` |
| `textInputState` | `::XCEngine::UI::Text::UITextInputState` | 结构体公开字段。 | `{}` |
| `editModel` | `::XCEngine::UI::Widgets::UIPropertyEditModel` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,38 @@
# UIEditorVector4Field
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Fields/UIEditorVector4Field.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorVector4Field` public API。
## 概述
`UIEditorVector4Field.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorVector4FieldHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorVector4FieldSpec` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector4FieldState` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector4FieldMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector4FieldPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector4FieldLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector4FieldHitTarget` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `Row` | - | 枚举项。 |
| `Component` | - | 枚举项。 |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,36 @@
# UIEditorVector4FieldInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Fields/UIEditorVector4FieldInteraction.h`
**描述**: 定义 `XCEditor/Fields` 子目录中的 `UIEditorVector4FieldInteraction` public API。
## 概述
`UIEditorVector4FieldInteraction.h``XCEditor/Fields` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorVector4FieldInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector4FieldInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorVector4FieldInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `vector4FieldState` | `Widgets::UIEditorVector4FieldState` | 结构体公开字段。 | `{}` |
| `textInputState` | `::XCEngine::UI::Text::UITextInputState` | 结构体公开字段。 | `{}` |
| `editModel` | `::XCEngine::UI::Widgets::UIPropertyEditModel` | 结构体公开字段。 | `{}` |
| `pointerPosition` | `::XCEngine::UI::UIPoint` | 结构体公开字段。 | `{}` |
| `hasPointerPosition` | `bool` | 结构体公开字段。 | `false` |
## 相关文档
- [当前目录](../Fields.md) - 返回 `Fields` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,50 @@
# Foundation
**命名空间**: `XCEngine::UI::Editor`
**类型**: `module`
**描述**: `XCEditor` 的基础协议层,覆盖命令注册、命令派发、快捷键管理以及主题度量解析入口。
## 概览
`Foundation` 解决的是“shell 和控件真正运行前,需要先有一套什么样的 editor 级基础协议”。
按当前代码,职责主要分成四块:
- `UIEditorCommandRegistry.h`
- 定义 editor 命令描述、workspace 命令描述以及注册表校验规则。
- `UIEditorCommandDispatcher.h`
-`commandId` 解析为 workspace command 或 host command并执行 preview / dispatch。
- `UIEditorShortcutManager.h`
- 复用 `XCEngine::UI::UIShortcutRegistry` 完成快捷键绑定、冲突校验与调度。
- `UIEditorTheme.h`
-`Collections / Fields / Shell` 汇总默认 metrics / palette 解析入口。
这层不直接渲染 widget也不直接拥有 workspace 状态;它更像 `XCEditor` 的“命令 + 输入 + 主题”底座。
## 当前调用链
- `new_editor/src/Shell/UIEditorShellAsset.cpp` 会从 shell asset 构造命令注册表和快捷键管理器。
- `new_editor/src/Shell/UIEditorMenuModel.cpp` 通过命令注册表、命令派发器和快捷键管理器生成 menu item 的启用态与 shortcut 文案。
- 多组 `tests/UI/Editor/unit/**``tests/UI/Editor/integration/**` 当前直接把这层当作 editor shell 的最小可验证基础设施。
## 公开头文件
- [UIEditorCommandRegistry](UIEditorCommandRegistry/UIEditorCommandRegistry.md) - editor 命令描述与注册表校验规则。
- [UIEditorCommandDispatcher](UIEditorCommandDispatcher/UIEditorCommandDispatcher.md) - `commandId -> workspace/host dispatch` 入口。
- [UIEditorShortcutManager](UIEditorShortcutManager/UIEditorShortcutManager.md) - editor 快捷键绑定、校验和调度入口。
- [UIEditorTheme](UIEditorTheme/UIEditorTheme.md) - 默认 metrics / palette 解析入口。
## 当前实现边界
- 该模块不直接渲染 UI而是为 `Shell``Collections``Fields` 提供命令、快捷键和主题基础能力。
- 当前主题解析函数统一返回静态默认值,还没有引入动态主题切换或 style 覆盖链。
- host command 仍然通过 `UIEditorHostCommandHandler` 抽象对外,不把宿主实现细节泄漏回 public header。
## 相关文档
- [XCEditor](../XCEditor.md)
- [Shell](../Shell/Shell.md)
- [Collections](../Collections/Collections.md)
- [Fields](../Fields/Fields.md)

View File

@@ -0,0 +1,41 @@
# UIEditorCommandDispatcher::UIEditorCommandDispatcher()
构造对象。
该方法在 `XCEditor/Foundation/UIEditorCommandDispatcher.h` 中提供了 2 个重载,当前页面统一汇总这些公开声明。
## 重载 1: 声明
```cpp
UIEditorCommandDispatcher() = default;
```
**参数:** 无。
**返回:** `void` - 无返回值。
## 重载 2: 声明
```cpp
explicit UIEditorCommandDispatcher(UIEditorCommandRegistry commandRegistry);
```
**参数:**
- `commandRegistry` - 参数语义详见头文件声明。
**返回:** `void` - 无返回值。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
void Example() {
XCEngine::UIEditorCommandDispatcher object;
}
```
## 相关文档
- [返回类总览](UIEditorCommandDispatcher.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,32 @@
# UIEditorCommandDispatcher::Dispatch
公开方法,详见头文件声明。
```cpp
UIEditorCommandDispatchResult Dispatch( std::string_view commandId, UIEditorWorkspaceController& controller) const;
```
该方法声明于 `XCEditor/Foundation/UIEditorCommandDispatcher.h`,当前页面用于固定 `UIEditorCommandDispatcher` 类目录下的方法级 canonical 路径。
**参数:**
- `commandId` - 参数语义详见头文件声明。
- `controller` - 参数语义详见头文件声明。
**返回:** `UIEditorCommandDispatchResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
void Example() {
XCEngine::UIEditorCommandDispatcher object;
// 根据上下文补齐参数后调用 UIEditorCommandDispatcher::Dispatch(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorCommandDispatcher.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,32 @@
# UIEditorCommandDispatcher::Evaluate
公开方法,详见头文件声明。
```cpp
UIEditorCommandEvaluationResult Evaluate( std::string_view commandId, const UIEditorWorkspaceController& controller) const;
```
该方法声明于 `XCEditor/Foundation/UIEditorCommandDispatcher.h`,当前页面用于固定 `UIEditorCommandDispatcher` 类目录下的方法级 canonical 路径。
**参数:**
- `commandId` - 参数语义详见头文件声明。
- `controller` - 参数语义详见头文件声明。
**返回:** `UIEditorCommandEvaluationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
void Example() {
XCEngine::UIEditorCommandDispatcher object;
// 根据上下文补齐参数后调用 UIEditorCommandDispatcher::Evaluate(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorCommandDispatcher.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,30 @@
# UIEditorCommandDispatcher::GetCommandRegistry
获取相关状态或对象。
```cpp
const UIEditorCommandRegistry& GetCommandRegistry() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorCommandDispatcher.h`,当前页面用于固定 `UIEditorCommandDispatcher` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `const UIEditorCommandRegistry&` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
void Example() {
XCEngine::UIEditorCommandDispatcher object;
// 根据上下文补齐参数后调用 UIEditorCommandDispatcher::GetCommandRegistry(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorCommandDispatcher.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,30 @@
# UIEditorCommandDispatcher::GetHostCommandHandler
获取相关状态或对象。
```cpp
UIEditorHostCommandHandler* GetHostCommandHandler() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorCommandDispatcher.h`,当前页面用于固定 `UIEditorCommandDispatcher` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `UIEditorHostCommandHandler*` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
void Example() {
XCEngine::UIEditorCommandDispatcher object;
// 根据上下文补齐参数后调用 UIEditorCommandDispatcher::GetHostCommandHandler(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorCommandDispatcher.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,31 @@
# UIEditorCommandDispatcher::SetHostCommandHandler
设置相关状态或配置。
```cpp
void SetHostCommandHandler(UIEditorHostCommandHandler* handler);
```
该方法声明于 `XCEditor/Foundation/UIEditorCommandDispatcher.h`,当前页面用于固定 `UIEditorCommandDispatcher` 类目录下的方法级 canonical 路径。
**参数:**
- `handler` - 参数语义详见头文件声明。
**返回:** `void` - 无返回值。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
void Example() {
XCEngine::UIEditorCommandDispatcher object;
// 根据上下文补齐参数后调用 UIEditorCommandDispatcher::SetHostCommandHandler(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorCommandDispatcher.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,60 @@
# UIEditorCommandDispatcher
**命名空间**: `XCEngine::UI::Editor`
**类型**: `class`
**头文件**: `XCEditor/Foundation/UIEditorCommandDispatcher.h`
**描述**: editor 命令执行入口,负责把 `commandId` 解析为 workspace command 或 host command并执行 preview / dispatch。
## 概览
`UIEditorCommandDispatcher` 位于命令描述层和 shell 工作区控制器之间。它当前做两步:
1. `Evaluate(...)`
- 校验注册表,查找 `commandId`,把 `ActivePanel` / `FixedPanelId` 等静态描述解析成当前可执行的具体命令。
2. `Dispatch(...)`
-`Evaluate(...)` 成功后,把 workspace 命令交给 `UIEditorWorkspaceController`,或者把 host 命令交给 `UIEditorHostCommandHandler`
这让 menu、shortcut 和 shell interaction 都可以共享同一套命令求值与分发逻辑。
## 主要声明
| 声明 | 角色 |
|------|------|
| `UIEditorHostCommandHandler` | 宿主命令执行抽象,允许 shell 外部接管 host 命令。 |
| `UIEditorCommandEvaluationCode` | 命令求值失败或成功的细分原因。 |
| `UIEditorCommandEvaluationResult` | `Evaluate(...)` 的结果,包含解析出的 workspace command 与 preview 结果。 |
| `UIEditorCommandDispatchStatus` | 最终 dispatch 状态。 |
| `UIEditorCommandDispatchResult` | `Dispatch(...)` 的结果。 |
| `UIEditorCommandDispatcher` | 命令求值与分发器本体。 |
## 当前实现行为
- `ValidateConfiguration()` 直接复用 `ValidateUIEditorCommandRegistry(...)`
- `Evaluate(...)` 当前会:
- 在注册表无效时返回 `InvalidCommandRegistry`
- 在命令不存在时返回 `UnknownCommandId`
-`Host` 命令转发给 `UIEditorHostCommandHandler::EvaluateHostCommand(...)`
-`Workspace` 命令解析 `panelSource`
-`ActivePanel` 但当前 workspace 没有 active panel 时返回 `MissingActivePanel`
- 复制一份 controller 做 preview dispatch`previewResult` 预测命令是否会被拒绝
- `Dispatch(...)` 当前先调用 `Evaluate(...)`,只有可执行时才真正分发。
- host 命令和 workspace 命令共享统一结果结构,但最终执行路径不同。
## 测试与调用链
- `tests/UI/Editor/unit/test_ui_editor_command_dispatcher.cpp`
- 当前覆盖 active panel 解析、缺少 active panel 的拒绝路径,以及 dispatch 后 workspace 状态变更。
- `tests/UI/Editor/unit/test_ui_editor_shell_interaction.cpp`
- 当前通过 shell interaction 间接消费命令派发器。
- `tests/UI/Editor/integration/shell/menu_bar_basic/main.cpp`
- 当前把命令派发器挂进 menu bar / context menu 的真实交互路径。
## 相关文档
- [Foundation](../Foundation.md)
- [UIEditorCommandRegistry](../UIEditorCommandRegistry/UIEditorCommandRegistry.md)
- [UIEditorShortcutManager](../UIEditorShortcutManager/UIEditorShortcutManager.md)
- [UIEditorWorkspaceController](../../Shell/UIEditorWorkspaceController/UIEditorWorkspaceController.md)

View File

@@ -0,0 +1,30 @@
# UIEditorCommandDispatcher::ValidateConfiguration
公开方法,详见头文件声明。
```cpp
UIEditorCommandRegistryValidationResult ValidateConfiguration() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorCommandDispatcher.h`,当前页面用于固定 `UIEditorCommandDispatcher` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `UIEditorCommandRegistryValidationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
void Example() {
XCEngine::UIEditorCommandDispatcher object;
// 根据上下文补齐参数后调用 UIEditorCommandDispatcher::ValidateConfiguration(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorCommandDispatcher.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,59 @@
# UIEditorCommandRegistry
**命名空间**: `XCEngine::UI::Editor`
**类型**: `enums + structs + functions`
**头文件**: `XCEditor/Foundation/UIEditorCommandRegistry.h`
**描述**: editor 命令描述协议与注册表校验入口,负责定义 workspace/host 命令的静态声明格式。
## 概览
`UIEditorCommandRegistry.h``XCEditor` 命令系统的静态描述层。它不执行命令,而是先回答这些问题:
- 一个 editor 命令的 `commandId``displayName` 和命令种类是什么。
- 这个命令对应的是 workspace command 还是 host command。
- 如果是 workspace command它的 panel 路由来自固定 panel、当前 active panel还是根本不需要 panel。
- 当前整张命令表是否合法,是否存在重复 id、空 displayName 或错误的 panel source 组合。
## 主要声明
| 声明 | 角色 |
|------|------|
| `UIEditorCommandKind` | 区分 `Workspace``Host` 命令。 |
| `UIEditorCommandPanelSource` | 描述 panel 路由来自 `None / FixedPanelId / ActivePanel`。 |
| `UIEditorWorkspaceCommandDescriptor` | 把高层命令映射到 `UIEditorWorkspaceCommandKind + panel routing`。 |
| `UIEditorCommandDescriptor` | 单个 editor 命令的完整静态描述。 |
| `UIEditorCommandRegistry` | 命令描述表。 |
| `UIEditorCommandRegistryValidationCode` | 注册表校验失败原因。 |
| `FindUIEditorCommandDescriptor(...)` | 通过 `commandId` 查找描述。 |
| `ValidateUIEditorCommandRegistry(...)` | 校验命令表的完整性与路由合法性。 |
## 当前实现行为
- `ValidateUIEditorCommandRegistry(...)` 会拒绝:
-`commandId`
-`displayName`
- 重复 `commandId`
- host 命令错误携带 workspace panel routing
- 需要 panel 的 workspace 命令却没有 panel source
- 不需要 panel 的命令却错误携带 `FixedPanelId` / `ActivePanel`
- `FindUIEditorCommandDescriptor(...)` 当前按线性遍历 `registry.commands` 查找。
- `CommandKindRequiresPanelId(...)` 当前把 `OpenPanel / ClosePanel / ShowPanel / HidePanel / ActivatePanel` 视为需要 panel 路由;`ResetWorkspace` 不需要。
## 测试与调用链
- `tests/UI/Editor/unit/test_ui_editor_command_registry.cpp`
- 当前覆盖 descriptor 查找、重复 id、空 displayName 和 panel source 校验。
- `new_editor/src/Foundation/UIEditorCommandDispatcher.cpp`
- 直接依赖这份注册表做命令解析和配置校验。
- `new_editor/src/Shell/UIEditorMenuModel.cpp`
- 当前用它决定 menu item 的 command 元数据与启用态来源。
## 相关文档
- [Foundation](../Foundation.md)
- [UIEditorCommandDispatcher](../UIEditorCommandDispatcher/UIEditorCommandDispatcher.md)
- [UIEditorShortcutManager](../UIEditorShortcutManager/UIEditorShortcutManager.md)
- [UIEditorWorkspaceController](../../Shell/UIEditorWorkspaceController/UIEditorWorkspaceController.md)

View File

@@ -0,0 +1,30 @@
# UIEditorShortcutManager::ClearBindings
清空内部数据。
```cpp
void ClearBindings();
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `void` - 无返回值。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::ClearBindings(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,41 @@
# UIEditorShortcutManager::UIEditorShortcutManager()
构造对象。
该方法在 `XCEditor/Foundation/UIEditorShortcutManager.h` 中提供了 2 个重载,当前页面统一汇总这些公开声明。
## 重载 1: 声明
```cpp
UIEditorShortcutManager() = default;
```
**参数:** 无。
**返回:** `void` - 无返回值。
## 重载 2: 声明
```cpp
explicit UIEditorShortcutManager(UIEditorCommandRegistry commandRegistry);
```
**参数:**
- `commandRegistry` - 参数语义详见头文件声明。
**返回:** `void` - 无返回值。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,33 @@
# UIEditorShortcutManager::Dispatch
公开方法,详见头文件声明。
```cpp
UIEditorShortcutDispatchResult Dispatch( const XCEngine::UI::UIInputEvent& event, const XCEngine::UI::UIShortcutContext& shortcutContext, UIEditorWorkspaceController& controller) const;
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:**
- `event` - 参数语义详见头文件声明。
- `shortcutContext` - 参数语义详见头文件声明。
- `controller` - 参数语义详见头文件声明。
**返回:** `UIEditorShortcutDispatchResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::Dispatch(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,30 @@
# UIEditorShortcutManager::GetCommandDispatcher
获取相关状态或对象。
```cpp
const UIEditorCommandDispatcher& GetCommandDispatcher() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `const UIEditorCommandDispatcher&` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::GetCommandDispatcher(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,30 @@
# UIEditorShortcutManager::GetCommandRegistry
获取相关状态或对象。
```cpp
const UIEditorCommandRegistry& GetCommandRegistry() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `const UIEditorCommandRegistry&` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::GetCommandRegistry(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,30 @@
# UIEditorShortcutManager::GetHostCommandHandler
获取相关状态或对象。
```cpp
UIEditorHostCommandHandler* GetHostCommandHandler() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `UIEditorHostCommandHandler*` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::GetHostCommandHandler(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,31 @@
# UIEditorShortcutManager::GetPreferredShortcutText
获取相关状态或对象。
```cpp
std::string GetPreferredShortcutText(std::string_view commandId) const;
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:**
- `commandId` - 参数语义详见头文件声明。
**返回:** `std::string` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::GetPreferredShortcutText(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,30 @@
# UIEditorShortcutManager::GetShortcutRegistry
获取相关状态或对象。
```cpp
const XCEngine::UI::UIShortcutRegistry& GetShortcutRegistry() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `const XCEngine::UI::UIShortcutRegistry&` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::GetShortcutRegistry(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,31 @@
# UIEditorShortcutManager::RegisterBinding
注册对象、回调或映射。
```cpp
std::uint64_t RegisterBinding(const XCEngine::UI::UIShortcutBinding& binding);
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:**
- `binding` - 参数语义详见头文件声明。
**返回:** `std::uint64_t` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::RegisterBinding(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,31 @@
# UIEditorShortcutManager::SetHostCommandHandler
设置相关状态或配置。
```cpp
void SetHostCommandHandler(UIEditorHostCommandHandler* handler);
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:**
- `handler` - 参数语义详见头文件声明。
**返回:** `void` - 无返回值。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::SetHostCommandHandler(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,64 @@
# UIEditorShortcutManager
**命名空间**: `XCEngine::UI::Editor`
**类型**: `class`
**头文件**: `XCEditor/Foundation/UIEditorShortcutManager.h`
**描述**: editor 快捷键绑定与调度入口,负责把 `UIShortcutRegistry` 的匹配结果连接到 editor 命令系统。
## 概览
`UIEditorShortcutManager``UIShortcutRegistry``UIEditorCommandDispatcher` 之间增加了一层 editor 语义:
- 先校验 command registry 和 shortcut binding 是否自洽
- 再根据输入事件和 `UIShortcutContext` 找到最佳匹配 binding
- 最后把匹配结果转换成 editor command dispatch
它同时还承担 shortcut 文案格式化,所以 menu bar / context menu 可以直接显示“当前推荐快捷键文本”。
## 主要声明
| 声明 | 角色 |
|------|------|
| `UIEditorShortcutManagerValidationCode` | 快捷键配置校验失败原因。 |
| `UIEditorShortcutManagerValidationResult` | 快捷键配置校验结果。 |
| `UIEditorShortcutDispatchStatus` | `NoMatch / Suppressed / Dispatched / Rejected` 四类结果。 |
| `UIEditorShortcutDispatchResult` | dispatch 后返回的命令 id、scope、owner 和 workspace command 结果。 |
| `UIEditorShortcutManager` | 快捷键绑定、校验和调度器本体。 |
## 当前实现行为
- `ValidateConfiguration()` 当前会拒绝:
- 无效 command registry
- binding 缺少 `commandId`
- binding 指向未知命令
- `keyCode == 0`
-`Global` scope 却没有 `ownerId`
- chord/scope/owner 完全冲突的重复 binding
- `GetPreferredShortcutText(...)` 会按 `Widget > Panel > Window > Global` 的展示优先级挑选 binding并把 chord 格式化成 `Ctrl+H` 这类文本。
- `Dispatch(...)` 当前流程是:
- 配置校验
- `m_shortcutRegistry.Match(...)`
-`textInputActive == true`,返回 `Suppressed`
- 调用 `m_commandDispatcher.Dispatch(...)`
- 把匹配到的 scope / owner 和 command result 一并回填到结果结构
## 测试与调用链
- `tests/UI/Editor/unit/test_ui_editor_shortcut_manager.cpp`
- 当前覆盖未知命令、冲突 chord、active-panel 路由、panel scope 优先于 global以及 text-input suppression。
- `tests/UI/Editor/integration/state/shortcut_dispatch/main.cpp`
- 当前验证 shortcut manager 在 editor shell 状态路径上的实际行为。
- `new_editor/src/Shell/UIEditorShellAsset.cpp`
- 当前用 asset 中的 command registry + bindings 构建 editor 快捷键管理器。
- `new_editor/src/Shell/UIEditorMenuModel.cpp`
- 当前通过它读取 shortcut 文案并参与 menu item 启用态生成。
## 相关文档
- [Foundation](../Foundation.md)
- [UIEditorCommandRegistry](../UIEditorCommandRegistry/UIEditorCommandRegistry.md)
- [UIEditorCommandDispatcher](../UIEditorCommandDispatcher/UIEditorCommandDispatcher.md)
- [UIShortcutRegistry](../../../XCEngine/UI/Input/UIShortcutRegistry/UIShortcutRegistry.md)

View File

@@ -0,0 +1,31 @@
# UIEditorShortcutManager::UnregisterBinding
取消注册对象、回调或映射。
```cpp
bool UnregisterBinding(std::uint64_t bindingId);
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:**
- `bindingId` - 参数语义详见头文件声明。
**返回:** `bool` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::UnregisterBinding(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,30 @@
# UIEditorShortcutManager::ValidateConfiguration
公开方法,详见头文件声明。
```cpp
UIEditorShortcutManagerValidationResult ValidateConfiguration() const;
```
该方法声明于 `XCEditor/Foundation/UIEditorShortcutManager.h`,当前页面用于固定 `UIEditorShortcutManager` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `UIEditorShortcutManagerValidationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
void Example() {
XCEngine::UIEditorShortcutManager object;
// 根据上下文补齐参数后调用 UIEditorShortcutManager::ValidateConfiguration(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorShortcutManager.md)
- [返回模块目录](../Foundation.md)

View File

@@ -0,0 +1,44 @@
# UIEditorTheme
**命名空间**: `XCEngine::UI::Editor`
**类型**: `theme-accessor header`
**头文件**: `XCEditor/Foundation/UIEditorTheme.h`
**描述**: `XCEditor` 默认主题解析入口,向 `Collections / Fields / Shell` 各类控件暴露统一的 metrics 与 palette 访问函数。
## 概览
`UIEditorTheme.h` 当前不是“主题对象 + 可编辑主题树”,而是一组默认值解析函数。
这组函数把下游控件需要的 theme 数据集中暴露出来,包括:
- `Fields`
- bool / number / text / vector / enum / color / object / asset / property-grid
- `Collections`
- list-view / tree-view / scroll-view / tab-strip
- `Shell`
- menu-bar / menu-popup / status-bar / panel-frame / dock-host / viewport-slot / shell-compose / shell-interaction
## 当前实现行为
- `new_editor/src/Foundation/UIEditorTheme.cpp` 通过 `GetDefaultValue<T>()` + 一组宏生成所有 `ResolveUIEditor*` 默认访问器。
- 每个访问器当前都返回静态默认构造值,生命周期稳定,可安全被多处重复读取。
- 当前还没有:
- 主题资源加载
- runtime 主题切换
- 层叠式 style override
- 按 workspace / panel 定制局部 palette
## 当前调用链
- 多组 `tests/UI/Editor/integration/shell/*/main.cpp` 当前直接依赖这些默认 theme 访问器来构造演示场景。
- `Collections``Fields``Shell` 的控件页当前都把这里视为默认 metrics / palette 的公共来源。
## 相关文档
- [Foundation](../Foundation.md)
- [Fields](../../Fields/Fields.md)
- [Collections](../../Collections/Collections.md)
- [Shell](../../Shell/Shell.md)

View File

@@ -0,0 +1,74 @@
# Shell
**命名空间**: `XCEngine::UI::Editor`
**类型**: `submodule`
**描述**: 编辑器壳层子模块,覆盖 menu、dock、workspace、viewport slot、panel registry 以及整套 shell compose / interaction 流程。
## 概述
`Shell` 是当前新编辑器 public headers 中最靠近应用层的一层。按 `new_editor/app/Application.cpp` 当前启动链:
1. 先构造 `EditorShellAsset`
2.`ValidateEditorShellAsset(...)` 校验 panel / workspace / shortcut 配置
3. 创建 `UIEditorWorkspaceController`
4. 在每帧中调用 `UpdateUIEditorShellInteraction(...)`
5. 再调用 `AppendUIEditorShellInteraction(...)` 输出绘制数据
因此这个子模块既包含纯数据模型,也包含布局与交互协议:
- shell 资产与配置
- `UIEditorShellAsset.h`
- `UIEditorPanelRegistry.h`
- `UIEditorWorkspaceModel.h`
- `UIEditorWorkspaceSession.h`
- 壳层布局与交互
- `UIEditorShellCompose.h`
- `UIEditorShellInteraction.h`
- `UIEditorWorkspaceCompose.h`
- `UIEditorWorkspaceInteraction.h`
- 具体面板宿主与框架控件
- `UIEditorDockHost*`
- `UIEditorMenu*`
- `UIEditorStatusBar.h`
- `UIEditorViewportSlot.h`
- `UIEditorViewportShell.h`
## 公开头文件
- `UIEditorDockHost.h`
- `UIEditorDockHostInteraction.h`
- `UIEditorMenuBar.h`
- `UIEditorMenuModel.h`
- `UIEditorMenuPopup.h`
- `UIEditorMenuSession.h`
- `UIEditorPanelContentHost.h`
- `UIEditorPanelFrame.h`
- `UIEditorPanelHostLifecycle.h`
- `UIEditorPanelRegistry.h`
- `UIEditorShellAsset.h`
- `UIEditorShellCompose.h`
- `UIEditorShellInteraction.h`
- `UIEditorStatusBar.h`
- `UIEditorStructuredShell.h`
- `UIEditorViewportInputBridge.h`
- `UIEditorViewportShell.h`
- `UIEditorViewportSlot.h`
- `UIEditorWorkspaceCompose.h`
- `UIEditorWorkspaceController.h`
- `UIEditorWorkspaceInteraction.h`
- `UIEditorWorkspaceLayoutPersistence.h`
- `UIEditorWorkspaceModel.h`
- `UIEditorWorkspaceSession.h`
## 当前实现边界
- 当前这里只建立目录索引页,具体头文件页仍需后续分批补齐。
- 这层 public API 面向新编辑器宿主;旧版 `editor/src/Viewport/**` 的 source-backed helper 不属于这里。
## 相关文档
- [XCEditor](../XCEditor.md)
- [Foundation](../Foundation/Foundation.md)
- [Fields](../Fields/Fields.md)

View File

@@ -0,0 +1,49 @@
# UIEditorDockHost
**命名空间**: `XCEngine`
**类型**: `enum class`
**头文件**: `XCEditor/Shell/UIEditorDockHost.h`
**描述**: 定义 `XCEditor/Shell` 子目录中的 `UIEditorDockHost` public API。
## 概述
`UIEditorDockHost.h``XCEditor/Shell` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorDockHostHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorDockHostHitTarget` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostTabStripVisualState` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostState` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostTabItemLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostSplitterLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostPanelLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostTabStackLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostForegroundOptions` | `struct` | 头文件中的公开声明。 |
## 枚举值
| 枚举值 | 数值 | 描述 |
|--------|------|------|
| `None` | `0` | 枚举项。 |
| `SplitterHandle` | - | 枚举项。 |
| `TabStripBackground` | - | 枚举项。 |
| `Tab` | - | 枚举项。 |
| `TabCloseButton` | - | 枚举项。 |
| `PanelHeader` | - | 枚举项。 |
| `PanelBody` | - | 枚举项。 |
| `PanelFooter` | - | 枚举项。 |
| `PanelCloseButton` | - | 枚举项。 |
## 相关文档
- [当前目录](../Shell.md) - 返回 `Shell` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,34 @@
# UIEditorDockHostInteraction
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Shell/UIEditorDockHostInteraction.h`
**描述**: 定义 `XCEditor/Shell` 子目录中的 `UIEditorDockHostInteraction` public API。
## 概述
`UIEditorDockHostInteraction.h``XCEditor/Shell` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorDockHostTabStripInteractionEntry` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostInteractionState` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostInteractionResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorDockHostInteractionFrame` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `nodeId` | `std::string` | 结构体公开字段。 | `{}` |
| `state` | `UIEditorTabStripInteractionState` | 结构体公开字段。 | `{}` |
## 相关文档
- [当前目录](../Shell.md) - 返回 `Shell` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,39 @@
# UIEditorMenuBar
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Shell/UIEditorMenuBar.h`
**描述**: 定义 `XCEditor/Shell` 子目录中的 `UIEditorMenuBar` public API。
## 概述
`UIEditorMenuBar.h``XCEditor/Shell` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorMenuBarItem` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuBarState` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuBarMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuBarPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuBarLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuBarHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorMenuBarHitTarget` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `menuId` | `std::string` | 结构体公开字段。 | `{}` |
| `label` | `std::string` | 结构体公开字段。 | `{}` |
| `enabled` | `bool` | 结构体公开字段。 | `true` |
| `desiredLabelWidth` | `float` | 结构体公开字段。 | `0.0f` |
## 相关文档
- [当前目录](../Shell.md) - 返回 `Shell` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,40 @@
# UIEditorMenuModel
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Shell/UIEditorMenuModel.h`
**描述**: 定义 `XCEditor/Shell` 子目录中的 `UIEditorMenuModel` public API。
## 概述
`UIEditorMenuModel.h``XCEditor/Shell` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorMenuItemKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorMenuCheckedStateSource` | `enum class` | 头文件中的公开声明。 |
| `UIEditorMenuCheckedStateBinding` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuItemDescriptor` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuDescriptor` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuModel` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuModelValidationCode` | `enum class` | 头文件中的公开声明。 |
| `UIEditorMenuModelValidationResult` | `struct` | 头文件中的公开声明。 |
| `UIEditorResolvedMenuItem` | `struct` | 头文件中的公开声明。 |
| `UIEditorResolvedMenuDescriptor` | `struct` | 头文件中的公开声明。 |
| `UIEditorResolvedMenuModel` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `menus` | `std::vector<UIEditorMenuDescriptor>` | 结构体公开字段。 | `{}` |
## 相关文档
- [当前目录](../Shell.md) - 返回 `Shell` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,44 @@
# UIEditorMenuPopup
**命名空间**: `XCEngine`
**类型**: `struct`
**头文件**: `XCEditor/Shell/UIEditorMenuPopup.h`
**描述**: 定义 `XCEditor/Shell` 子目录中的 `UIEditorMenuPopup` public API。
## 概述
`UIEditorMenuPopup.h``XCEditor/Shell` 子目录 下的 public header当前页面作为平行目录中的 canonical 总览,用于汇总该头文件暴露的主要声明。
## 声明概览
| 声明 | 类型 | 说明 |
|------|------|------|
| `UIEditorMenuPopupItem` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuPopupState` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuPopupMetrics` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuPopupPalette` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuPopupLayout` | `struct` | 头文件中的公开声明。 |
| `UIEditorMenuPopupHitTargetKind` | `enum class` | 头文件中的公开声明。 |
| `UIEditorMenuPopupHitTarget` | `struct` | 头文件中的公开声明。 |
## 结构体成员
| 成员 | 类型 | 描述 | 默认值 |
|------|------|------|--------|
| `itemId` | `std::string` | 结构体公开字段。 | `{}` |
| `kind` | `::XCEngine::UI::Editor::UIEditorMenuItemKind` | 结构体公开字段。 | `::XCEngine::UI::Editor::UIEditorMenuItemKind::Command` |
| `label` | `std::string` | 结构体公开字段。 | `{}` |
| `shortcutText` | `std::string` | 结构体公开字段。 | `{}` |
| `enabled` | `bool` | 结构体公开字段。 | `true` |
| `checked` | `bool` | 结构体公开字段。 | `false` |
| `hasSubmenu` | `bool` | 结构体公开字段。 | `false` |
| `desiredLabelWidth` | `float` | 结构体公开字段。 | `0.0f` |
| `desiredShortcutWidth` | `float` | 结构体公开字段。 | `0.0f` |
## 相关文档
- [当前目录](../Shell.md) - 返回 `Shell` 平行目录
- [API 总索引](../../../main.md) - 返回顶层索引

View File

@@ -0,0 +1,31 @@
# UIEditorMenuSession::CloseAll
公开方法,详见头文件声明。
```cpp
UIEditorMenuSessionMutationResult CloseAll( ::XCEngine::UI::Widgets::UIPopupDismissReason dismissReason = ::XCEngine::UI::Widgets::UIPopupDismissReason::Programmatic);
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `dismissReason` - 参数语义详见头文件声明。
**返回:** `UIEditorMenuSessionMutationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::CloseAll(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,30 @@
# UIEditorMenuSession::DismissFromEscape
公开方法,详见头文件声明。
```cpp
UIEditorMenuSessionMutationResult DismissFromEscape();
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `UIEditorMenuSessionMutationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::DismissFromEscape(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,31 @@
# UIEditorMenuSession::DismissFromFocusLoss
公开方法,详见头文件声明。
```cpp
UIEditorMenuSessionMutationResult DismissFromFocusLoss( const UIInputPath& focusedPath);
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `focusedPath` - 参数语义详见头文件声明。
**返回:** `UIEditorMenuSessionMutationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::DismissFromFocusLoss(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,31 @@
# UIEditorMenuSession::DismissFromPointerDown
公开方法,详见头文件声明。
```cpp
UIEditorMenuSessionMutationResult DismissFromPointerDown( const UIInputPath& hitPath);
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `hitPath` - 参数语义详见头文件声明。
**返回:** `UIEditorMenuSessionMutationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::DismissFromPointerDown(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,31 @@
# UIEditorMenuSession::FindPopupState
查找并返回匹配对象。
```cpp
const UIEditorMenuPopupState* FindPopupState(std::string_view popupId) const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `popupId` - 参数语义详见头文件声明。
**返回:** `const UIEditorMenuPopupState*` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::FindPopupState(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,30 @@
# UIEditorMenuSession::GetOpenRootMenuId
获取相关状态或对象。
```cpp
std::string_view GetOpenRootMenuId() const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `std::string_view` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::GetOpenRootMenuId(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,30 @@
# UIEditorMenuSession::GetOpenSubmenuItemIds
获取相关状态或对象。
```cpp
const std::vector<std::string>& GetOpenSubmenuItemIds() const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `const std::vector<std::string>&` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::GetOpenSubmenuItemIds(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,30 @@
# UIEditorMenuSession::GetPopupOverlayModel
获取相关状态或对象。
```cpp
const ::XCEngine::UI::Widgets::UIPopupOverlayModel& GetPopupOverlayModel() const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `const ::XCEngine::UI::Widgets::UIPopupOverlayModel&` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::GetPopupOverlayModel(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,30 @@
# UIEditorMenuSession::GetPopupStates
获取相关状态或对象。
```cpp
const std::vector<UIEditorMenuPopupState>& GetPopupStates() const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `const std::vector<UIEditorMenuPopupState>&` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::GetPopupStates(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,30 @@
# UIEditorMenuSession::HasOpenMenu
判断是否具备指定状态或能力。
```cpp
[[nodiscard]] bool HasOpenMenu() const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:** 无。
**返回:** `[[nodiscard]] bool` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::HasOpenMenu(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,32 @@
# UIEditorMenuSession::HoverMenuBarRoot
公开方法,详见头文件声明。
```cpp
UIEditorMenuSessionMutationResult HoverMenuBarRoot( std::string_view menuId, ::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `menuId` - 参数语义详见头文件声明。
- `entry` - 参数语义详见头文件声明。
**返回:** `UIEditorMenuSessionMutationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::HoverMenuBarRoot(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,32 @@
# UIEditorMenuSession::HoverSubmenu
公开方法,详见头文件声明。
```cpp
UIEditorMenuSessionMutationResult HoverSubmenu( std::string_view itemId, ::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `itemId` - 参数语义详见头文件声明。
- `entry` - 参数语义详见头文件声明。
**返回:** `UIEditorMenuSessionMutationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::HoverSubmenu(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,31 @@
# UIEditorMenuSession::IsMenuOpen
查询当前状态。
```cpp
[[nodiscard]] bool IsMenuOpen(std::string_view menuId) const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `menuId` - 参数语义详见头文件声明。
**返回:** `[[nodiscard]] bool` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::IsMenuOpen(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,31 @@
# UIEditorMenuSession::IsPopupOpen
查询当前状态。
```cpp
[[nodiscard]] bool IsPopupOpen(std::string_view popupId) const;
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `popupId` - 参数语义详见头文件声明。
**返回:** `[[nodiscard]] bool` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::IsPopupOpen(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

View File

@@ -0,0 +1,32 @@
# UIEditorMenuSession::OpenMenuBarRoot
公开方法,详见头文件声明。
```cpp
UIEditorMenuSessionMutationResult OpenMenuBarRoot( std::string_view menuId, ::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
```
该方法声明于 `XCEditor/Shell/UIEditorMenuSession.h`,当前页面用于固定 `UIEditorMenuSession` 类目录下的方法级 canonical 路径。
**参数:**
- `menuId` - 参数语义详见头文件声明。
- `entry` - 参数语义详见头文件声明。
**返回:** `UIEditorMenuSessionMutationResult` - 返回值语义详见头文件声明。
**示例:**
```cpp
#include <XCEditor/Shell/UIEditorMenuSession.h>
void Example() {
XCEngine::UIEditorMenuSession object;
// 根据上下文补齐参数后调用 UIEditorMenuSession::OpenMenuBarRoot(...)。
(void)object;
}
```
## 相关文档
- [返回类总览](UIEditorMenuSession.md)
- [返回模块目录](../Shell.md)

Some files were not shown because too many files have changed in this diff Show More