Add transform session handling to ViewportCanvas and ViewportPanel
This commit is contained in:
@@ -6,6 +6,7 @@ import type { ProjectAssetRecord } from "../assets/project-assets";
|
|||||||
import type { EditorSelection } from "../core/selection";
|
import type { EditorSelection } from "../core/selection";
|
||||||
import type { ToolMode } from "../core/tool-mode";
|
import type { ToolMode } from "../core/tool-mode";
|
||||||
import type { Vec3 } from "../core/vector";
|
import type { Vec3 } from "../core/vector";
|
||||||
|
import type { ActiveTransformSession, TransformSessionState } from "../core/transform-session";
|
||||||
import type { SceneDocument } from "../document/scene-document";
|
import type { SceneDocument } from "../document/scene-document";
|
||||||
import type { WorldSettings } from "../document/world-settings";
|
import type { WorldSettings } from "../document/world-settings";
|
||||||
import { createWorldBackgroundStyle } from "../shared-ui/world-background-style";
|
import { createWorldBackgroundStyle } from "../shared-ui/world-background-style";
|
||||||
@@ -34,6 +35,7 @@ interface ViewportCanvasProps {
|
|||||||
selection: EditorSelection;
|
selection: EditorSelection;
|
||||||
toolMode: ToolMode;
|
toolMode: ToolMode;
|
||||||
toolPreview: ViewportToolPreview;
|
toolPreview: ViewportToolPreview;
|
||||||
|
transformSession: TransformSessionState;
|
||||||
cameraState: ViewportPanelCameraState;
|
cameraState: ViewportPanelCameraState;
|
||||||
viewMode: ViewportViewMode;
|
viewMode: ViewportViewMode;
|
||||||
displayMode: ViewportDisplayMode;
|
displayMode: ViewportDisplayMode;
|
||||||
@@ -45,6 +47,9 @@ interface ViewportCanvasProps {
|
|||||||
onCommitCreation(toolPreview: CreationViewportToolPreview): boolean;
|
onCommitCreation(toolPreview: CreationViewportToolPreview): boolean;
|
||||||
onCameraStateChange(cameraState: ViewportPanelCameraState): void;
|
onCameraStateChange(cameraState: ViewportPanelCameraState): void;
|
||||||
onToolPreviewChange(toolPreview: ViewportToolPreview): void;
|
onToolPreviewChange(toolPreview: ViewportToolPreview): void;
|
||||||
|
onTransformSessionChange(transformSession: TransformSessionState): void;
|
||||||
|
onTransformCommit(transformSession: ActiveTransformSession): void;
|
||||||
|
onTransformCancel(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ViewportCanvas({
|
export function ViewportCanvas({
|
||||||
@@ -57,6 +62,7 @@ export function ViewportCanvas({
|
|||||||
selection,
|
selection,
|
||||||
toolMode,
|
toolMode,
|
||||||
toolPreview,
|
toolPreview,
|
||||||
|
transformSession,
|
||||||
cameraState,
|
cameraState,
|
||||||
viewMode,
|
viewMode,
|
||||||
displayMode,
|
displayMode,
|
||||||
@@ -67,7 +73,10 @@ export function ViewportCanvas({
|
|||||||
onSelectionChange,
|
onSelectionChange,
|
||||||
onCommitCreation,
|
onCommitCreation,
|
||||||
onCameraStateChange,
|
onCameraStateChange,
|
||||||
onToolPreviewChange
|
onToolPreviewChange,
|
||||||
|
onTransformSessionChange,
|
||||||
|
onTransformCommit,
|
||||||
|
onTransformCancel
|
||||||
}: ViewportCanvasProps) {
|
}: ViewportCanvasProps) {
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const hostRef = useRef<ViewportHost | null>(null);
|
const hostRef = useRef<ViewportHost | null>(null);
|
||||||
@@ -94,6 +103,7 @@ export function ViewportCanvas({
|
|||||||
try {
|
try {
|
||||||
const viewportHost = new ViewportHost();
|
const viewportHost = new ViewportHost();
|
||||||
hostRef.current = viewportHost;
|
hostRef.current = viewportHost;
|
||||||
|
viewportHost.setPanelId(panelId);
|
||||||
viewportHost.mount(container);
|
viewportHost.mount(container);
|
||||||
setViewportMessage(null);
|
setViewportMessage(null);
|
||||||
|
|
||||||
@@ -108,6 +118,10 @@ export function ViewportCanvas({
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
hostRef.current?.setPanelId(panelId);
|
||||||
|
}, [panelId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
hostRef.current?.updateWorld(world);
|
hostRef.current?.updateWorld(world);
|
||||||
}, [world]);
|
}, [world]);
|
||||||
@@ -157,6 +171,18 @@ export function ViewportCanvas({
|
|||||||
hostRef.current?.setCreationCommitHandler(onCommitCreation);
|
hostRef.current?.setCreationCommitHandler(onCommitCreation);
|
||||||
}, [onCommitCreation]);
|
}, [onCommitCreation]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
hostRef.current?.setTransformSessionChangeHandler(onTransformSessionChange);
|
||||||
|
}, [onTransformSessionChange]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
hostRef.current?.setTransformCommitHandler(onTransformCommit);
|
||||||
|
}, [onTransformCommit]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
hostRef.current?.setTransformCancelHandler(onTransformCancel);
|
||||||
|
}, [onTransformCancel]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
hostRef.current?.setToolMode(toolMode);
|
hostRef.current?.setToolMode(toolMode);
|
||||||
}, [toolMode]);
|
}, [toolMode]);
|
||||||
@@ -165,6 +191,10 @@ export function ViewportCanvas({
|
|||||||
hostRef.current?.setCreationPreview(toolMode === "create" && toolPreview.kind === "create" ? toolPreview : null);
|
hostRef.current?.setCreationPreview(toolMode === "create" && toolPreview.kind === "create" ? toolPreview : null);
|
||||||
}, [toolMode, toolPreview]);
|
}, [toolMode, toolPreview]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
hostRef.current?.setTransformSession(transformSession);
|
||||||
|
}, [transformSession]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (focusRequestId === 0) {
|
if (focusRequestId === 0) {
|
||||||
return;
|
return;
|
||||||
@@ -174,8 +204,9 @@ export function ViewportCanvas({
|
|||||||
}, [focusRequestId, focusSelection, sceneDocument]);
|
}, [focusRequestId, focusSelection, sceneDocument]);
|
||||||
|
|
||||||
const previewVisible = toolMode === "create" && toolPreview.kind === "create" && toolPreview.center !== null;
|
const previewVisible = toolMode === "create" && toolPreview.kind === "create" && toolPreview.center !== null;
|
||||||
|
const transformPreviewVisible = transformSession.kind === "active";
|
||||||
const showViewModeOverlay = layoutMode === "quad";
|
const showViewModeOverlay = layoutMode === "quad";
|
||||||
const showOverlay = showViewModeOverlay || previewVisible;
|
const showOverlay = showViewModeOverlay || previewVisible || transformPreviewVisible;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -205,6 +236,13 @@ export function ViewportCanvas({
|
|||||||
Preview: {(toolPreview.center as Vec3).x}, {(toolPreview.center as Vec3).y}, {(toolPreview.center as Vec3).z}
|
Preview: {(toolPreview.center as Vec3).x}, {(toolPreview.center as Vec3).y}, {(toolPreview.center as Vec3).z}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!transformPreviewVisible ? null : (
|
||||||
|
<div className="viewport-canvas__overlay-preview" data-testid={`viewport-transform-preview-${panelId}`}>
|
||||||
|
{transformSession.kind !== "active"
|
||||||
|
? null
|
||||||
|
: `${transformSession.operation}${transformSession.axisConstraint === null ? "" : ` · ${transformSession.axisConstraint.toUpperCase()}`}`}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ 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 { ActiveTransformSession, TransformSessionState } from "../core/transform-session";
|
||||||
import type { ToolMode } from "../core/tool-mode";
|
import type { ToolMode } from "../core/tool-mode";
|
||||||
import type { SceneDocument } from "../document/scene-document";
|
import type { SceneDocument } from "../document/scene-document";
|
||||||
import type { WorldSettings } from "../document/world-settings";
|
import type { WorldSettings } from "../document/world-settings";
|
||||||
@@ -35,6 +36,7 @@ interface ViewportPanelProps {
|
|||||||
selection: EditorSelection;
|
selection: EditorSelection;
|
||||||
toolMode: ToolMode;
|
toolMode: ToolMode;
|
||||||
toolPreview: ViewportToolPreview;
|
toolPreview: ViewportToolPreview;
|
||||||
|
transformSession: TransformSessionState;
|
||||||
cameraState: ViewportPanelCameraState;
|
cameraState: ViewportPanelCameraState;
|
||||||
focusRequestId: number;
|
focusRequestId: number;
|
||||||
focusSelection: EditorSelection;
|
focusSelection: EditorSelection;
|
||||||
@@ -44,6 +46,9 @@ interface ViewportPanelProps {
|
|||||||
onCommitCreation(toolPreview: CreationViewportToolPreview): boolean;
|
onCommitCreation(toolPreview: CreationViewportToolPreview): boolean;
|
||||||
onCameraStateChange(cameraState: ViewportPanelCameraState): void;
|
onCameraStateChange(cameraState: ViewportPanelCameraState): void;
|
||||||
onToolPreviewChange(toolPreview: ViewportToolPreview): void;
|
onToolPreviewChange(toolPreview: ViewportToolPreview): void;
|
||||||
|
onTransformSessionChange(transformSession: TransformSessionState): void;
|
||||||
|
onTransformCommit(transformSession: ActiveTransformSession): void;
|
||||||
|
onTransformCancel(): void;
|
||||||
onSelectionChange(selection: EditorSelection): void;
|
onSelectionChange(selection: EditorSelection): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +67,7 @@ export function ViewportPanel({
|
|||||||
selection,
|
selection,
|
||||||
toolMode,
|
toolMode,
|
||||||
toolPreview,
|
toolPreview,
|
||||||
|
transformSession,
|
||||||
cameraState,
|
cameraState,
|
||||||
focusRequestId,
|
focusRequestId,
|
||||||
focusSelection,
|
focusSelection,
|
||||||
@@ -71,6 +77,9 @@ export function ViewportPanel({
|
|||||||
onCommitCreation,
|
onCommitCreation,
|
||||||
onCameraStateChange,
|
onCameraStateChange,
|
||||||
onToolPreviewChange,
|
onToolPreviewChange,
|
||||||
|
onTransformSessionChange,
|
||||||
|
onTransformCommit,
|
||||||
|
onTransformCancel,
|
||||||
onSelectionChange
|
onSelectionChange
|
||||||
}: ViewportPanelProps) {
|
}: ViewportPanelProps) {
|
||||||
const shouldShow = layoutMode === "quad" || isActive;
|
const shouldShow = layoutMode === "quad" || isActive;
|
||||||
@@ -131,6 +140,7 @@ export function ViewportPanel({
|
|||||||
selection={selection}
|
selection={selection}
|
||||||
toolMode={toolMode}
|
toolMode={toolMode}
|
||||||
toolPreview={toolPreview}
|
toolPreview={toolPreview}
|
||||||
|
transformSession={transformSession}
|
||||||
cameraState={cameraState}
|
cameraState={cameraState}
|
||||||
viewMode={panelState.viewMode}
|
viewMode={panelState.viewMode}
|
||||||
displayMode={panelState.displayMode}
|
displayMode={panelState.displayMode}
|
||||||
@@ -142,6 +152,9 @@ export function ViewportPanel({
|
|||||||
onCommitCreation={onCommitCreation}
|
onCommitCreation={onCommitCreation}
|
||||||
onCameraStateChange={onCameraStateChange}
|
onCameraStateChange={onCameraStateChange}
|
||||||
onToolPreviewChange={onToolPreviewChange}
|
onToolPreviewChange={onToolPreviewChange}
|
||||||
|
onTransformSessionChange={onTransformSessionChange}
|
||||||
|
onTransformCommit={onTransformCommit}
|
||||||
|
onTransformCancel={onTransformCancel}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1034,13 +1034,17 @@ export class ViewportHost {
|
|||||||
this.transformGizmoGroup.add(this.createTranslateHandle("y", session.axisConstraint === "y"));
|
this.transformGizmoGroup.add(this.createTranslateHandle("y", session.axisConstraint === "y"));
|
||||||
this.transformGizmoGroup.add(this.createTranslateHandle("z", session.axisConstraint === "z"));
|
this.transformGizmoGroup.add(this.createTranslateHandle("z", session.axisConstraint === "z"));
|
||||||
} else if (session.operation === "rotate") {
|
} else if (session.operation === "rotate") {
|
||||||
this.transformGizmoGroup.add(this.createRotateHandle("x", effectiveRotationAxis === "x"));
|
for (const axis of ["x", "y", "z"] as const) {
|
||||||
this.transformGizmoGroup.add(this.createRotateHandle("y", effectiveRotationAxis === "y"));
|
if (!supportsTransformAxisConstraint(session, axis)) {
|
||||||
this.transformGizmoGroup.add(this.createRotateHandle("z", effectiveRotationAxis === "z"));
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.transformGizmoGroup.add(this.createRotateHandle(axis, effectiveRotationAxis === axis));
|
||||||
|
}
|
||||||
} else if (session.operation === "scale" && session.target.kind === "modelInstance") {
|
} else if (session.operation === "scale" && session.target.kind === "modelInstance") {
|
||||||
this.transformGizmoGroup.add(this.createScaleHandle("x", session.axisConstraint === "x"));
|
for (const axis of ["x", "y", "z"] as const) {
|
||||||
this.transformGizmoGroup.add(this.createScaleHandle("y", session.axisConstraint === "y"));
|
this.transformGizmoGroup.add(this.createScaleHandle(axis, session.axisConstraint === axis));
|
||||||
this.transformGizmoGroup.add(this.createScaleHandle("z", session.axisConstraint === "z"));
|
}
|
||||||
this.transformGizmoGroup.add(this.createUniformScaleHandle(session.axisConstraint === null));
|
this.transformGizmoGroup.add(this.createUniformScaleHandle(session.axisConstraint === null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2191,7 +2195,38 @@ export class ViewportHost {
|
|||||||
this.advancedRenderingComposer?.setSize(width, height);
|
this.advancedRenderingComposer?.setSize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private pickTransformHandle(event: PointerEvent): { axisConstraint: TransformAxis | null } | null {
|
||||||
|
if (this.currentTransformSession.kind !== "active" || !this.transformGizmoGroup.visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.setPointerFromClientPosition(event.clientX, event.clientY)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.raycaster.setFromCamera(this.pointer, this.getActiveCamera());
|
||||||
|
|
||||||
|
const hits = this.raycaster.intersectObjects(this.transformGizmoGroup.children, true);
|
||||||
|
|
||||||
|
for (const hit of hits) {
|
||||||
|
const axisConstraint = hit.object.userData.transformAxisConstraint;
|
||||||
|
|
||||||
|
if (axisConstraint === null || axisConstraint === "x" || axisConstraint === "y" || axisConstraint === "z") {
|
||||||
|
return {
|
||||||
|
axisConstraint
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private handlePointerDown = (event: PointerEvent) => {
|
private handlePointerDown = (event: PointerEvent) => {
|
||||||
|
this.lastCanvasPointerPosition = {
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
};
|
||||||
|
|
||||||
if (event.button === 1) {
|
if (event.button === 1) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.activeCameraDragPointerId = event.pointerId;
|
this.activeCameraDragPointerId = event.pointerId;
|
||||||
@@ -2207,6 +2242,66 @@ export class ViewportHost {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.currentTransformSession.kind === "active") {
|
||||||
|
if (this.currentTransformSession.sourcePanelId !== this.panelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transformHandle = this.pickTransformHandle(event);
|
||||||
|
|
||||||
|
if (transformHandle !== null) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (
|
||||||
|
transformHandle.axisConstraint !== null &&
|
||||||
|
!supportsTransformAxisConstraint(this.currentTransformSession, transformHandle.axisConstraint)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextSession = this.buildTransformPreviewFromPointer(
|
||||||
|
createTransformSession({
|
||||||
|
source: "gizmo",
|
||||||
|
sourcePanelId: this.panelId,
|
||||||
|
operation: this.currentTransformSession.operation,
|
||||||
|
axisConstraint: transformHandle.axisConstraint,
|
||||||
|
target: this.currentTransformSession.target
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
},
|
||||||
|
transformHandle.axisConstraint
|
||||||
|
);
|
||||||
|
|
||||||
|
this.currentTransformSession = nextSession;
|
||||||
|
this.applyTransformPreview();
|
||||||
|
this.syncTransformGizmo();
|
||||||
|
this.transformSessionChangeHandler?.(nextSession);
|
||||||
|
this.activeTransformDrag = {
|
||||||
|
pointerId: event.pointerId,
|
||||||
|
sessionId: nextSession.id,
|
||||||
|
axisConstraint: transformHandle.axisConstraint,
|
||||||
|
initialClientPosition: {
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.renderer.domElement.setPointerCapture(event.pointerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.currentTransformSession.source !== "gizmo" || this.currentTransformSession.sourcePanelId === this.panelId) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.transformCommitHandler?.(this.currentTransformSession);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.toolMode === "create" && this.creationPreview !== null) {
|
if (this.toolMode === "create" && this.creationPreview !== null) {
|
||||||
const previewCenter = this.getCreationPreviewCenter(event, this.creationPreview.target);
|
const previewCenter = this.getCreationPreviewCenter(event, this.creationPreview.target);
|
||||||
const nextCreationPreview = {
|
const nextCreationPreview = {
|
||||||
@@ -2281,8 +2376,7 @@ export class ViewportHost {
|
|||||||
} else if (typeof brushId === "string") {
|
} else if (typeof brushId === "string") {
|
||||||
const faceMaterialIndex = hit.face?.materialIndex;
|
const faceMaterialIndex = hit.face?.materialIndex;
|
||||||
const faceId = typeof faceMaterialIndex === "number" ? BOX_FACE_IDS[faceMaterialIndex] ?? null : null;
|
const faceId = typeof faceMaterialIndex === "number" ? BOX_FACE_IDS[faceMaterialIndex] ?? null : null;
|
||||||
// In face-edit mode each face is a distinct candidate; in brush mode collapse to brush.
|
key = event.altKey && faceId !== null ? `brushFace:${brushId}:${faceId}` : `brush:${brushId}`;
|
||||||
key = faceId !== null ? `brushFace:${brushId}:${faceId}` : `brush:${brushId}`;
|
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2343,7 +2437,7 @@ export class ViewportHost {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (faceId !== null) {
|
if (event.altKey && faceId !== null) {
|
||||||
this.brushSelectionChangeHandler?.({ kind: "brushFace", brushId, faceId });
|
this.brushSelectionChangeHandler?.({ kind: "brushFace", brushId, faceId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2352,6 +2446,11 @@ export class ViewportHost {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private handlePointerMove = (event: PointerEvent) => {
|
private handlePointerMove = (event: PointerEvent) => {
|
||||||
|
this.lastCanvasPointerPosition = {
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
};
|
||||||
|
|
||||||
if (this.activeCameraDragPointerId === event.pointerId && this.lastCameraDragClientPosition !== null) {
|
if (this.activeCameraDragPointerId === event.pointerId && this.lastCameraDragClientPosition !== null) {
|
||||||
const deltaX = event.clientX - this.lastCameraDragClientPosition.x;
|
const deltaX = event.clientX - this.lastCameraDragClientPosition.x;
|
||||||
const deltaY = event.clientY - this.lastCameraDragClientPosition.y;
|
const deltaY = event.clientY - this.lastCameraDragClientPosition.y;
|
||||||
@@ -2370,6 +2469,56 @@ export class ViewportHost {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.activeTransformDrag !== null &&
|
||||||
|
this.activeTransformDrag.pointerId === event.pointerId &&
|
||||||
|
this.currentTransformSession.kind === "active" &&
|
||||||
|
this.currentTransformSession.id === this.activeTransformDrag.sessionId
|
||||||
|
) {
|
||||||
|
const nextSession = this.buildTransformPreviewFromPointer(
|
||||||
|
this.currentTransformSession,
|
||||||
|
this.activeTransformDrag.initialClientPosition,
|
||||||
|
{
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
},
|
||||||
|
this.activeTransformDrag.axisConstraint
|
||||||
|
);
|
||||||
|
|
||||||
|
this.currentTransformSession = nextSession;
|
||||||
|
this.applyTransformPreview();
|
||||||
|
this.syncTransformGizmo();
|
||||||
|
this.transformSessionChangeHandler?.(nextSession);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.currentTransformSession.kind === "active" &&
|
||||||
|
this.currentTransformSession.sourcePanelId === this.panelId &&
|
||||||
|
this.currentTransformSession.source !== "gizmo" &&
|
||||||
|
this.keyboardTransformPointerOrigin !== null &&
|
||||||
|
this.keyboardTransformPointerOrigin.sessionId === this.currentTransformSession.id
|
||||||
|
) {
|
||||||
|
const nextSession = this.buildTransformPreviewFromPointer(
|
||||||
|
this.currentTransformSession,
|
||||||
|
{
|
||||||
|
x: this.keyboardTransformPointerOrigin.clientX,
|
||||||
|
y: this.keyboardTransformPointerOrigin.clientY
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY
|
||||||
|
},
|
||||||
|
this.currentTransformSession.axisConstraint
|
||||||
|
);
|
||||||
|
|
||||||
|
this.currentTransformSession = nextSession;
|
||||||
|
this.applyTransformPreview();
|
||||||
|
this.syncTransformGizmo();
|
||||||
|
this.transformSessionChangeHandler?.(nextSession);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.toolMode !== "create" || this.creationPreview === null) {
|
if (this.toolMode !== "create" || this.creationPreview === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2385,6 +2534,25 @@ export class ViewportHost {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private handlePointerUp = (event: PointerEvent) => {
|
private handlePointerUp = (event: PointerEvent) => {
|
||||||
|
if (this.activeTransformDrag !== null && this.activeTransformDrag.pointerId === event.pointerId) {
|
||||||
|
if (this.renderer.domElement.hasPointerCapture(event.pointerId)) {
|
||||||
|
this.renderer.domElement.releasePointerCapture(event.pointerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const completedSession = this.currentTransformSession.kind === "active" ? this.currentTransformSession : null;
|
||||||
|
this.activeTransformDrag = null;
|
||||||
|
|
||||||
|
if (completedSession !== null) {
|
||||||
|
if (event.type === "pointercancel") {
|
||||||
|
this.transformCancelHandler?.();
|
||||||
|
} else {
|
||||||
|
this.transformCommitHandler?.(completedSession);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.activeCameraDragPointerId !== event.pointerId) {
|
if (this.activeCameraDragPointerId !== event.pointerId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2799,6 +2967,7 @@ export class ViewportHost {
|
|||||||
|
|
||||||
private render = () => {
|
private render = () => {
|
||||||
this.animationFrame = window.requestAnimationFrame(this.render);
|
this.animationFrame = window.requestAnimationFrame(this.render);
|
||||||
|
this.updateTransformGizmoPose();
|
||||||
|
|
||||||
if (this.advancedRenderingComposer !== null) {
|
if (this.advancedRenderingComposer !== null) {
|
||||||
this.advancedRenderingComposer.render();
|
this.advancedRenderingComposer.render();
|
||||||
|
|||||||
Reference in New Issue
Block a user