Some code cleanup, get keyframes working

This commit is contained in:
FromTheLOLAshes committed 2024-04-01 14:58:47 +07:00
1 parent 9347782812
commit 565280f2df
16 files changed
+653 -563

No files matched your search

+12 -10
View File
@@ -1,11 +1,11 @@
import { twMerge } from "tailwind-merge";
import { H4 } from ".";
import { ArtStyle } from "~/pages/PageEnigma/js/api_manager";
interface ItemPickerProps extends React.ImgHTMLAttributes<HTMLImageElement> {
label: string
label: ArtStyle;
selected: boolean;
onSelected : (val:string)=>void;
onSelected: (picked: ArtStyle) => void;
}
export const ItemPicker = ({
@@ -13,20 +13,22 @@ export const ItemPicker = ({
selected = false,
onSelected,
...imgProps
}:ItemPickerProps) => {
const handleSelected = ()=>{
}: ItemPickerProps) => {
const handleSelected = () => {
onSelected(label);
};
return (
<div
className={twMerge("relative border-2 rounded-lg overflow-hidden cursor-pointer transition-colors ease-in-out", selected ? "border-brand-primary" : "border-ui-border")}
className={twMerge(
"relative cursor-pointer overflow-hidden rounded-lg border-2 transition-colors ease-in-out",
selected ? "border-brand-primary" : "border-ui-border",
)}
onClick={handleSelected}
>
<img className="aspect-square min-w-20" {...imgProps} />
<div className="bg-gradient-to-t from-gray-700 absolute top-0 left-0 w-full h-full"/>
<div className="absolute left-0 top-0 h-full w-full bg-gradient-to-t from-gray-700" />
<H4 className="absolute bottom-0 left-2 drop-shadow-md">{label}</H4>
</div>
)
}
);
};
+9 -1
View File
@@ -1,10 +1,18 @@
import { PageEnigmaComponent } from "./PageEnigmaComponent";
import { TrackProvider } from "~/pages/PageEnigma/contexts/TrackContext/TrackProvider";
import { AppUIProvider } from "~/pages/PageEnigma/contexts/AppUiContext";
import { EngineProvider } from "~/pages/PageEnigma/contexts/EngineProvider";
import { DragComponent } from "~/pages/PageEnigma/comps/DragComponent/DragComponent";
export const PageEnigma = () => {
return (
<TrackProvider>
<PageEnigmaComponent />
<AppUIProvider>
<EngineProvider>
<PageEnigmaComponent />
</EngineProvider>
</AppUIProvider>
<DragComponent />
</TrackProvider>
);
};
+66 -80
View File
@@ -1,4 +1,4 @@
import { useReducer } from "react";
import { useContext } from "react";
import { faSparkles } from "@fortawesome/pro-solid-svg-icons";
@@ -15,23 +15,14 @@ import { ViewSideBySide } from "./comps/ViewSideBySide";
import { SidePanelTabs } from "./comps/SidePanelTabs";
import { Timeline } from "./comps/Timeline";
import { EngineProvider } from "./contexts/EngineProvider";
import { AppUIProvider } from "./contexts/AppUiContext";
import {
appUiReducer,
appUiInitialStateValues,
APPUI_VIEW_MODES,
} from "./reducers";
import { APPUI_VIEW_MODES } from "./reducers";
import { timelineHeight } from "~/pages/PageEnigma/store";
import { useSignals } from "@preact/signals-react/runtime";
import { DragComponent } from "~/pages/PageEnigma/comps/DragComponent/DragComponent";
import { AppUiContext } from "~/pages/PageEnigma/contexts/AppUiContext";
export const PageEnigmaComponent = () => {
useSignals();
const [appUiState, dispatchAppUiState] = useReducer(
appUiReducer,
appUiInitialStateValues,
);
const [appUiState] = useContext(AppUiContext);
//To prevent the click event from propagating to the canvas: TODO: HANDLE THIS BETTER?
const handleOverlayClick = (event: React.MouseEvent<HTMLDivElement>) => {
@@ -45,82 +36,77 @@ export const PageEnigmaComponent = () => {
<Button icon={faSparkles}>Generate Movie</Button>
</TopBarHelmet>
<AppUIProvider value={[appUiState, dispatchAppUiState]}>
<EngineProvider>
<div style={{ height: "calc(100vh - 68px)" }}>
{/* Engine section/side panel */}
<div style={{ height: "calc(100vh - 68px)" }}>
{/* Engine section/side panel */}
<div
id="engine-n-panels-wrapper"
className="flex"
style={{ height: `calc(100% - ${lowerHeight}px)` }}
>
<div className="relative w-full overflow-hidden bg-transparent">
<div
id="engine-n-panels-wrapper"
className="flex"
style={{ height: `calc(100% - ${lowerHeight}px)` }}
className={
appUiState.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE
? "invisible"
: ""
}
>
<div className="relative w-full overflow-hidden bg-transparent">
<div
className={
appUiState.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE
? "invisible"
: ""
}
>
<canvas id="video-scene" width="1280px" height="720px" />
<canvas id="video-scene" width="1280px" height="720px" />
{/* Top controls */}
<div
className="absolute left-0 top-0 w-full"
onClick={handleOverlayClick}
>
<div className="grid grid-cols-3 gap-4">
<ControlsTopButtons />
<Controls3D />
</div>
</div>
{/* Bottom controls */}
<div
className="absolute bottom-0 left-0 w-full"
onClick={handleOverlayClick}
>
<PreviewEngineCamera />
<ControlsVideo />
<ControlPanelSceneObject />
</div>
{/* Top controls */}
<div
className="absolute left-0 top-0 w-full"
onClick={handleOverlayClick}
>
<div className="grid grid-cols-3 gap-4">
<ControlsTopButtons />
<Controls3D />
</div>
{appUiState.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE && (
<ViewSideBySide />
)}
<LoadingDots
className="absolute left-0 top-0"
isShowing={appUiState.showEditorLoader.isShowing}
type="bricks"
message={appUiState.showEditorLoader.message}
/>
<LoadingBar
id="editor-loading-bar"
wrapperClassName="absolute top-0 left-0"
innerWrapperClassName="max-w-screen-sm"
isShowing={appUiState.showEditorLoadingBar.isShowing}
message={appUiState.showEditorLoadingBar.message}
label={appUiState.showEditorLoadingBar.label}
progress={appUiState.showEditorLoadingBar.progress}
/>
</div>
{/* Side panel */}
<div onClick={handleOverlayClick}>
<SidePanel>
<SidePanelTabs />
</SidePanel>
{/* Bottom controls */}
<div
className="absolute bottom-0 left-0 w-full"
onClick={handleOverlayClick}
>
<PreviewEngineCamera />
<ControlsVideo />
<ControlPanelSceneObject />
</div>
</div>
{/* Timeline */}
<div onClick={handleOverlayClick}>
<Timeline />
</div>
{appUiState.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE && (
<ViewSideBySide />
)}
<LoadingDots
className="absolute left-0 top-0"
isShowing={appUiState.showEditorLoader.isShowing}
type="bricks"
message={appUiState.showEditorLoader.message}
/>
<LoadingBar
id="editor-loading-bar"
wrapperClassName="absolute top-0 left-0"
innerWrapperClassName="max-w-screen-sm"
isShowing={appUiState.showEditorLoadingBar.isShowing}
message={appUiState.showEditorLoadingBar.message}
label={appUiState.showEditorLoadingBar.label}
progress={appUiState.showEditorLoadingBar.progress}
/>
</div>
</EngineProvider>
</AppUIProvider>
<DragComponent />
{/* Side panel */}
<div onClick={handleOverlayClick}>
<SidePanel>
<SidePanelTabs />
</SidePanel>
</div>
</div>
{/* Timeline */}
<div onClick={handleOverlayClick}>
<Timeline />
</div>
</div>
</div>
);
};
@@ -20,36 +20,30 @@ import { QueueKeyframe } from "~/pages/PageEnigma/models/track";
export const ControlPanelSceneObject = () => {
const [appUiState, dispatchAppUiState] = useContext(AppUiContext);
const position = appUiState?.currentSceneObject.objectVectors.position;
const rotation = appUiState?.currentSceneObject.objectVectors.rotation;
const scale = appUiState?.currentSceneObject.objectVectors.scale;
const currentSceneObject = appUiState?.currentSceneObject;
const handlePositionChange = (xyz: XYZ) => {
if (appUiState) {
if (currentSceneObject == null) {
console.log("Missing Scene Object Position");
return;
}
dispatchAppUiState({
type: ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT,
payload: {
currentSceneObject: {
group: currentSceneObject.group,
object_uuid: currentSceneObject.object_uuid,
object_name: currentSceneObject.object_name,
version: currentSceneObject.version,
objectVectors: {
position: { ...xyz },
rotation: appUiState.currentSceneObject.objectVectors.rotation,
scale: appUiState.currentSceneObject.objectVectors.scale,
},
},
},
});
if (!currentSceneObject) {
console.log("Missing Scene Object Position");
return;
}
dispatchAppUiState({
type: ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT,
payload: {
group: currentSceneObject.group,
object_uuid: currentSceneObject.object_uuid,
object_name: currentSceneObject.object_name,
version: currentSceneObject.version,
objectVectors: {
position: { ...xyz },
rotation: appUiState?.controlPanel.currentSceneObject?.objectVectors
?.rotation ?? { x: 0, y: 0, z: 0 },
scale: appUiState?.controlPanel.currentSceneObject?.objectVectors
?.scale ?? { x: 0, y: 0, z: 0 },
},
},
});
};
const handleRotationChange = (xyz: XYZ) => {
if (appUiState) {
if (currentSceneObject == null) {
@@ -60,21 +54,22 @@ export const ControlPanelSceneObject = () => {
dispatchAppUiState({
type: ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT,
payload: {
currentSceneObject: {
group: currentSceneObject.group,
object_uuid: currentSceneObject.object_uuid,
object_name: currentSceneObject.object_name,
version: currentSceneObject.version,
objectVectors: {
position: appUiState.currentSceneObject.objectVectors.position,
rotation: { ...xyz },
scale: appUiState.currentSceneObject.objectVectors.scale,
},
group: currentSceneObject.group,
object_uuid: currentSceneObject.object_uuid,
object_name: currentSceneObject.object_name,
version: currentSceneObject.version,
objectVectors: {
position:
appUiState.controlPanel.currentSceneObject.objectVectors.position,
rotation: { ...xyz },
scale:
appUiState.controlPanel.currentSceneObject.objectVectors.scale,
},
},
});
}
};
const handleScaleChange = (xyz: XYZ) => {
if (appUiState) {
if (currentSceneObject == null) {
@@ -84,16 +79,16 @@ export const ControlPanelSceneObject = () => {
dispatchAppUiState({
type: ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT,
payload: {
currentSceneObject: {
group: currentSceneObject.group,
object_uuid: currentSceneObject.object_uuid,
object_name: currentSceneObject.object_name,
version: currentSceneObject.version,
objectVectors: {
position: appUiState.currentSceneObject.objectVectors.position,
rotation: appUiState.currentSceneObject.objectVectors.rotation,
scale: { ...xyz },
},
group: currentSceneObject.group,
object_uuid: currentSceneObject.object_uuid,
object_name: currentSceneObject.object_name,
version: currentSceneObject.version,
objectVectors: {
position:
appUiState.controlPanel.currentSceneObject.objectVectors.position,
rotation:
appUiState.controlPanel.currentSceneObject.objectVectors.rotation,
scale: { ...xyz },
},
},
});
@@ -145,9 +140,19 @@ export const ControlPanelSceneObject = () => {
}
};
if (!appUiState.controlPanel.currentSceneObject) {
return null;
}
const position =
appUiState.controlPanel.currentSceneObject.objectVectors.position;
const rotation =
appUiState.controlPanel.currentSceneObject.objectVectors.rotation;
const scale = appUiState.controlPanel.currentSceneObject.objectVectors.scale;
const currentSceneObject = appUiState.controlPanel.currentSceneObject;
return (
<Transition
show={appUiState?.currentSceneObject.isShowing}
show={appUiState?.controlPanel.isShowing}
className="absolute bottom-0 right-0 m-4 flex h-fit w-fit flex-col gap-2 rounded-lg border border-ui-panel-border bg-ui-panel p-4 text-white"
enter="transition-opacity duration-100"
enterFrom="opacity-0"
@@ -4,10 +4,11 @@ import { ButtonDialogue } from "~/modules/ButtonDialogue";
import { AppUiContext } from "../../contexts/AppUiContext";
import { EngineContext } from "../../contexts/EngineContext";
import { APPUI_ACTION_TYPES } from "../../reducers";
import { ClipGroup } from "~/pages/PageEnigma/models/track";
export const ControlsTopButtons = () => {
const editorEngine = useContext(EngineContext);
const [ appUiState, dispatchAppUiState ] = useContext(AppUiContext);
const [appUiState, dispatchAppUiState] = useContext(AppUiContext);
const [sceneName, setSceneName] = useState<string>("");
const [sceneToken, setSceneToken] = useState<string>("");
@@ -22,8 +23,8 @@ export const ControlsTopButtons = () => {
};
const handleButtonTest = () => {
editorEngine?.testStylizeRequest()
editorEngine?.testStylizeRequest();
// if(appUiState?.showEditorLoadingBar.isShowing){
//TO GO TO A HUNDRED AND DISAPPER
// dispatchAppUiState({
@@ -41,15 +42,15 @@ export const ControlsTopButtons = () => {
// }, 1000);
//END :TO GO TO A HUNDRED AND DISAPPER
//EAMPLE OF CHANING LOADING MESSAGE
// dispatchAppUiState({
// type: APPUI_ACTION_TYPES.UPDATE_EDITOR_LOADINGBAR,
// payload:{
// showEditorLoadingBar: {
// message: "new message",
// }
// }
// });
//EAMPLE OF CHANING LOADING MESSAGE
// dispatchAppUiState({
// type: APPUI_ACTION_TYPES.UPDATE_EDITOR_LOADINGBAR,
// payload:{
// showEditorLoadingBar: {
// message: "new message",
// }
// }
// });
// }else{
// dispatchAppUiState({
// type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADINGBAR,
@@ -59,31 +60,33 @@ export const ControlsTopButtons = () => {
// progress: 10,
// }
// }
// });
//}
};
const handleObjectPanelTest = () => {
if (appUiState?.currentSceneObject.isShowing) {
if (appUiState?.controlPanel.isShowing) {
dispatchAppUiState({
type: APPUI_ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT
type: APPUI_ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT,
});
}else{
} else {
dispatchAppUiState({
type:APPUI_ACTION_TYPES.SHOW_CONTROLPANELS_SCENEOBJECT,
payload:{
currentSceneObject:{
objectVectors: {
position: {x:1,y:2,z:3},
rotation: {x:4,y:5,z:6},
scale: {x:7,y:8,z:9},
}
}
}
type: APPUI_ACTION_TYPES.SHOW_CONTROLPANELS_SCENEOBJECT,
payload: {
group: ClipGroup.OBJECT,
object_name: "",
object_uuid: "",
version: "1",
objectVectors: {
position: { x: 1, y: 2, z: 3 },
rotation: { x: 4, y: 5, z: 6 },
scale: { x: 7, y: 8, z: 9 },
},
},
});
}
}
};
const handleButtonCameraView = () => {
editorEngine?.switchCameraView();
@@ -111,40 +114,44 @@ export const ControlsTopButtons = () => {
<div className="flex flex-col gap-2 pl-3 pt-3">
<div className="flex gap-2">
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Load Scene",
}}
title="Load Scene"
confirmButtonProps={{
label: "Load",
disabled: sceneToken === "" ? true : false,
onClick: handleButtonLoadScene,
}}
>
buttonProps={{
variant: "secondary",
label: "Load Scene",
}}
title="Load Scene"
confirmButtonProps={{
label: "Load",
disabled: sceneToken === "",
onClick: handleButtonLoadScene,
}}
>
<Input
label="Please provide the Token of the scene you wished to load:"
onChange={(e)=>{setSceneToken(e.target.value)}}
onChange={(e) => {
setSceneToken(e.target.value);
}}
/>
</ButtonDialogue>
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Save Scene",
}}
title="Save Scene"
confirmButtonProps={{
label: "Save",
disabled: sceneName === "" ? true : false,
onClick: handleButtonSave,
}}
>
<Input
label="Please Enter a name for your scene"
onChange={(e)=>{setSceneName(e.target.value)}}
/>
</ButtonDialogue>
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Save Scene",
}}
title="Save Scene"
confirmButtonProps={{
label: "Save",
disabled: sceneName === "",
onClick: handleButtonSave,
}}
>
<Input
label="Please Enter a name for your scene"
onChange={(e) => {
setSceneName(e.target.value);
}}
/>
</ButtonDialogue>
<ButtonDialogue
buttonProps={{
@@ -172,7 +179,6 @@ export const ControlsTopButtons = () => {
</Button>
</div>
<div className="flex gap-2">
<Button onClick={handleButtonSingleFrame}>Render Single Frame</Button>
<Button onClick={handleButtonTakeFrame}>Take Frame</Button>
<Button onClick={handleButtonRender}>Render</Button>
@@ -181,7 +187,7 @@ export const ControlsTopButtons = () => {
<Button
onClick={handleButtonTest}
className="bg-brand-tertiary hover:bg-brand-teriary-400 focus-visible:outline-brand-tertiary"
style={{zIndex:9001}}
style={{ zIndex: 9001 }}
>
Test
</Button>
@@ -1,105 +1,114 @@
import { useContext, useState } from 'react';
import { useContext, useState } from "react";
import {
Button,
H4,
ItemPicker,
Textarea
} from "~/components"
import { Button, H4, ItemPicker, Textarea } from "~/components";
import { AppUiContext } from '../../contexts/AppUiContext';
import { APPUI_ACTION_TYPES } from '../../reducers';
import { APPUI_VIEW_MODES } from '../../reducers';
import { EngineContext } from '../../contexts/EngineContext';
import { ArtStyle } from '../../js/api_manager';
export const TabStylization = ()=>{
import { AppUiContext } from "../../contexts/AppUiContext";
import { APPUI_ACTION_TYPES, APPUI_VIEW_MODES } from "../../reducers";
import { EngineContext } from "../../contexts/EngineContext";
import { ArtStyle } from "../../js/api_manager";
export const TabStylization = () => {
const [appUiState, dispatchAppUiState] = useContext(AppUiContext);
const [ selection, setSelection ] = useState<string>("Anime");
const [selection, setSelection] = useState<string>("Anime");
const editorEngine = useContext(EngineContext);
const handlePickingStylizer = (picked:ArtStyle)=>{
const handlePickingStylizer = (picked: ArtStyle) => {
console.log(`Picked style: ${picked}`);
if (editorEngine == null) { console.log("Editor is null"); return;}
editorEngine.art_style = picked
if (editorEngine == null) {
console.log("Editor is null");
return;
}
editorEngine.art_style = picked;
setSelection(picked);
}
};
const onChangeHandlerNegative = (e:React.ChangeEvent<HTMLInputElement>) => {
if (editorEngine == null) { console.log("Editor is null"); return;}
editorEngine.negative_prompt = e.target.value
console.log(e.target.value)
}
const onChangeHandlerNegative = (
e: React.ChangeEvent<HTMLTextAreaElement>,
) => {
if (editorEngine == null) {
console.log("Editor is null");
return;
}
editorEngine.negative_prompt = e.target.value;
console.log(e.target.value);
};
const onChangeHandlerPositive = (e:React.ChangeEvent<HTMLInputElement>) => {
if (editorEngine == null) { console.log("Editor is null"); return;}
editorEngine.positive_prompt = e.target.value
console.log(e.target.value)
}
const handleChangeViewMode = ()=>{
if(dispatchAppUiState!==null){
const onChangeHandlerPositive = (
e: React.ChangeEvent<HTMLTextAreaElement>,
) => {
if (editorEngine == null) {
console.log("Editor is null");
return;
}
editorEngine.positive_prompt = e.target.value;
console.log(e.target.value);
};
const handleChangeViewMode = () => {
if (dispatchAppUiState !== null) {
dispatchAppUiState({
type: APPUI_ACTION_TYPES.ON_CHANGE_VIEW_MODE,
payload: {
viewMode: appUiState?.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE
? APPUI_VIEW_MODES.EDITOR : APPUI_VIEW_MODES.SIDE_BY_SIDE,
}
})
viewMode:
appUiState?.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE
? APPUI_VIEW_MODES.EDITOR
: APPUI_VIEW_MODES.SIDE_BY_SIDE,
},
});
}
}
return(
<div className="gap-2 w-full h-full overflow-scroll">
};
return (
<div className="h-full w-full gap-2 overflow-scroll">
<H4>Select Base Stylizer</H4>
<div className="flex gap-2 my-2">
<div className="my-2 flex gap-2">
<ItemPicker
label="Anime"
selected={(selection === ArtStyle.Anime2DFlat)}
label={ArtStyle.Anime2_5D}
selected={selection === ArtStyle.Anime2DFlat}
onSelected={handlePickingStylizer}
src="/resources/avatars/0.webp"
/>
<ItemPicker
label="Pixel"
label={ArtStyle.PixelArt}
selected={selection === ArtStyle.PixelArt}
onSelected={handlePickingStylizer}
src="/resources/avatars/1.webp"
/>
<ItemPicker
label="Pixar"
label={ArtStyle.Cartoon3D}
selected={selection === ArtStyle.Cartoon3D}
onSelected={handlePickingStylizer}
src="/resources/avatars/2.webp"
/>
<ItemPicker
label="Stylized"
label={ArtStyle.ComicBook}
selected={selection === ArtStyle.ComicBook}
onSelected={handlePickingStylizer}
src="/resources/avatars/3.webp"
/>
</div>
<H4>Enter a Prompt</H4>
<div className="flex gap-2 my-2">
<div className="my-2 flex gap-2">
<Textarea
className="w-full h-32"
className="h-32 w-full"
placeholder="Type here to describe your scene"
onChange={onChangeHandlerPositive}
/>
</div>
<H4>Negative Prompt</H4>
<div className="flex gap-2 my-2">
<div className="my-2 flex gap-2">
<Textarea
className="w-full h-32"
className="h-32 w-full"
placeholder="Type here to filter out the things you don't want in the scene"
onChange={onChangeHandlerNegative}
/>
</div>
<div className="flex gap-2 mt-6 justify-center">
<div className="mt-6 flex justify-center gap-2">
<Button onClick={handleChangeViewMode}>
{
appUiState?.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE
? "Back to Scene" : "Preview Side by Side"
}
{appUiState?.viewMode === APPUI_VIEW_MODES.SIDE_BY_SIDE
? "Back to Scene"
: "Preview Side by Side"}
</Button>
</div>
</div>
);
}
};
@@ -51,7 +51,6 @@ export const Timeline = () => {
};
}, [onDeleteAsk]);
console.log("timeline");
return (
<>
<LowerPanel>
@@ -37,7 +37,6 @@ export function useQueueHandler() {
console.log("TO TIMELINE", action, data);
switch (action) {
case toTimelineActions.ADD_KEYFRAME:
console.log(1);
addKeyframe(data as QueueKeyframe, currentTime.value);
break;
default:
+15 -14
View File
@@ -1,19 +1,20 @@
import { createContext, Dispatch, ReactNode } from "react";
import { AppUiState, AppUiAction } from "../reducers";
import { createContext, Dispatch, ReactNode, useReducer } from "react";
import {
AppUiState,
AppUiAction,
appUiReducer,
appUiInitialStateValues,
} from "../reducers";
export const AppUiContext = createContext<[
AppUiState | null,
Dispatch<AppUiAction>
]>([ null ,()=>{}]);
export const AppUiContext = createContext<[AppUiState, Dispatch<AppUiAction>]>([
appUiInitialStateValues,
() => {},
]);
export const AppUIProvider = ({ children }: { children: ReactNode }) => {
const value = useReducer(appUiReducer, appUiInitialStateValues);
export const AppUIProvider = ({
value,
children,
}:{
value:[AppUiState, Dispatch<AppUiAction>],
children: ReactNode
})=>{
return (
<AppUiContext.Provider value={value}>{children}</AppUiContext.Provider>
);
}
};
@@ -5,31 +5,38 @@ import {
Keyframe,
} from "~/pages/PageEnigma/models/track";
import {
addCameraKeyframe,
addCharacterKeyframe,
addObjectKeyframe,
deleteCameraKeyframe,
deleteCharacterKeyframe,
deleteObjectKeyframe,
} from "~/pages/PageEnigma/store";
const ADD_KEYFRAME: Record<
ClipGroup,
(keyframe: QueueKeyframe, offset: number) => void
> = {
[ClipGroup.CAMERA]: addCameraKeyframe,
[ClipGroup.CHARACTER]: addCharacterKeyframe,
[ClipGroup.OBJECT]: addObjectKeyframe,
[ClipGroup.GLOBAL_AUDIO]: () => {},
};
const DELETE_KEYFRAME: Record<ClipGroup, (keyframe: Keyframe) => void> = {
[ClipGroup.CAMERA]: deleteCameraKeyframe,
[ClipGroup.CHARACTER]: deleteCharacterKeyframe,
[ClipGroup.OBJECT]: deleteObjectKeyframe,
[ClipGroup.GLOBAL_AUDIO]: () => {},
};
export default function useUpdateKeyframe() {
const addKeyframe = useCallback((keyframe: QueueKeyframe, offset: number) => {
console.log(keyframe, offset);
if (keyframe.group === ClipGroup.OBJECT) {
console.log(2);
addObjectKeyframe(keyframe, offset);
}
if (keyframe.group === ClipGroup.CHARACTER) {
addCharacterKeyframe(keyframe, offset);
}
ADD_KEYFRAME[keyframe.group](keyframe, offset);
}, []);
const deleteKeyframe = useCallback((keyframe: Keyframe) => {
if (keyframe.group === ClipGroup.OBJECT) {
deleteObjectKeyframe(keyframe);
}
if (keyframe.group === ClipGroup.CHARACTER) {
deleteCharacterKeyframe(keyframe);
}
DELETE_KEYFRAME[keyframe.group](keyframe);
}, []);
return {
+214 -127
View File
@@ -3,7 +3,7 @@ import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { FreeCam } from "./free_cam";
import { TransformControls } from "three/addons/controls/TransformControls.js";
import Scene from "./scene.js";
import { APIManager, ArtStyle, Visibility } from "./api_manager.js";
import { APIManager, ArtStyle, Visibility } from "./api_manager.js";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
@@ -101,7 +101,7 @@ class Editor {
positive_prompt: string;
negative_prompt: string;
art_style:ArtStyle;
art_style: ArtStyle;
// Default params.
constructor() {
console.log(
@@ -111,9 +111,8 @@ class Editor {
// Special async react lifecycle fix
// For making sure the editor only gets created onece.
this.can_initialize = false;
let one_element = document.getElementById("created-one-element");
this.can_initialize = true;
let newElement = document.createElement("div");
const newElement = document.createElement("div");
newElement.id = "created-one-element";
document.body.appendChild(newElement);
// life cycle fix
@@ -198,9 +197,10 @@ class Editor {
this.current_scene_glb_media_token = null;
// stylization parameters
this.positive_prompt = "((masterpiece, best quality, 8K, detailed)), colorful, epic, fantasy, (fox, red fox:1.2), no humans, 1other, ((koi pond)), outdoors, pond, rocks, stones, koi fish, ((watercolor))), lilypad, fish swimming around."
this.negative_prompt = ""
this.art_style = ArtStyle.Anime2DFlat
this.positive_prompt =
"((masterpiece, best quality, 8K, detailed)), colorful, epic, fantasy, (fox, red fox:1.2), no humans, 1other, ((koi pond)), outdoors, pond, rocks, stones, koi fish, ((watercolor))), lilypad, fish swimming around.";
this.negative_prompt = "";
this.art_style = ArtStyle.Anime2DFlat;
}
initialize(config: any) {
@@ -212,7 +212,6 @@ class Editor {
// type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADER
// });
if (this.can_initialize == false) {
console.log("Editor Already Initialized");
return;
@@ -224,15 +223,20 @@ class Editor {
this.canvasRenderCamReference = document.getElementById("camera-view");
// Base width and height.
let width = this.canvReference.width;
let height = this.canvReference.height;
const width = this.canvReference.width;
const height = this.canvReference.height;
// Sets up camera and base position.
this.camera = new THREE.PerspectiveCamera(70, width / height, 0.15, 30);
this.camera.position.z = 3;
this.camera.position.y = 3;
this.camera.position.x = -3;
this.render_camera = new THREE.PerspectiveCamera(70, width / height, 0.15, 30);
this.render_camera = new THREE.PerspectiveCamera(
70,
width / height,
0.15,
30,
);
// Base WebGL render and clock for delta time.
this.renderer = new THREE.WebGLRenderer({
@@ -291,9 +295,21 @@ class Editor {
this._test_demo();
this.renderer.domElement.addEventListener("mousedown", this.onMouseDown.bind(this), false);
this.renderer.domElement.addEventListener("mouseup", this.onMouseUp.bind(this), false);
this.renderer.domElement.addEventListener("onContextMenu", this.onContextMenu.bind(this), false);
this.renderer.domElement.addEventListener(
"mousedown",
this.onMouseDown.bind(this),
false,
);
this.renderer.domElement.addEventListener(
"mouseup",
this.onMouseUp.bind(this),
false,
);
this.renderer.domElement.addEventListener(
"onContextMenu",
this.onContextMenu.bind(this),
false,
);
// saving state of the scene
this.current_scene_media_token = null;
@@ -317,7 +333,13 @@ class Editor {
this.cam_obj = this.activeScene.get_object_by_name("::CAM::");
if (this.cam_obj) {
this.addTransformClipBase("Camera Object", "camera", this.cam_obj, 0, 150);
this.addTransformClipBase(
"Camera Object",
"camera",
this.cam_obj,
0,
150,
);
}
console.log(this.cam_obj);
@@ -338,22 +360,27 @@ class Editor {
// Token comes in from the front end to load the scene from the site.
public async testBatchRequest() {
const result = await this.api_manager.getMediaBatch(["m_8fmp9hrvsqcryzka1fra597kg42s50", "m_z4jzbst3xfh64h0qn4bqh4afenfps9"]);
const result = await this.api_manager.getMediaBatch([
"m_8fmp9hrvsqcryzka1fra597kg42s50",
"m_z4jzbst3xfh64h0qn4bqh4afenfps9",
]);
console.log(result);
}
public async testTestTimelineEvents() {
}
public async testTestTimelineEvents() {}
public async testStylizeRequest() {
const result = await this.api_manager.stylizeVideo(
"mu_6wy1570a0c3c0tpkkncf4tsvb5234",
this.art_style,
this.positive_prompt,
this.negative_prompt,
Visibility.Public).catch(error=> {
console.log(error);
});
const result = await this.api_manager
.stylizeVideo(
"mu_6wy1570a0c3c0tpkkncf4tsvb5234",
this.art_style,
this.positive_prompt,
this.negative_prompt,
Visibility.Public,
)
.catch((error) => {
console.log(error);
});
console.log(result);
}
@@ -378,7 +405,9 @@ class Editor {
const loaded_scene = load_scene_state_response.data["scene"];
if (load_scene_state_response.data == null) { return; }
if (load_scene_state_response.data == null) {
return;
}
// Load these so you can rewrite the scene glb using it's token.
this.current_scene_media_token =
load_scene_state_response.data["scene_media_file_token"];
@@ -395,9 +424,9 @@ class Editor {
child.parent = this.activeScene.scene;
if (child.type == "DirectionalLight") {
let pos = child.position;
let rot = child.rotation;
let light = this.activeScene._create_base_lighting();
const pos = child.position;
const rot = child.rotation;
const light = this.activeScene._create_base_lighting();
light.position.set(pos.x, pos.y, pos.z);
light.rotation.set(rot.x, rot.y, rot.z);
this.activeScene.scene.remove(child);
@@ -468,7 +497,7 @@ class Editor {
async _serialize_timeline() {
// note the database from the server is the source of truth for all the data.
// Test code here
let object: any = await this.activeScene.load_glb(
const object: any = await this.activeScene.load_glb(
"./resources/models/fox/fox.glb",
);
@@ -494,7 +523,16 @@ class Editor {
// media id for this is up in the air but when a path is created you should be able to store and delete it
this.timeline.addPlayableClip(
new ClipUI(1.0, "transform", "character", "clip2", object.uuid, object.uuid, 0, 150),
new ClipUI(
1.0,
"transform",
"character",
"clip2",
object.uuid,
object.uuid,
0,
150,
),
);
// media id for this as well it can be downloaded
@@ -519,7 +557,7 @@ class Editor {
switchCameraView() {
this.camera_person_mode = !this.camera_person_mode;
console.log("camera")
console.log("camera");
if (this.cam_obj) {
if (this.camera_person_mode) {
this.last_cam_pos.copy(this.camera.position);
@@ -536,12 +574,11 @@ class Editor {
if (this.cameraViewControls) {
this.cameraViewControls.enabled = true;
}
this.cam_obj.scale.set(0,0,0);
this.cam_obj.scale.set(0, 0, 0);
if (this.activeScene.hot_items) {
this.activeScene.hot_items.forEach((element) => {
element.visible = false;
});
}
} else {
this.camera.position.copy(this.last_cam_pos);
@@ -555,7 +592,7 @@ class Editor {
if (this.cameraViewControls) {
this.cameraViewControls.enabled = false;
}
this.cam_obj.scale.set(1,1,1);
this.cam_obj.scale.set(1, 1, 1);
if (this.activeScene.hot_items) {
this.activeScene.hot_items.forEach((element) => {
element.visible = true;
@@ -579,7 +616,7 @@ class Editor {
group,
name,
object.uuid, // object id here ...
object.uuid,// Need to change to media id ....
object.uuid, // Need to change to media id ....
offset,
length,
),
@@ -590,7 +627,7 @@ class Editor {
async _test_demo() {
// note the database from the server is the source of truth for all the data.
// Test code here
let object: any = await this.activeScene.load_glb(
const object: any = await this.activeScene.load_glb(
"./resources/models/fox/fox.glb",
);
@@ -651,8 +688,8 @@ class Editor {
// Configure post processing.
_configurePostProcessing() {
let width = this.canvReference.width;
let height = this.canvReference.height;
const width = this.canvReference.width;
const height = this.canvReference.height;
if (this.renderer == undefined || this.camera == undefined) {
return;
@@ -714,7 +751,7 @@ class Editor {
}
create_parim(name: string) {
let uuid = this.activeScene.instantiate(name);
const uuid = this.activeScene.instantiate(name);
}
renderMode() {
@@ -756,11 +793,16 @@ class Editor {
// Basicly Unity 3D's update loop.
updateLoop(time: number) {
if (this.cam_obj == undefined) {
this.cam_obj = this.activeScene.get_object_by_name("::CAM::");
if (this.cam_obj) {
this.addTransformClipBase("Camera Object", "camera", this.cam_obj, 0, 150)
this.addTransformClipBase(
"Camera Object",
"camera",
this.cam_obj,
0,
150,
);
}
}
@@ -773,7 +815,7 @@ class Editor {
return;
}
let delta_time = this.clock.getDelta();
const delta_time = this.clock.getDelta();
if (this.cameraViewControls && this.camera_person_mode) {
this.cameraViewControls.update(5 * delta_time);
@@ -813,13 +855,12 @@ class Editor {
}
async convertAudioClip(itteration: number, ffmpeg: FFmpeg, clip: ClipUI) {
let video_og = itteration + 'tmp.mp4';
let wav_name = itteration + 'tmp.wav';
let new_video = (itteration + 1) + 'tmp.mp4';
const video_og = itteration + "tmp.mp4";
const wav_name = itteration + "tmp.wav";
const new_video = itteration + 1 + "tmp.mp4";
let startFrame = clip.offset;
let endFrame = clip.length;
if (endFrame > this.timeline.timeline_limit) {
endFrame = this.timeline.timeline_limit;
}
@@ -829,42 +870,72 @@ class Editor {
const startTime = startFrame / this.cap_fps;
const endTime = endFrame / this.cap_fps;
let end = endTime - startTime;
const end = endTime - startTime;
let duration = this.timeline.timeline_limit / this.cap_fps;
let audioSegment = "as_" + wav_name;
await ffmpeg.FS('writeFile', wav_name, await fetchFile(await this.api_manager.getMediaFile(clip.media_id)));
await ffmpeg.run('-i',
const audioSegment = "as_" + wav_name;
await ffmpeg.FS(
"writeFile",
wav_name,
'-ss', '0',
'-to', '' + end,
"-max_muxing_queue_size", "999999",
audioSegment);
await ffmpeg.run('-i', video_og, "-max_muxing_queue_size", "999999", `${itteration}empty_tmp.wav`);
await fetchFile(await this.api_manager.getMediaFile(clip.media_id)),
);
await ffmpeg.run(
"-i",
wav_name,
"-ss",
"0",
"-to",
"" + end,
"-max_muxing_queue_size",
"999999",
audioSegment,
);
await ffmpeg.run(
'-i', `${itteration}empty_tmp.wav`,
'-i', audioSegment,
'-filter_complex', "[1:a]adelay=" + startTime * 1000 + "|" + startTime * 1000 + "[a1];[0:a][a1]amix=inputs=2[a]",
"-map", "[a]",
`${itteration}final_tmp.wav`)
"-i",
video_og,
"-max_muxing_queue_size",
"999999",
`${itteration}empty_tmp.wav`,
);
await ffmpeg.run(
'-i', video_og,
'-i', `${itteration}final_tmp.wav`,
'-c:v', 'copy',
'-c:a', 'aac',
'-map', '0:v:0',
'-map', '1:a:0',
'-strict', 'experimental',
new_video)
"-i",
`${itteration}empty_tmp.wav`,
"-i",
audioSegment,
"-filter_complex",
"[1:a]adelay=" +
startTime * 1000 +
"|" +
startTime * 1000 +
"[a1];[0:a][a1]amix=inputs=2[a]",
"-map",
"[a]",
`${itteration}final_tmp.wav`,
);
await ffmpeg.run(
"-i",
video_og,
"-i",
`${itteration}final_tmp.wav`,
"-c:v",
"copy",
"-c:a",
"aac",
"-map",
"0:v:0",
"-map",
"1:a:0",
"-strict",
"experimental",
new_video,
);
}
async stopPlayback(compile_audio: boolean = true) {
this.renderMode();
let ffmpeg = createFFmpeg({ log: true });
const ffmpeg = createFFmpeg({ log: true });
await ffmpeg.load();
for (let index = 0; index < this.frame_buffer.length; index++) {
const element = this.frame_buffer[index];
@@ -890,10 +961,9 @@ class Editor {
"-c:a",
"aac", // Specify audio codec (optional, but recommended for MP4)
"-shortest", // Ensure output duration matches the shortest stream (video or audio)
"0tmp.mp4"
"0tmp.mp4",
);
let itteration = 0;
if (compile_audio) {
@@ -902,10 +972,10 @@ class Editor {
await this.convertAudioClip(itteration, ffmpeg, clip);
itteration += 1;
}
};
}
}
let output = await ffmpeg.FS("readFile", itteration + "tmp.mp4");
const output = await ffmpeg.FS("readFile", itteration + "tmp.mp4");
// Create a Blob from the output file for downloading
const blob = new Blob([output.buffer], { type: "video/mp4" });
const url = URL.createObjectURL(blob);
@@ -918,11 +988,9 @@ class Editor {
URL.revokeObjectURL(url);
document.body.removeChild(downloadLink);
let data = await this.api_manager.uploadMedia(blob, "tmp.wav");
const data = await this.api_manager.uploadMedia(blob, "tmp.wav");
console.log(data);
// Create a link to download the file
}
async generateFrame() {
@@ -931,7 +999,7 @@ class Editor {
this.generating_preview = true;
this.activeScene.renderMode(true);
if (this.activeScene.hot_items) {
this.activeScene.hot_items.forEach(element => {
this.activeScene.hot_items.forEach((element) => {
element.visible = false;
});
}
@@ -943,37 +1011,41 @@ class Editor {
this.renderer.setSize(this.render_width, this.render_height);
this.renderer.render(this.activeScene.scene, this.render_camera);
let imgData = this.renderer.domElement.toDataURL();
const imgData = this.renderer.domElement.toDataURL();
this.activeScene.renderMode(false);
this.onWindowResize();
const rawPreview: HTMLVideoElement | null = document.getElementById("raw-preview") as HTMLVideoElement;
const rawPreview: HTMLVideoElement | null = document.getElementById(
"raw-preview",
) as HTMLVideoElement;
if (rawPreview) {
rawPreview.src = imgData;
let ffmpeg = createFFmpeg({ log: false });
const ffmpeg = createFFmpeg({ log: false });
await ffmpeg.load();
await ffmpeg.FS(
"writeFile",
`render.png`,
await fetchFile(imgData),
);
await ffmpeg.run('-i', `render.png`, 'render.mp4');
let output = await ffmpeg.FS("readFile", 'render.mp4');
await ffmpeg.FS("writeFile", `render.png`, await fetchFile(imgData));
await ffmpeg.run("-i", `render.png`, "render.mp4");
const output = await ffmpeg.FS("readFile", "render.mp4");
const blob = new Blob([output.buffer], { type: "video/mp4" });
let url = await this.api_manager.uploadMediaFrameGeneration(blob, "render.mp4", "anime_ghibli", "((masterpiece, best quality, 8K, detailed)), colorful, epic, fantasy, (fox, red fox:1.2), no humans, 1other, ((koi pond)), outdoors, pond, rocks, stones, koi fish, ((watercolor))), lilypad, fish swimming around.", "");
const url = await this.api_manager.uploadMediaFrameGeneration(
blob,
"render.mp4",
"anime_ghibli",
"((masterpiece, best quality, 8K, detailed)), colorful, epic, fantasy, (fox, red fox:1.2), no humans, 1other, ((koi pond)), outdoors, pond, rocks, stones, koi fish, ((watercolor))), lilypad, fish swimming around.",
"",
);
console.log(url);
const stylePreview: HTMLVideoElement | null = document.getElementById("stylized-preview") as HTMLVideoElement;
const stylePreview: HTMLVideoElement | null = document.getElementById(
"stylized-preview",
) as HTMLVideoElement;
if (stylePreview) {
stylePreview.src = url;
stylePreview.width = rawPreview.width;
stylePreview.height = rawPreview.height;
}
else {
console.log("No style preview window.")
} else {
console.log("No style preview window.");
}
this.generating_preview = false;
@@ -981,9 +1053,8 @@ class Editor {
return new Promise((resolve, reject) => {
resolve(url);
});
}
else {
console.log("No raw preview window.")
} else {
console.log("No raw preview window.");
}
this.generating_preview = false;
}
@@ -991,14 +1062,16 @@ class Editor {
generateVideo() {
console.log("Generating video...");
if (this.rendering) { return; }
if (this.rendering) {
return;
}
this.startPlayback();
this.frame_buffer = [];
this.render_timer = 0;
this.rendering = true;
this.activeScene.renderMode(this.rendering);
if (this.activeScene.hot_items) {
this.activeScene.hot_items.forEach(element => {
this.activeScene.hot_items.forEach((element) => {
element.visible = false;
});
}
@@ -1046,7 +1119,7 @@ class Editor {
if (this.rendering && this.renderer && this.clock) {
this.playback_location++;
let imgData = this.renderer.domElement.toDataURL();
const imgData = this.renderer.domElement.toDataURL();
this.frame_buffer.push(imgData);
this.render_timer += this.clock.getDelta();
if (this.timeline.is_playing == false) {
@@ -1060,35 +1133,47 @@ class Editor {
}
updateSelectedUI() {
if (this.selected == undefined) { return; }
if (this.selected == undefined) {
return;
}
const pos = this.selected.position;
const rot = this.selected.rotation;
const scale = this.selected.scale;
let pos = this.selected.position;
let rot = this.selected.rotation;
let scale = this.selected.scale;
this.dispatchAppUiState({
type: APPUI_ACTION_TYPES.SHOW_CONTROLPANELS_SCENEOBJECT,
payload: {
currentSceneObject: {
group: "object", // TODO: add meta data to determine what it is a camera or a object or a character into prefab clips
object_uuid: this.selected.uuid,
object_name: this.selected.name,
version: this.version,
objectVectors: {
position: { x: parseFloat(pos.x.toFixed(2)), y: parseFloat(pos.y.toFixed(2)), z: parseFloat(pos.z.toFixed(2)) },
rotation: { x: parseFloat(rot.x.toFixed(2)), y: parseFloat(rot.y.toFixed(2)), z: parseFloat(rot.z.toFixed(2)) },
scale: { x: parseFloat(scale.x.toFixed(2)), y: parseFloat(scale.y.toFixed(2)), z: parseFloat(scale.z.toFixed(2)) },
}
}
}
group: "object", // TODO: add meta data to determine what it is a camera or a object or a character into prefab clips
object_uuid: this.selected.uuid,
object_name: this.selected.name,
version: this.version,
objectVectors: {
position: {
x: parseFloat(pos.x.toFixed(2)),
y: parseFloat(pos.y.toFixed(2)),
z: parseFloat(pos.z.toFixed(2)),
},
rotation: {
x: parseFloat(rot.x.toFixed(2)),
y: parseFloat(rot.y.toFixed(2)),
z: parseFloat(rot.z.toFixed(2)),
},
scale: {
x: parseFloat(scale.x.toFixed(2)),
y: parseFloat(scale.y.toFixed(2)),
z: parseFloat(scale.z.toFixed(2)),
},
},
},
});
}
// Automaticly resize scene.
onWindowResize() {
// Calculate the maximum possible dimensions while maintaining the aspect ratio
let width = window.innerWidth; // / aspect_adjust
let height = window.innerHeight; // / aspectRatio
const width = window.innerWidth; // / aspect_adjust
const height = window.innerHeight; // / aspectRatio
if (this.camera == undefined || this.renderer == undefined) {
return;
@@ -1103,7 +1188,9 @@ class Editor {
this.composer.setSize(width, height);
}
if (this.render_camera == undefined) { return; }
if (this.render_camera == undefined) {
return;
}
//this.renderer.setSize(this.render_width, this.render_height);
this.render_camera.aspect = this.render_width / this.render_height;
@@ -1148,7 +1235,7 @@ class Editor {
}
this.raycaster.setFromCamera(this.mouse, this.camera);
let interactable: any[] = [];
const interactable: any[] = [];
this.activeScene.scene.children.forEach((child: THREE.Object3D) => {
if (child.name != "") {
if (child.type == "Mesh" || child.type == "Object3D") {
@@ -1156,7 +1243,7 @@ class Editor {
}
}
});
let intersects = this.raycaster.intersectObjects(interactable, true);
const intersects = this.raycaster.intersectObjects(interactable, true);
if (intersects.length > 0) {
if (intersects[0].object.type != "GridHelper") {
@@ -1180,7 +1267,7 @@ class Editor {
} else if (this.transform_interaction == false) {
this.removeTransformControls();
this.dispatchAppUiState({
type: APPUI_ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT
type: APPUI_ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT,
});
} else {
this.transform_interaction = false;
@@ -1,107 +1,95 @@
import { State, Action, ACTION_TYPES} from './types';
import { State, Action, ACTION_TYPES } from "./types";
export function reducer(state: State, action: Action): State {
switch(action.type){
case ACTION_TYPES.SHOW_CONTROLPANELS_SCENEOBJECT:{
return{
switch (action.type) {
case ACTION_TYPES.SHOW_CONTROLPANELS_SCENEOBJECT: {
console.log("pay", action.payload);
return {
...state,
currentSceneObject: {
group:action.payload.currentSceneObject.group,
object_name:action.payload.currentSceneObject.object_name,
object_uuid:action.payload.currentSceneObject.object_uuid,
version:action.payload.currentSceneObject.version,
controlPanel: {
isShowing: true,
objectVectors: {...action.payload.currentSceneObject.objectVectors},
currentSceneObject: action.payload,
},
}
};
}
case ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT:{
return{
case ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT: {
return {
...state,
currentSceneObject: {
group:action.payload.currentSceneObject.group,
object_name:action.payload.currentSceneObject.object_name,
object_uuid:action.payload.currentSceneObject.object_uuid,
version:action.payload.currentSceneObject.version,
isShowing: state.currentSceneObject.isShowing,
objectVectors: {...action.payload.currentSceneObject.objectVectors},
controlPanel: {
isShowing: state.controlPanel.isShowing,
currentSceneObject: action.payload,
},
}
};
}
case ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT:{
return{
case ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT: {
return {
...state,
currentSceneObject: {
group:action.payload.currentSceneObject.group,
object_name:action.payload.currentSceneObject.object_name,
object_uuid:action.payload.currentSceneObject.object_uuid,
version:action.payload.currentSceneObject.version,
controlPanel: {
...state.controlPanel,
isShowing: false,
objectVectors: state.currentSceneObject.objectVectors,
},
}
};
}
case ACTION_TYPES.SHOW_EDITOR_LOADER:{
return{
case ACTION_TYPES.SHOW_EDITOR_LOADER: {
return {
...state,
showEditorLoader: {
isShowing: true,
message: action.payload?.showEditorLoader.message,
},
}
};
}
case ACTION_TYPES.HIDE_EDITOR_LOADER:{
return{
case ACTION_TYPES.HIDE_EDITOR_LOADER: {
return {
...state,
showEditorLoader: {
isShowing: false,
message: state.showEditorLoader.message
message: state.showEditorLoader.message,
},
}
};
}
case ACTION_TYPES.SHOW_EDITOR_LOADINGBAR:{
return{
case ACTION_TYPES.SHOW_EDITOR_LOADINGBAR: {
return {
...state,
showEditorLoadingBar: {
...action.payload?.showEditorLoadingBar,
isShowing: true,
},
}
};
}
case ACTION_TYPES.UPDATE_EDITOR_LOADINGBAR:{
return{
case ACTION_TYPES.UPDATE_EDITOR_LOADINGBAR: {
return {
...state,
showEditorLoadingBar: {
...state.showEditorLoadingBar,
...action.payload?.showEditorLoadingBar,
},
}
};
}
case ACTION_TYPES.HIDE_EDITOR_LOADINGBAR:{
return{
case ACTION_TYPES.HIDE_EDITOR_LOADINGBAR: {
return {
...state,
showEditorLoadingBar: {
...state.showEditorLoadingBar,
isShowing: false,
},
}
};
}
case ACTION_TYPES.ON_TIMELINE_RESIZE:{
return{
case ACTION_TYPES.ON_TIMELINE_RESIZE: {
return {
...state,
timelineHeight: action.payload.timelineHeight,
}
};
}
case ACTION_TYPES.ON_CHANGE_VIEW_MODE:{
case ACTION_TYPES.ON_CHANGE_VIEW_MODE: {
console.log(action);
return{
return {
...state,
viewMode: action.payload.viewMode
}
viewMode: action.payload.viewMode,
};
}
default:{
default: {
return state; //no change
}
}// end switch
} // end switch
}
@@ -1,37 +1,41 @@
import { Simple3DVector } from "../../datastructures/common";
import { ClipGroup } from "../../models/track";
export enum VIEW_MODES {
EDITOR = 'editor',
SIDE_BY_SIDE = 'side-by-side'
};
EDITOR = "editor",
SIDE_BY_SIDE = "side-by-side",
}
type ViewModes = VIEW_MODES.EDITOR | VIEW_MODES.SIDE_BY_SIDE;
export type ControlPanel = {
isShowing: boolean;
currentSceneObject: SceneObject;
};
export type SceneObject = {
group: ClipGroup; // TODO: add meta data to determine what it is a camera or a object or a character into prefab clips
object_uuid: string;
object_name: string;
version: string;
objectVectors: Simple3DVector;
};
export type State = {
viewMode: ViewModes;
timelineHeight: number;
showEditorLoader: {
isShowing:boolean;
message?:string;
isShowing: boolean;
message?: string;
};
showEditorLoadingBar:{
showEditorLoadingBar: {
isShowing: boolean;
label?: string;
message?: string;
progress?: number;
useFakeTimer?: number;
}
currentSceneObject:{
group: ClipGroup, // TODO: add meta data to determine what it is a camera or a object or a character into prefab clips
object_uuid: string,
object_name: string,
version: string
isShowing: boolean;
objectVectors: Simple3DVector;
}
};
controlPanel: ControlPanel;
};
export enum ACTION_TYPES {
ON_TIMELINE_RESIZE = "on_timeline_resize",
ON_CHANGE_VIEW_MODE = "on_change_view_mode",
@@ -43,86 +47,61 @@ export enum ACTION_TYPES {
SHOW_CONTROLPANELS_SCENEOBJECT = "show_controlpanels_sceneobject",
UPDATE_CONTROLPANELS_SCENEOBJECT = "update_controlpanels_sceneobject",
HIDE_CONTROLPANELS_SCENEOBJECT = "hide_controlpanels_sceneobject",
};
}
export type Action =
| { // Not sure why we need this but type script won't stop complaning fix wil.
type: ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT,
payload:{
currentSceneObject: {
group: ClipGroup,
object_uuid: string,
object_name: string,
version: string,
objectVectors: Simple3DVector;
| {
// Not sure why we need this but type script won't stop complaning fix wil.
type: ACTION_TYPES.HIDE_CONTROLPANELS_SCENEOBJECT;
}
| {
type: ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT;
payload: SceneObject;
}
| {
type: ACTION_TYPES.SHOW_CONTROLPANELS_SCENEOBJECT;
payload: SceneObject;
}
| { type: ACTION_TYPES.HIDE_EDITOR_LOADER }
| {
type: ACTION_TYPES.SHOW_EDITOR_LOADER;
payload?: {
showEditorLoader: {
message: string | undefined;
};
};
}
}
| { type: ACTION_TYPES.HIDE_EDITOR_LOADINGBAR }
| {
type: ACTION_TYPES.UPDATE_CONTROLPANELS_SCENEOBJECT,
payload:{
currentSceneObject: {
group: ClipGroup,
object_uuid: string,
object_name: string,
version: string,
objectVectors: Simple3DVector;
};
}
}
| {
type: ACTION_TYPES.SHOW_CONTROLPANELS_SCENEOBJECT,
payload:{
currentSceneObject: {
group: ClipGroup,
object_uuid: string,
object_name: string,
version: string,
objectVectors: Simple3DVector;
};
}
}
| {type: ACTION_TYPES.HIDE_EDITOR_LOADER,}
| {
type: ACTION_TYPES.SHOW_EDITOR_LOADER,
payload?:{
showEditorLoader: {
message:string|undefined;
}
}
}
| {type: ACTION_TYPES.HIDE_EDITOR_LOADINGBAR,}
| {
type: ACTION_TYPES.SHOW_EDITOR_LOADINGBAR,
payload?:{
type: ACTION_TYPES.SHOW_EDITOR_LOADINGBAR;
payload?: {
showEditorLoadingBar: {
label?: string;
message?: string;
progress?: number;
useFakeTimer?: number;
}
}
};
};
}
| {
type: ACTION_TYPES.UPDATE_EDITOR_LOADINGBAR,
payload:{
type: ACTION_TYPES.UPDATE_EDITOR_LOADINGBAR;
payload: {
showEditorLoadingBar: {
label?: string;
message?: string;
progress?: number;
}
}
};
};
}
| {
type: ACTION_TYPES.ON_TIMELINE_RESIZE,
type: ACTION_TYPES.ON_TIMELINE_RESIZE;
payload: {
timelineHeight: number
}
timelineHeight: number;
};
}
| {
type: ACTION_TYPES.ON_CHANGE_VIEW_MODE,
payload: {
viewMode: ViewModes
}
}
;
type: ACTION_TYPES.ON_CHANGE_VIEW_MODE;
payload: {
viewMode: ViewModes;
};
};
@@ -1,23 +1,30 @@
import {State, VIEW_MODES} from './types';
import { State, VIEW_MODES } from "./types";
import { ClipGroup } from "~/pages/PageEnigma/models/track";
export const initialStateValues : State = {
export const initialStateValues: State = {
timelineHeight: 260,
viewMode: VIEW_MODES.EDITOR,
showEditorLoader: {
isShowing:false,
message: 'Loading Editor Engine 🦊'
isShowing: false,
message: "Loading Editor Engine 🦊",
},
showEditorLoadingBar: {
isShowing:true,
progress:5,
message: 'Loading Editor Engine 🦊'
isShowing: true,
progress: 5,
message: "Loading Editor Engine 🦊",
},
currentSceneObject:{
isShowing:false,
objectVectors:{
position:{x:0,y:0,z:0},
rotation:{x:0,y:0,z:0},
scale:{x:0,y:0,z:0},
}
}
}
controlPanel: {
isShowing: false,
currentSceneObject: {
group: ClipGroup.OBJECT,
object_name: "",
object_uuid: "",
version: "1",
objectVectors: {
position: { x: 0, y: 0, z: 0 },
rotation: { x: 0, y: 0, z: 0 },
scale: { x: 0, y: 0, z: 0 },
},
},
},
};
+2 -2
View File
@@ -78,13 +78,13 @@ export function selectCameraKeyframe(keyframeId: string) {
};
}
export function deleteCameraKeyframe(keyframeId: string) {
export function deleteCameraKeyframe(deleteKeyframe: Keyframe) {
const oldCameraGroup = cameraGroup.value;
cameraGroup.value = {
...oldCameraGroup,
keyframes: [
...oldCameraGroup.keyframes.filter((keyframe) => {
if (keyframe.keyframe_uuid === keyframeId) {
if (keyframe.keyframe_uuid === deleteKeyframe.keyframe_uuid) {
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.DELETE_KEYFRAME,
+11 -4
View File
@@ -6,6 +6,9 @@ import {
} from "~/pages/PageEnigma/models/track";
import { useCallback } from "react";
import * as uuid from "uuid";
import Queue from "~/pages/PageEnigma/Queue/Queue";
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
export const objectGroup = signal<ObjectGroup>({
id: "OB1",
@@ -39,7 +42,7 @@ export function addObjectKeyframe(keyframe: QueueKeyframe, offset: number) {
name: keyframe.object_name ?? "unknown",
keyframes: [] as Keyframe[],
};
newObject.keyframes.push({
const newKeyframe = {
version: keyframe.version,
keyframe_uuid: uuid.v4(),
group: keyframe.group,
@@ -49,13 +52,13 @@ export function addObjectKeyframe(keyframe: QueueKeyframe, offset: number) {
rotation: keyframe.rotation,
scale: keyframe.scale,
selected: false,
} as Keyframe);
} as Keyframe;
newObject.keyframes.push(newKeyframe);
console.log(newObject);
newObject.keyframes.sort(
(keyframeA, keyframeB) => keyframeA.offset - keyframeB.offset,
);
console.log(4);
objectGroup.value = {
...oldObjectGroup,
objects: [
@@ -65,7 +68,11 @@ export function addObjectKeyframe(keyframe: QueueKeyframe, offset: number) {
newObject,
].sort((objA, objB) => (objA.object_uuid < objB.object_uuid ? -1 : 1)),
};
console.log("T", objectGroup.value);
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.ADD_KEYFRAME,
data: newKeyframe,
});
}
export function deleteObjectKeyframe(keyframe: Keyframe) {