resources: formalize internal shader ir

This commit is contained in:
2026-04-07 11:31:13 +08:00
parent 1c87650fb3
commit 864438c508
11 changed files with 431 additions and 259 deletions

View File

@@ -46,6 +46,7 @@ using XCEngine::UI::Editor::BuildUIEditorWorkspacePanel;
using XCEngine::UI::Editor::BuildUIEditorWorkspaceSplit;
using XCEngine::UI::Editor::BuildUIEditorWorkspaceTabStack;
using XCEngine::UI::Editor::CollectUIEditorWorkspaceVisiblePanels;
using XCEngine::UI::Editor::FindUIEditorWorkspaceViewportPresentationFrame;
using XCEngine::UI::Editor::GetUIEditorCommandDispatchStatusName;
using XCEngine::UI::Editor::UpdateUIEditorShellInteraction;
using XCEngine::UI::Editor::UIEditorCommandDispatchResult;
@@ -63,6 +64,7 @@ using XCEngine::UI::Editor::UIEditorShellInteractionFrame;
using XCEngine::UI::Editor::UIEditorShellInteractionModel;
using XCEngine::UI::Editor::UIEditorShellInteractionResult;
using XCEngine::UI::Editor::UIEditorShellInteractionState;
using XCEngine::UI::Editor::UIEditorViewportInputBridgeFrame;
using XCEngine::UI::Editor::UIEditorWorkspaceCommandKind;
using XCEngine::UI::Editor::UIEditorWorkspaceController;
using XCEngine::UI::Editor::UIEditorWorkspaceModel;
@@ -120,11 +122,15 @@ bool ContainsPoint(const UIRect& rect, float x, float y) {
bool HasMeaningfulInteractionResult(const UIEditorShellInteractionResult& result) {
return result.consumed ||
result.requestPointerCapture ||
result.releasePointerCapture ||
result.commandTriggered ||
result.menuMutation.changed ||
result.workspaceResult.consumed ||
!result.menuId.empty() ||
!result.popupId.empty() ||
!result.itemId.empty() ||
!result.viewportPanelId.empty() ||
!result.commandId.empty();
}
@@ -149,6 +155,34 @@ std::string FormatDismissReason(UIPopupDismissReason reason) {
return "Unknown";
}
std::string DescribeViewportEvent(const UIEditorViewportInputBridgeFrame& frame) {
if (frame.captureStarted) {
return "Viewport CaptureStarted";
}
if (frame.captureEnded) {
return "Viewport CaptureEnded";
}
if (frame.focusGained) {
return "Viewport FocusGained";
}
if (frame.focusLost) {
return "Viewport FocusLost";
}
if (frame.pointerPressedInside) {
return "Viewport PointerDownInside";
}
if (frame.pointerReleasedInside) {
return "Viewport PointerUpInside";
}
if (frame.pointerMoved) {
return "Viewport PointerMove";
}
if (frame.wheelDelta != 0.0f) {
return "Viewport Wheel";
}
return "Viewport Input";
}
std::string JoinVisiblePanelIds(
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session) {
@@ -357,8 +391,11 @@ private:
void UpdateLayout();
void HandleMouseMove(float x, float y);
void HandleLeftButtonDown(float x, float y);
void HandleLeftButtonUp(float x, float y);
void ExecuteAction(ActionId action);
UIEditorShellInteractionModel BuildInteractionModel() const;
bool HasInteractiveCaptureState() const;
void ApplyHostCaptureRequests(const UIEditorShellInteractionResult& result);
void SetInteractionResult(const UIEditorShellInteractionResult& result);
void SetDispatchResult(const UIEditorCommandDispatchResult& result);
void RenderFrame();
@@ -464,6 +501,12 @@ LRESULT CALLBACK ScenarioApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LP
return 0;
}
break;
case WM_LBUTTONUP:
if (app != nullptr) {
app->HandleLeftButtonUp(static_cast<float>(GET_X_LPARAM(lParam)), static_cast<float>(GET_Y_LPARAM(lParam)));
return 0;
}
break;
case WM_SETFOCUS:
if (app != nullptr) {
UIInputEvent event = {};
@@ -480,6 +523,16 @@ LRESULT CALLBACK ScenarioApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LP
return 0;
}
break;
case WM_CAPTURECHANGED:
if (app != nullptr &&
reinterpret_cast<HWND>(lParam) != hwnd &&
app->HasInteractiveCaptureState()) {
UIInputEvent event = {};
event.type = UIInputEventType::FocusLost;
app->m_pendingInputEvents.push_back(event);
return 0;
}
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (app != nullptr) {
@@ -553,6 +606,9 @@ bool ScenarioApp::Initialize(HINSTANCE hInstance, int nCmdShow) {
}
void ScenarioApp::Shutdown() {
if (GetCapture() == m_hwnd) {
ReleaseCapture();
}
m_autoScreenshot.Shutdown();
m_renderer.Shutdown();
if (m_hwnd != nullptr && IsWindow(m_hwnd)) {
@@ -564,6 +620,9 @@ void ScenarioApp::Shutdown() {
}
void ScenarioApp::ResetScenario() {
if (GetCapture() == m_hwnd) {
ReleaseCapture();
}
m_controller = BuildDefaultUIEditorWorkspaceController(BuildPanelRegistry(), BuildWorkspace());
m_commandDispatcher = UIEditorCommandDispatcher(BuildCommandRegistry());
m_menuModel = BuildMenuModel();
@@ -627,6 +686,14 @@ void ScenarioApp::HandleLeftButtonDown(float x, float y) {
m_pendingInputEvents.push_back(event);
}
void ScenarioApp::HandleLeftButtonUp(float x, float y) {
UIInputEvent event = {};
event.type = UIInputEventType::PointerButtonUp;
event.position = UIPoint(x, y);
event.pointerButton = UIPointerButton::Left;
m_pendingInputEvents.push_back(event);
}
void ScenarioApp::ExecuteAction(ActionId action) {
if (action == ActionId::Reset) {
ResetScenario();
@@ -642,6 +709,29 @@ void ScenarioApp::ExecuteAction(ActionId action) {
m_lastColor = kWarning;
}
bool ScenarioApp::HasInteractiveCaptureState() const {
if (m_interactionState.workspaceInteractionState.dockHostInteractionState.splitterDragState.active) {
return true;
}
for (const auto& panelState : m_interactionState.workspaceInteractionState.composeState.panelStates) {
if (panelState.viewportShellState.inputBridgeState.captured) {
return true;
}
}
return false;
}
void ScenarioApp::ApplyHostCaptureRequests(const UIEditorShellInteractionResult& result) {
if (result.requestPointerCapture && GetCapture() != m_hwnd) {
SetCapture(m_hwnd);
}
if (result.releasePointerCapture && GetCapture() == m_hwnd) {
ReleaseCapture();
}
}
UIEditorShellInteractionModel ScenarioApp::BuildInteractionModel() const {
UIEditorShellInteractionModel model = {};
model.resolvedMenuModel = BuildUIEditorResolvedMenuModel(
@@ -720,6 +810,46 @@ void ScenarioApp::SetInteractionResult(const UIEditorShellInteractionResult& res
return;
}
if (result.workspaceResult.dockHostResult.layoutResult.status !=
XCEngine::UI::Editor::UIEditorWorkspaceLayoutOperationStatus::Rejected) {
m_lastStatus = "WorkspaceLayout";
m_lastMessage = result.workspaceResult.dockHostResult.layoutResult.message;
m_lastColor = kSuccess;
return;
}
if (result.workspaceResult.dockHostResult.commandResult.status !=
XCEngine::UI::Editor::UIEditorWorkspaceCommandStatus::Rejected) {
m_lastStatus = "WorkspaceCommand";
m_lastMessage = result.workspaceResult.dockHostResult.commandResult.message;
m_lastColor = kSuccess;
return;
}
if (!result.viewportPanelId.empty()) {
m_lastStatus = result.viewportPanelId;
m_lastMessage = DescribeViewportEvent(result.viewportInputFrame);
m_lastColor =
result.viewportInputFrame.captureStarted || result.viewportInputFrame.focusGained
? kSuccess
: kWarning;
return;
}
if (result.requestPointerCapture) {
m_lastStatus = "Capture";
m_lastMessage = "宿主已收到 root shell 返回的 pointer capture 请求。";
m_lastColor = kSuccess;
return;
}
if (result.releasePointerCapture) {
m_lastStatus = "Release";
m_lastMessage = "宿主已执行 root shell 返回的 pointer release。";
m_lastColor = kWarning;
return;
}
if (result.consumed) {
m_lastStatus = "NoOp";
m_lastMessage = "这次输入被根壳交互层消费,但没有触发额外状态变化。";
@@ -738,27 +868,29 @@ void ScenarioApp::RenderFrame() {
m_cachedModel = BuildInteractionModel();
m_cachedFrame = UpdateUIEditorShellInteraction(
m_interactionState,
m_controller,
m_shellRect,
m_controller.GetPanelRegistry(),
m_controller.GetWorkspace(),
m_controller.GetSession(),
m_cachedModel,
m_pendingInputEvents);
m_pendingInputEvents.clear();
ApplyHostCaptureRequests(m_cachedFrame.result);
SetInteractionResult(m_cachedFrame.result);
if (m_cachedFrame.result.commandTriggered) {
m_cachedModel = BuildInteractionModel();
m_cachedFrame = UpdateUIEditorShellInteraction(
m_interactionState,
m_controller,
m_shellRect,
m_controller.GetPanelRegistry(),
m_controller.GetWorkspace(),
m_controller.GetSession(),
m_cachedModel,
{});
}
const auto* viewportFrame =
FindUIEditorWorkspaceViewportPresentationFrame(m_cachedFrame.workspaceInteractionFrame.composeFrame, "scene");
const std::string selectedPresentation =
viewportFrame != nullptr ? "ViewportShell" : "DockHost Placeholder";
RECT clientRect = {};
GetClientRect(m_hwnd, &clientRect);
const float width = static_cast<float>((std::max)(clientRect.right - clientRect.left, 1L));
@@ -772,9 +904,9 @@ void ScenarioApp::RenderFrame() {
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 70.0f), "1. 验证 MenuBar 的 root open / root switch 行为是否统一稳定。", kTextPrimary, 12.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 92.0f), "2. 验证 hover 子菜单时child popup 是否直接展开,不需要额外点击。", kTextPrimary, 12.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 114.0f), "3. 验证 outside pointer down / Esc / focus loss 是否能正确收起 popup chain。", kTextPrimary, 12.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 136.0f), "4. 验证预览区是真实 root shellMenuBar + Workspace + StatusBar + popup overlay", kTextPrimary, 12.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 158.0f), "5. 验证 command 只通过最小 dispatch hook 回传,不接旧 editor 业务。", kTextPrimary, 12.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 182.0f), "建议操作:点击 Filehover `Workspace Tools`再按 Esc 或点预览外空白处。", kTextWeak, 11.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 136.0f), "4. 验证菜单打开时会屏蔽 workspace 输入菜单关闭后workspace 交互立即恢复", kTextPrimary, 12.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 158.0f), "5. 验证 root shell 会继续透传 viewport / splitter 的 capture 请求,不接旧 editor 业务。", kTextPrimary, 12.0f);
drawList.AddText(UIPoint(m_introRect.x + 16.0f, m_introRect.y + 182.0f), "建议操作:点击 Filehover `Workspace Tools`,点预览外空白处,再点 `Document` 或拖 splitter", kTextWeak, 11.0f);
DrawCard(drawList, m_controlsRect, "操作", "只保留这个场景必要的控制。");
for (const ButtonState& button : m_buttons) {
@@ -791,13 +923,16 @@ void ScenarioApp::RenderFrame() {
addStateLine("Open Root", m_cachedFrame.openRootMenuId.empty() ? "(none)" : m_cachedFrame.openRootMenuId, kTextPrimary);
addStateLine("Popup Chain", JoinPopupChainIds(m_interactionState), kTextPrimary, 11.0f);
addStateLine("Submenu Path", JoinSubmenuPathIds(m_interactionState), kTextPrimary, 11.0f);
addStateLine("Selected Presentation", selectedPresentation, kTextPrimary, 11.0f);
addStateLine("Active Panel", m_controller.GetWorkspace().activePanelId.empty() ? "(none)" : m_controller.GetWorkspace().activePanelId, kTextPrimary, 11.0f);
addStateLine("Focused", FormatBool(m_cachedFrame.focused), m_cachedFrame.focused ? kSuccess : kTextMuted);
addStateLine("Result", m_lastStatus, m_lastColor);
drawList.AddText(UIPoint(m_stateRect.x + 16.0f, stateY + 4.0f), m_lastMessage, kTextMuted, 11.0f);
stateY += 34.0f;
addStateLine("Visible Panels", JoinVisiblePanelIds(m_controller.GetWorkspace(), m_controller.GetSession()), kTextWeak, 11.0f);
addStateLine("Host Capture", FormatBool(GetCapture() == m_hwnd), GetCapture() == m_hwnd ? kSuccess : kTextMuted, 11.0f);
addStateLine(
"Capture",
"Screenshot",
m_autoScreenshot.HasPendingCapture()
? "截图排队中..."
: (m_autoScreenshot.GetLastCaptureSummary().empty()