mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-07 10:31:46 +00:00
Add remount logic to event listeners for 3D
This commit is contained in:
1 parent
cf235ecbe8
commit
165078ddb4
7 files changed
+159
-58
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import {
|
||||
faChevronLeft,
|
||||
faGear,
|
||||
@@ -18,6 +18,7 @@ import { TabSelector, TabItem } from "@storyteller/ui-tab-selector";
|
||||
import { Signal } from "@preact/signals-react";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { setLogoutStates } from "~/signals/authentication/utilities";
|
||||
import { EngineContext } from "~/pages/PageEnigma/contexts/EngineContext";
|
||||
|
||||
function isEditorPath(path: string) {
|
||||
if (path === "/") return true;
|
||||
@@ -29,6 +30,7 @@ interface Props {
|
||||
pageName: string;
|
||||
appTabIdSignal: Signal<string>;
|
||||
setAppTabId: (id: string) => void;
|
||||
is3DInitSignal: Signal<boolean>;
|
||||
}
|
||||
|
||||
const appTabs: TabItem[] = [
|
||||
@@ -36,7 +38,7 @@ const appTabs: TabItem[] = [
|
||||
{ id: "2D", label: "2D" },
|
||||
];
|
||||
|
||||
export const TopBar = ({ pageName, appTabIdSignal, setAppTabId }: Props) => {
|
||||
export const TopBar = ({ pageName, appTabIdSignal, setAppTabId, is3DInitSignal }: Props) => {
|
||||
useSignals();
|
||||
|
||||
const currentLocation = getCurrentLocationWithoutParams(
|
||||
@@ -47,6 +49,22 @@ export const TopBar = ({ pageName, appTabIdSignal, setAppTabId }: Props) => {
|
||||
const [activeLibraryTab, setActiveLibraryTab] = useState("my-media");
|
||||
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
||||
|
||||
const engine3D = useContext(EngineContext);
|
||||
const handleTabChange = (tabId: string) => {
|
||||
if (appTabIdSignal.peek() == "3D") {
|
||||
engine3D?.unmountEngine();
|
||||
}
|
||||
setAppTabId(tabId);
|
||||
}
|
||||
|
||||
const currentAppTabId = appTabIdSignal.value;
|
||||
const is3DInit = is3DInitSignal.value;
|
||||
useEffect(() => {
|
||||
if (currentAppTabId == "3D" && is3DInit) {
|
||||
engine3D?.remountEngine();
|
||||
}
|
||||
}, [currentAppTabId, engine3D, is3DInit]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="fixed left-0 top-0 z-[60] w-full border-b border-white/5 bg-ui-background">
|
||||
@@ -68,13 +86,13 @@ export const TopBar = ({ pageName, appTabIdSignal, setAppTabId }: Props) => {
|
||||
Back to Editor
|
||||
</ButtonLink>
|
||||
)}
|
||||
{/* <TabSelector
|
||||
<TabSelector
|
||||
tabs={appTabs}
|
||||
activeTab={appTabIdSignal.value}
|
||||
disabled={false}
|
||||
onTabChange={(tabId: string) => setAppTabId(tabId)}
|
||||
onTabChange={handleTabChange}
|
||||
className="w-fit"
|
||||
/> */}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center gap-2 font-medium">
|
||||
|
||||
@@ -57,6 +57,7 @@ import { BufferType, EngineFrameBuffers } from "./VideoProcessor/engine_buffer";
|
||||
import Stats from "three/examples/jsm/libs/stats.module.js";
|
||||
import { CharacterAnimationEngine } from "./Engines/CharacterAnimationEngine";
|
||||
import { cameras, selectedCameraId } from "~/pages/PageEnigma/signals/camera";
|
||||
import { is3DEditorInitialized, setIs3DEditorInitialized } from "~/signals/appTab";
|
||||
|
||||
export type EditorInitializeConfig = {
|
||||
sceneToken: string;
|
||||
@@ -200,6 +201,7 @@ class Editor {
|
||||
// Allows us to cancel the queued render
|
||||
private renderEventToken: number;
|
||||
private shouldRender: boolean;
|
||||
private isMounted: boolean;
|
||||
|
||||
constructor() {
|
||||
this.processingHasFailed = false;
|
||||
@@ -261,7 +263,7 @@ class Editor {
|
||||
this.last_selected_sum = 0;
|
||||
this.selectedCanvas = false;
|
||||
this.renderEventToken = -1;
|
||||
this.shouldRender = true;
|
||||
this.shouldRender = false;
|
||||
// Audio Engine Test.
|
||||
|
||||
this.render_camera_aspect_ratio = CameraAspectRatio.HORIZONTAL_3_2;
|
||||
@@ -601,13 +603,6 @@ class Editor {
|
||||
|
||||
this.cam_obj = this.activeScene.get_object_by_name(this.camera_name);
|
||||
|
||||
if (this.outliner_feature_flag) {
|
||||
const result = this.sceneManager?.render_outliner(
|
||||
this.timeline.characters,
|
||||
);
|
||||
if (result) outlinerState.items.value = result.items;
|
||||
}
|
||||
|
||||
this.mouse_controls = new MouseControls(
|
||||
this.camera,
|
||||
this.get_camera_person_mode.bind(this),
|
||||
@@ -648,10 +643,19 @@ class Editor {
|
||||
this.mouse_controls.sceneManager = this.sceneManager;
|
||||
}
|
||||
|
||||
// Creates the main update loop.
|
||||
//this.renderer.setAnimationLoop(this.updateLoop.bind(this));
|
||||
if (this.outliner_feature_flag) {
|
||||
const result = this.sceneManager?.render_outliner(
|
||||
this.timeline.characters,
|
||||
);
|
||||
if (result) outlinerState.items.value = result.items;
|
||||
}
|
||||
|
||||
this.startRenderLoop();
|
||||
// Attach freecam state controller
|
||||
this.mouseOverEventHandler = this.mouseOverEventHandler.bind(this);
|
||||
|
||||
// This will enable all event and render loops
|
||||
// We'll disable it here so the UI events can control is manually
|
||||
// this.remountEngine();
|
||||
|
||||
if (!this.utils.isEmpty(sceneToken)) {
|
||||
this.loadScene(sceneToken);
|
||||
@@ -664,24 +668,6 @@ class Editor {
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("mouseover", (event) => {
|
||||
if (this.cameraViewControls) {
|
||||
if (
|
||||
event.target instanceof HTMLCanvasElement ||
|
||||
(event.target as HTMLElement).id == "letterbox"
|
||||
) {
|
||||
this.cameraViewControls.enabled = true;
|
||||
this.selectedCanvas = true;
|
||||
this.focused = true;
|
||||
} else {
|
||||
this.cameraViewControls.reset();
|
||||
this.focused = false;
|
||||
this.cameraViewControls.enabled = false;
|
||||
this.selectedCanvas = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this._configurePostProcessingRaw();
|
||||
|
||||
loadingBarData.value = {
|
||||
@@ -689,6 +675,8 @@ class Editor {
|
||||
progress: 100,
|
||||
};
|
||||
loadingBarIsShowing.value = false;
|
||||
|
||||
setIs3DEditorInitialized(true);
|
||||
}
|
||||
|
||||
public isMovable(): boolean {
|
||||
@@ -699,6 +687,32 @@ class Editor {
|
||||
document.body.appendChild(this.stats.dom);
|
||||
}
|
||||
|
||||
private mouseOverEventHandler(event: MouseEvent) {
|
||||
if (this.cameraViewControls) {
|
||||
if (
|
||||
event.target instanceof HTMLCanvasElement ||
|
||||
(event.target as HTMLElement).id == "letterbox"
|
||||
) {
|
||||
this.cameraViewControls.enabled = true;
|
||||
this.selectedCanvas = true;
|
||||
this.focused = true;
|
||||
} else {
|
||||
this.cameraViewControls.reset();
|
||||
this.focused = false;
|
||||
this.cameraViewControls.enabled = false;
|
||||
this.selectedCanvas = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enableFreeCamControls() {
|
||||
document.addEventListener("mouseover", this.mouseOverEventHandler);
|
||||
}
|
||||
|
||||
public disableFreeCamControls() {
|
||||
document.removeEventListener("mouseover", this.mouseOverEventHandler);
|
||||
}
|
||||
|
||||
// Captures the scene without the grid
|
||||
public snapShotOfCurrentFrame(shouldDownload: boolean = true) {
|
||||
if (!this.renderer?.domElement || !this.camera) {
|
||||
@@ -1404,7 +1418,9 @@ class Editor {
|
||||
startRenderLoop() {
|
||||
if (this.shouldRender) {
|
||||
console.warn("Render flag is already true");
|
||||
return;
|
||||
}
|
||||
|
||||
this.shouldRender = true;
|
||||
this.updateLoop();
|
||||
}
|
||||
@@ -1418,6 +1434,30 @@ class Editor {
|
||||
}
|
||||
}
|
||||
|
||||
remountEngine() {
|
||||
if (!is3DEditorInitialized.peek()) {
|
||||
console.log("3D mount: Wait for initialization");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isMounted) {
|
||||
console.log("3D already mounted, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
this.startRenderLoop();
|
||||
this.sceneManager?.attachEventListeners();
|
||||
this.enableFreeCamControls();
|
||||
this.cameraViewControls?.attachEventListeners();
|
||||
}
|
||||
|
||||
unmountEngine() {
|
||||
this.stopRenderLoop();
|
||||
this.sceneManager?.detachEventListeners();
|
||||
this.disableFreeCamControls();
|
||||
this.cameraViewControls?.detachEventListeners();
|
||||
}
|
||||
|
||||
change_mode(type: "translate" | "rotate" | "scale") {
|
||||
if (this.control == undefined) {
|
||||
return;
|
||||
|
||||
@@ -83,6 +83,10 @@ class FreeCam extends EventDispatcher {
|
||||
|
||||
this.keydown = this.keydown.bind(this);
|
||||
this.keyup = this.keyup.bind(this);
|
||||
this.mousedown = this.mousedown.bind(this);
|
||||
this.mouseup = this.mouseup.bind(this);
|
||||
this.mousemove = this.mousemove.bind(this);
|
||||
this.mousewheel = this.mousewheel.bind(this);
|
||||
this.reset = this.reset.bind(this);
|
||||
this.update = this.update.bind(this);
|
||||
this.updateMovementVector = this.updateMovementVector.bind(this);
|
||||
@@ -94,18 +98,28 @@ class FreeCam extends EventDispatcher {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", this.keydown.bind(this));
|
||||
window.addEventListener("keyup", this.keyup.bind(this));
|
||||
|
||||
window.addEventListener("mousedown", this.mousedown.bind(this));
|
||||
window.addEventListener("mouseup", this.mouseup.bind(this));
|
||||
window.addEventListener("mousemove", this.mousemove.bind(this));
|
||||
window.addEventListener("wheel", this.mousewheel.bind(this));
|
||||
|
||||
this.updateMovementVector();
|
||||
this.updateRotationVector();
|
||||
}
|
||||
|
||||
attachEventListeners() {
|
||||
window.addEventListener("keydown", this.keydown);
|
||||
window.addEventListener("keyup", this.keyup);
|
||||
window.addEventListener("mousedown", this.mousedown);
|
||||
window.addEventListener("mouseup", this.mouseup);
|
||||
window.addEventListener("mousemove", this.mousemove);
|
||||
window.addEventListener("wheel", this.mousewheel);
|
||||
}
|
||||
|
||||
detachEventListeners() {
|
||||
window.removeEventListener("keydown", this.keydown);
|
||||
window.removeEventListener("keyup", this.keyup);
|
||||
window.removeEventListener("mousedown", this.mousedown);
|
||||
window.removeEventListener("mouseup", this.mouseup);
|
||||
window.removeEventListener("mousemove", this.mousemove);
|
||||
window.removeEventListener("wheel", this.mousewheel);
|
||||
}
|
||||
|
||||
keydown(event: KeyboardEvent) {
|
||||
if (!this.enabled || isPromptBoxFocused.value) {
|
||||
return;
|
||||
|
||||
@@ -65,6 +65,7 @@ export class SceneManager implements SceneManagerAPI {
|
||||
private lastSceneState: SceneState;
|
||||
private copiedObject: THREE.Object3D | undefined;
|
||||
private is_character: Function;
|
||||
private devMode: boolean;
|
||||
|
||||
constructor(
|
||||
version: number,
|
||||
@@ -80,14 +81,35 @@ export class SceneManager implements SceneManagerAPI {
|
||||
this.lastSceneState = this.getSceneState();
|
||||
this.updateOutliner = updateOutliner;
|
||||
this.is_character = is_character;
|
||||
this.devMode = devMode;
|
||||
|
||||
if (devMode) {
|
||||
window.addEventListener("mousemove", this.onMouseMove.bind(this), false);
|
||||
window.addEventListener("click", this.onMouseClick.bind(this), false);
|
||||
window.addEventListener("keydown", this.onKeyDown.bind(this), false);
|
||||
window.addEventListener("mousedown", this.onMouseDown.bind(this), false);
|
||||
window.addEventListener("mouseup", this.onMouseUp.bind(this), false);
|
||||
this.onMouseMove = this.onMouseMove.bind(this);
|
||||
this.onMouseClick = this.onMouseClick.bind(this);
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
this.onMouseDown = this.onMouseDown.bind(this);
|
||||
this.onMouseUp = this.onMouseUp.bind(this);
|
||||
}
|
||||
|
||||
public attachEventListeners() {
|
||||
if (!this.devMode) {
|
||||
return;
|
||||
}
|
||||
window.addEventListener("mousemove", this.onMouseMove, false);
|
||||
window.addEventListener("click", this.onMouseClick, false);
|
||||
window.addEventListener("keydown", this.onKeyDown, false);
|
||||
window.addEventListener("mousedown", this.onMouseDown, false);
|
||||
window.addEventListener("mouseup", this.onMouseUp, false);
|
||||
}
|
||||
|
||||
public detachEventListeners() {
|
||||
if (!this.devMode) {
|
||||
return;
|
||||
}
|
||||
window.removeEventListener("mousemove", this.onMouseMove, false);
|
||||
window.removeEventListener("click", this.onMouseClick, false);
|
||||
window.removeEventListener("keydown", this.onKeyDown, false);
|
||||
window.removeEventListener("mousedown", this.onMouseDown, false);
|
||||
window.removeEventListener("mouseup", this.onMouseUp, false);
|
||||
}
|
||||
|
||||
public async undo() {
|
||||
@@ -121,7 +143,7 @@ export class SceneManager implements SceneManagerAPI {
|
||||
name: string,
|
||||
position: THREE.Vector3,
|
||||
): Promise<THREE.Object3D<THREE.Object3DEventMap>> {
|
||||
if (media_token.includes("SKY::")){
|
||||
if (media_token.includes("SKY::")) {
|
||||
const token = media_token.replace("SKY::", "");
|
||||
this.scene.updateSkybox(token);
|
||||
}
|
||||
@@ -243,16 +265,16 @@ export class SceneManager implements SceneManagerAPI {
|
||||
}
|
||||
|
||||
public async copy() {
|
||||
// TODO MAKE BETTER FIX: Temp disables copy and paste of characters.
|
||||
// TODO MAKE BETTER FIX: Temp disables copy and paste of characters.
|
||||
const object = this.mouse_controls.selected?.at(0)
|
||||
if(object !== undefined ){
|
||||
if(this.is_character(object.uuid) === false)
|
||||
this.copiedObject = object;
|
||||
if (object !== undefined) {
|
||||
if (this.is_character(object.uuid) === false)
|
||||
this.copiedObject = object;
|
||||
}
|
||||
}
|
||||
|
||||
public async paste() {
|
||||
if(this.copiedObject && this.copiedObject.name != "::CAM::") {
|
||||
if (this.copiedObject && this.copiedObject.name != "::CAM::") {
|
||||
const userdata = this.copiedObject.userData;
|
||||
const position = this.copiedObject.position.clone();
|
||||
const rotation = this.copiedObject.rotation.clone();
|
||||
@@ -264,7 +286,7 @@ export class SceneManager implements SceneManagerAPI {
|
||||
|
||||
const obj = await this.create(media_id, name, position);
|
||||
this.scene.setColor(obj.uuid, color);
|
||||
obj.position.copy(position.add(new THREE.Vector3(0.5,0.0,0.5)));
|
||||
obj.position.copy(position.add(new THREE.Vector3(0.5, 0.0, 0.5)));
|
||||
obj.rotation.copy(rotation);
|
||||
obj.scale.copy(scale);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import { PromptBox3D } from "@storyteller/ui-promptbox";
|
||||
import { PopoverItem } from "@storyteller/ui-popover";
|
||||
import { OnboardingHelper } from "./comps/OnboardingHelper";
|
||||
import { FocalLengthDisplay } from "./comps/FocalLengthDisplay/FocalLengthDisplay";
|
||||
import { appTabId, setAppTabId } from "~/signals/appTab";
|
||||
import { appTabId, is3DEditorInitialized, setAppTabId } from "~/signals/appTab";
|
||||
import { KonvaCanvasContainer } from "../Page2d/KonvaCanvasContainer";
|
||||
import { KonvaRootComponent } from "../Page2d/KonvaRootComponent";
|
||||
import {
|
||||
@@ -265,6 +265,7 @@ export const PageEditor = () => {
|
||||
pageName="Edit Scene"
|
||||
appTabIdSignal={appTabId}
|
||||
setAppTabId={setAppTabId}
|
||||
is3DInitSignal={is3DEditorInitialized}
|
||||
/>
|
||||
|
||||
{appTabId.value === "3D" ? (
|
||||
@@ -366,7 +367,7 @@ export const PageEditor = () => {
|
||||
)}
|
||||
|
||||
<LoginModal
|
||||
onClose={() => {}}
|
||||
onClose={() => { }}
|
||||
videoSrc2D="/resources/videos/artcraft-canvas-demo.mp4"
|
||||
videoSrc3D="/resources/videos/artcraft-3d-demo.mp4"
|
||||
openAiLogo="/resources/images/openai-logo.png"
|
||||
|
||||
@@ -18,7 +18,7 @@ import { StyleSelection } from "~/pages/PageEnigma/comps/StyleSelection";
|
||||
import { StyleMoreOptions } from "~/pages/PageEnigma/comps/StyleMoreOptions/StyleMoreOptions";
|
||||
import Queue, { QueueNames } from "~/pages/PageEnigma/Queue";
|
||||
import { toTimelineActions } from "~/pages/PageEnigma/Queue/toTimelineActions";
|
||||
import { appTabId, setAppTabId } from "~/signals/appTab";
|
||||
import { appTabId, is3DEditorInitialized, setAppTabId } from "~/signals/appTab";
|
||||
|
||||
export const PageStyling = () => {
|
||||
useSignals();
|
||||
@@ -64,6 +64,7 @@ export const PageStyling = () => {
|
||||
pageName="Stylization"
|
||||
appTabIdSignal={appTabId}
|
||||
setAppTabId={setAppTabId}
|
||||
is3DInitSignal={is3DEditorInitialized}
|
||||
/>
|
||||
<div className="mt-4 flex flex-col items-center gap-6">
|
||||
<PreviewImages />
|
||||
|
||||
@@ -10,3 +10,8 @@ export const setAppTabId = (newId: string) => {
|
||||
|
||||
appTabId.value = newId;
|
||||
};
|
||||
|
||||
export const is3DEditorInitialized = signal(false);
|
||||
export const setIs3DEditorInitialized = (isInitialized: boolean) => {
|
||||
is3DEditorInitialized.value = isInitialized;
|
||||
}
|
||||
Reference in new issue
Block a user