From 9054e963d2f52fd27cbc6a1a892c4014b949e212 Mon Sep 17 00:00:00 2001 From: Tanish Manku Date: Wed, 7 May 2025 16:16:39 -0700 Subject: [PATCH] Update PageEditor to use new 3D PromptBox --- .../app/src/pages/PageEnigma/PageEditor.tsx | 337 ++++++++++++++---- 1 file changed, 266 insertions(+), 71 deletions(-) diff --git a/frontend/apps/editor3d/app/src/pages/PageEnigma/PageEditor.tsx b/frontend/apps/editor3d/app/src/pages/PageEnigma/PageEditor.tsx index 7d0362b66f..eba1f43af9 100644 --- a/frontend/apps/editor3d/app/src/pages/PageEnigma/PageEditor.tsx +++ b/frontend/apps/editor3d/app/src/pages/PageEnigma/PageEditor.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useContext, useEffect } from "react"; import { invoke } from "@tauri-apps/api/core"; import { useSignals } from "@preact/signals-react/runtime"; import { LoadingDots, TopBar } from "~/components"; @@ -16,12 +16,17 @@ import { editorLoader, cameraAspectRatio, outlinerIsShowing, + disableHotkeyInput, + enableHotkeyInput, + gridVisibility, + setGridVisibility, } from "~/pages/PageEnigma/signals"; import { EditorCanvas } from "./comps/EngineCanvases"; import { SceneContainer } from "./comps/SceneContainer"; import { Outliner } from "./comps/Outliner"; import { CameraAspectRatio } from "./enums"; -import { PromptBox } from "./comps/PromptBox"; +import { PromptBox3D } from "@storyteller/ui-promptbox"; +import { PopoverItem } from "@storyteller/ui-popover"; import { OnboardingHelper } from "./comps/OnboardingHelper"; import { IsDesktopApp } from "@storyteller/tauri-utils"; import { FocalLengthDisplay } from "./comps/FocalLengthDisplay/FocalLengthDisplay"; @@ -29,10 +34,17 @@ import { DemoModal } from "@storyteller/ui-demo-modal"; import { appTabId, setAppTabId } from "~/signals/appTab"; import { KonvaCanvasContainer } from "../Page2d/KonvaCanvasContainer"; import { KonvaRootComponent } from "../Page2d/KonvaRootComponent"; +import { addCamera, cameras, deleteCamera, focalLengthDragging, selectedCameraId, updateCamera } from "./signals/camera"; +import { isPromptBoxFocused } from "./signals/promptBox"; +import { uploadImage } from "~/components/reusable/UploadModalMedia/uploadImage"; +import { EngineContext } from "./contexts/EngineContext"; +import Queue, { QueueNames } from "./Queue"; +import { toEngineActions } from "./Queue/toEngineActions"; +import { UnionedDataTypes } from "./Queue/Queue"; export const PageEditor = () => { useSignals(); - + const handleOverlayClick = (event: React.MouseEvent) => { event.stopPropagation(); }; @@ -75,93 +87,276 @@ export const PageEditor = () => { return scaleHeight; }; + // These are callbacks required by promptbox + const editorEngine = useContext(EngineContext); + const handleCameraSelect = (selectedItem: PopoverItem) => { + const selectedCamera = cameras.value.find( + (cam) => cam.label === selectedItem.label, + ); + if (selectedCamera && editorEngine) { + selectedCameraId.value = selectedCamera.id; + + // Show focal length display temporarily + // TODO: Rename dragging to visible - BFlat + focalLengthDragging.value = { + isDragging: true, + focalLength: selectedCamera.focalLength, + }; + setTimeout(() => { + focalLengthDragging.value = { + isDragging: false, + focalLength: selectedCamera.focalLength, + }; + }, 1500); + + // Update the main camera to match the selected camera's properties + if (editorEngine.camera) { + // First update position and lookAt + editorEngine.camera.position.set( + selectedCamera.position.x, + selectedCamera.position.y, + selectedCamera.position.z, + ); + editorEngine.camera.lookAt( + selectedCamera.lookAt.x, + selectedCamera.lookAt.y, + selectedCamera.lookAt.z, + ); + + // Update FOV + editorEngine.camera.fov = editorEngine.focalLengthToFov( + selectedCamera.focalLength, + ); + editorEngine.camera.updateProjectionMatrix(); + + // Reset and update camera controls + if (editorEngine.cameraViewControls) { + editorEngine.cameraViewControls.reset(); + editorEngine.cameraViewControls.update(0); + } + + // Force a render to update the view + editorEngine.renderScene(); + + // Queue an update to ensure the engine processes the camera change + // Queue.publish({ + // queueName: QueueNames.TO_ENGINE, + // action: toEngineActions.CAMERA_CHANGED, + // data: selectedCamera, + // }); + } + + // Force update camera properties in the state + updateCamera(selectedCamera.id, { + focalLength: selectedCamera.focalLength, + position: selectedCamera.position, + rotation: selectedCamera.rotation, + lookAt: selectedCamera.lookAt, + }); + } + }; + + const handleAddCamera = () => { + // Check if we've reached the maximum number of cameras + if (cameras.value.length >= 6) { + console.warn("Maximum number of cameras (6) reached"); + return; + } + + const newIndex = cameras.value.length + 1; + const newId = `cam${newIndex}`; + + // This is for generating random orbital position for the new camera using spherical coordinates + const radius = Math.random() * 5 + 7; // Distance from center: 7 to 12 units + const theta = Math.random() * Math.PI * 2; // Azimuthal angle: 0 to 2π + const phi = Math.PI / 3 + (Math.random() * Math.PI) / 6; // Polar angle: π/3 to π/2 (60° to 90° from horizontal) + + // Convert spherical coordinates to Cartesian coordinates + const randomX = radius * Math.sin(phi) * Math.cos(theta); + const randomY = Math.abs(radius * Math.cos(phi)) + 2; // Ensure Y is positive and at least 2 units up + const randomZ = radius * Math.sin(phi) * Math.sin(theta); + + addCamera({ + id: newId, + label: `Camera ${newIndex}`, + focalLength: 24, + position: { + x: randomX, + y: randomY, + z: randomZ, + }, + rotation: { x: 0, y: 0, z: 0 }, + lookAt: { x: 0, y: 0, z: 0 }, + }); + + // Switch to the newly created camera + selectedCameraId.value = newId; + + // Update the engine camera to match the new camera's properties + if (editorEngine && editorEngine.camera) { + editorEngine.camera.position.set(randomX, randomY, randomZ); + editorEngine.camera.lookAt(0, 0, 0); + editorEngine.camera.fov = editorEngine.focalLengthToFov(24); + editorEngine.camera.updateProjectionMatrix(); + + // Reset and update camera controls + if (editorEngine.cameraViewControls) { + editorEngine.cameraViewControls.reset(); + editorEngine.cameraViewControls.update(0); + } + + // Force a render to update the view + editorEngine.renderScene(); + + // Queue.publish({ + // queueName: QueueNames.TO_ENGINE, + // action: toEngineActions.CAMERA_CHANGED, + // data: { + // id: newId, + // label: `Camera ${newIndex}`, + // focalLength: 24, + // position: { x: randomX, y: randomY, z: randomZ }, + // rotation: { x: 0, y: 0, z: 0 }, + // lookAt: { x: 0, y: 0, z: 0 }, + // }, + // }); + } + }; + + const handleCameraNameChange = (id: string, newName: string) => { + updateCamera(id, { label: newName }); + }; + + const handleCameraFocalLengthChange = (id: string, value: number) => { + const camera = cameras.value.find((cam) => cam.id === id); + if (camera) { + updateCamera(id, { focalLength: value }); + } + }; + + const onAspectRatioSelect = (newRatio: UnionedDataTypes) => { + // Publish the change to the engine + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.CHANGE_CAMERA_ASPECT_RATIO, + data: newRatio, + }); + } + const ContentFor3D = () => { return <> -
- {/* Engine section/side panel */}
-
- - - - + {/* Engine section/side panel */} +
+
+ + + + - {/* Focal Length Display */} - + {/* Focal Length Display */} + - {/* Pose Mode Selector */} - + {/* Pose Mode Selector */} + - {/* Top controls */} -
-
- - -
-
- - {/* Bottom controls */} -
+ {/* Top controls */}
- - +
+ + +
- + {/* Bottom controls */} +
+
+ + +
+ + +
+ + { + if (!editorEngine) { + return; + } + + editorEngine!.positive_prompt = prompt + }} + snapshotCurrentFrame={ + editorEngine?.snapShotOfCurrentFrame + } + /> + +
- - - -
-
- { - if (IsDesktopApp()) { - await invoke("open_sora_login_command"); - } else { - console.error("This is not the Desktop app."); - } - }} - /> + { + if (IsDesktopApp()) { + await invoke("open_sora_login_command"); + } else { + console.error("This is not the Desktop app."); + } + }} + /> } const ContentFor2D = () => { return - + ; };