Update ViewportCanvas and ViewportPanel to support terrain brush state and commit handling

This commit is contained in:
2026-04-18 20:21:58 +02:00
parent d42765d9f8
commit fc375c4937
2 changed files with 37 additions and 0 deletions

View File

@@ -4,6 +4,10 @@ import type { LoadedModelAsset } from "../assets/gltf-model-import";
import type { LoadedImageAsset } from "../assets/image-assets"; import type { LoadedImageAsset } from "../assets/image-assets";
import type { ProjectAssetRecord } from "../assets/project-assets"; import type { ProjectAssetRecord } from "../assets/project-assets";
import type { EditorSelection } from "../core/selection"; import type { EditorSelection } from "../core/selection";
import type {
ArmedTerrainBrushState,
TerrainBrushStrokeCommit
} from "../core/terrain-brush";
import { getWhiteboxSelectionFeedbackLabel } from "../core/whitebox-selection-feedback"; import { getWhiteboxSelectionFeedbackLabel } from "../core/whitebox-selection-feedback";
import type { ToolMode } from "../core/tool-mode"; import type { ToolMode } from "../core/tool-mode";
import { type WhiteboxSelectionMode } from "../core/whitebox-selection-mode"; import { type WhiteboxSelectionMode } from "../core/whitebox-selection-mode";
@@ -52,6 +56,7 @@ interface ViewportCanvasProps {
viewportGridVisible: boolean; viewportGridVisible: boolean;
selection: EditorSelection; selection: EditorSelection;
activeSelectionId: string | null; activeSelectionId: string | null;
terrainBrushState: ArmedTerrainBrushState | null;
toolMode: ToolMode; toolMode: ToolMode;
toolPreview: ViewportToolPreview; toolPreview: ViewportToolPreview;
transformSession: TransformSessionState; transformSession: TransformSessionState;
@@ -63,6 +68,7 @@ interface ViewportCanvasProps {
focusRequestId: number; focusRequestId: number;
focusSelection: EditorSelection; focusSelection: EditorSelection;
onSelectionChange(selection: EditorSelection): void; onSelectionChange(selection: EditorSelection): void;
onTerrainBrushCommit(commit: TerrainBrushStrokeCommit): boolean;
onCommitCreation(toolPreview: CreationViewportToolPreview): boolean; onCommitCreation(toolPreview: CreationViewportToolPreview): boolean;
onCameraStateChange(cameraState: ViewportPanelCameraState): void; onCameraStateChange(cameraState: ViewportPanelCameraState): void;
onToolPreviewChange(toolPreview: ViewportToolPreview): void; onToolPreviewChange(toolPreview: ViewportToolPreview): void;
@@ -86,6 +92,7 @@ export function ViewportCanvas({
viewportGridVisible, viewportGridVisible,
selection, selection,
activeSelectionId, activeSelectionId,
terrainBrushState,
toolMode, toolMode,
toolPreview, toolPreview,
transformSession, transformSession,
@@ -97,6 +104,7 @@ export function ViewportCanvas({
focusRequestId, focusRequestId,
focusSelection, focusSelection,
onSelectionChange, onSelectionChange,
onTerrainBrushCommit,
onCommitCreation, onCommitCreation,
onCameraStateChange, onCameraStateChange,
onToolPreviewChange, onToolPreviewChange,
@@ -209,6 +217,10 @@ export function ViewportCanvas({
hostRef.current?.setBrushSelectionChangeHandler(onSelectionChange); hostRef.current?.setBrushSelectionChangeHandler(onSelectionChange);
}, [onSelectionChange]); }, [onSelectionChange]);
useEffect(() => {
hostRef.current?.setTerrainBrushCommitHandler?.(onTerrainBrushCommit);
}, [onTerrainBrushCommit]);
useEffect(() => { useEffect(() => {
hostRef.current?.setWhiteboxHoverLabelChangeHandler( hostRef.current?.setWhiteboxHoverLabelChangeHandler(
setHoveredWhiteboxLabel setHoveredWhiteboxLabel
@@ -252,6 +264,10 @@ export function ViewportCanvas({
hostRef.current?.setToolMode(toolMode); hostRef.current?.setToolMode(toolMode);
}, [toolMode]); }, [toolMode]);
useLayoutEffect(() => {
hostRef.current?.setTerrainBrushState?.(terrainBrushState);
}, [terrainBrushState]);
useLayoutEffect(() => { useLayoutEffect(() => {
hostRef.current?.setCreationPreview( hostRef.current?.setCreationPreview(
toolMode === "create" && toolPreview.kind === "create" toolMode === "create" && toolPreview.kind === "create"
@@ -280,6 +296,8 @@ export function ViewportCanvas({
const selectedWhiteboxLabel = toolMode === "select" const selectedWhiteboxLabel = toolMode === "select"
? getWhiteboxSelectionFeedbackLabel(sceneDocument, selection) ? getWhiteboxSelectionFeedbackLabel(sceneDocument, selection)
: null; : null;
const terrainBrushOverlayVisible =
toolMode === "select" && terrainBrushState !== null;
const resolvedViewportBackground = const resolvedViewportBackground =
editorSimulationScene !== null && editorSimulationClock !== null editorSimulationScene !== null && editorSimulationClock !== null
? resolveRuntimeDayNightWorldState( ? resolveRuntimeDayNightWorldState(
@@ -291,6 +309,7 @@ export function ViewportCanvas({
const showOverlay = const showOverlay =
previewVisible || previewVisible ||
transformPreviewVisible || transformPreviewVisible ||
terrainBrushOverlayVisible ||
selectedWhiteboxLabel !== null || selectedWhiteboxLabel !== null ||
hoveredWhiteboxLabel !== null; hoveredWhiteboxLabel !== null;
@@ -351,6 +370,14 @@ export function ViewportCanvas({
] ]
.filter((part) => part !== null) .filter((part) => part !== null)
.join(" · ")} .join(" · ")}
</div>
)}
{!terrainBrushOverlayVisible ? null : (
<div
className="viewport-canvas__overlay-preview"
data-testid={`viewport-terrain-brush-preview-${panelId}`}
>
terrain · {terrainBrushState.tool}
</div> </div>
)} )}
{selectedWhiteboxLabel === null ? null : ( {selectedWhiteboxLabel === null ? null : (

View File

@@ -25,6 +25,10 @@ import type { LoadedModelAsset } from "../assets/gltf-model-import";
import type { LoadedImageAsset } from "../assets/image-assets"; import type { LoadedImageAsset } from "../assets/image-assets";
import type { ProjectAssetRecord } from "../assets/project-assets"; import type { ProjectAssetRecord } from "../assets/project-assets";
import type { EditorSelection } from "../core/selection"; import type { EditorSelection } from "../core/selection";
import type {
ArmedTerrainBrushState,
TerrainBrushStrokeCommit
} from "../core/terrain-brush";
import { import {
getWhiteboxSelectionModeLabel, getWhiteboxSelectionModeLabel,
WHITEBOX_SELECTION_MODES, WHITEBOX_SELECTION_MODES,
@@ -62,6 +66,7 @@ interface ViewportPanelProps {
viewportGridVisible: boolean; viewportGridVisible: boolean;
selection: EditorSelection; selection: EditorSelection;
activeSelectionId: string | null; activeSelectionId: string | null;
terrainBrushState: ArmedTerrainBrushState | null;
toolMode: ToolMode; toolMode: ToolMode;
toolPreview: ViewportToolPreview; toolPreview: ViewportToolPreview;
transformSession: TransformSessionState; transformSession: TransformSessionState;
@@ -85,6 +90,7 @@ interface ViewportPanelProps {
displayMode: ViewportDisplayMode displayMode: ViewportDisplayMode
): void; ): void;
onCommitCreation(toolPreview: CreationViewportToolPreview): boolean; onCommitCreation(toolPreview: CreationViewportToolPreview): boolean;
onTerrainBrushCommit(commit: TerrainBrushStrokeCommit): boolean;
onCameraStateChange(cameraState: ViewportPanelCameraState): void; onCameraStateChange(cameraState: ViewportPanelCameraState): void;
onToolPreviewChange(toolPreview: ViewportToolPreview): void; onToolPreviewChange(toolPreview: ViewportToolPreview): void;
onBeginTransformOperation(operation: TransformOperation): void; onBeginTransformOperation(operation: TransformOperation): void;
@@ -136,6 +142,7 @@ export function ViewportPanel({
viewportGridVisible, viewportGridVisible,
selection, selection,
activeSelectionId, activeSelectionId,
terrainBrushState,
toolMode, toolMode,
toolPreview, toolPreview,
transformSession, transformSession,
@@ -153,6 +160,7 @@ export function ViewportPanel({
onSetPanelViewMode, onSetPanelViewMode,
onSetPanelDisplayMode, onSetPanelDisplayMode,
onCommitCreation, onCommitCreation,
onTerrainBrushCommit,
onCameraStateChange, onCameraStateChange,
onToolPreviewChange, onToolPreviewChange,
onBeginTransformOperation, onBeginTransformOperation,
@@ -198,6 +206,7 @@ export function ViewportPanel({
viewportGridVisible={viewportGridVisible} viewportGridVisible={viewportGridVisible}
selection={selection} selection={selection}
activeSelectionId={activeSelectionId} activeSelectionId={activeSelectionId}
terrainBrushState={terrainBrushState}
toolMode={toolMode} toolMode={toolMode}
toolPreview={toolPreview} toolPreview={toolPreview}
transformSession={transformSession} transformSession={transformSession}
@@ -209,6 +218,7 @@ export function ViewportPanel({
focusRequestId={focusRequestId} focusRequestId={focusRequestId}
focusSelection={focusSelection} focusSelection={focusSelection}
onSelectionChange={onSelectionChange} onSelectionChange={onSelectionChange}
onTerrainBrushCommit={onTerrainBrushCommit}
onCommitCreation={onCommitCreation} onCommitCreation={onCommitCreation}
onCameraStateChange={onCameraStateChange} onCameraStateChange={onCameraStateChange}
onToolPreviewChange={onToolPreviewChange} onToolPreviewChange={onToolPreviewChange}