mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
Refactor for queuing
This commit is contained in:
1 parent
92ed9cd26c
commit
4ebba7dfad
16 files changed
+349
-188
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { useReducer, useEffect } from "react";
|
||||
import { useReducer } from "react";
|
||||
|
||||
import { faSparkles } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
@@ -17,7 +17,6 @@ import { AppUIProvider } from "./contexts/AppUiContext";
|
||||
import {
|
||||
appUiReducer,
|
||||
appUiInitialStateValues,
|
||||
APPUI_ACTION_TYPES,
|
||||
APPUI_VIEW_MODES,
|
||||
} from "./reducers";
|
||||
import { ViewSideBySide } from "./comps/ViewSideBySide";
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { fromEngineActions } from "~/pages/PageEnigma/Queue/fromEngineActions";
|
||||
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
|
||||
import { QueueClip } from "~/pages/PageEnigma/models/track";
|
||||
|
||||
class Queue {
|
||||
private _queue: Record<
|
||||
string,
|
||||
{ action: fromEngineActions | toEngineActions; data: any }[]
|
||||
{
|
||||
action: fromEngineActions | toEngineActions;
|
||||
data: QueueClip | { currentTime: number };
|
||||
}[]
|
||||
> = {};
|
||||
private _subscribers: Record<
|
||||
string,
|
||||
(entry: { action: fromEngineActions | toEngineActions; data: any }) => void
|
||||
(entry: {
|
||||
action: fromEngineActions | toEngineActions;
|
||||
data: QueueClip | { currentTime: number };
|
||||
}) => void
|
||||
> = {};
|
||||
|
||||
public publish({
|
||||
@@ -18,12 +25,13 @@ class Queue {
|
||||
}: {
|
||||
queueName: string;
|
||||
action: fromEngineActions | toEngineActions;
|
||||
data: any;
|
||||
data: QueueClip | { currentTime: number };
|
||||
}) {
|
||||
if (!this._queue[queueName]) {
|
||||
this._queue[queueName] = [];
|
||||
}
|
||||
this._queue[queueName].push({ action, data });
|
||||
console.log("Queued", queueName, action, data);
|
||||
|
||||
if (this._subscribers[queueName]) {
|
||||
this._subscribers[queueName](this._queue[queueName].splice(0, 1)[0]);
|
||||
@@ -34,7 +42,7 @@ class Queue {
|
||||
queueName: string,
|
||||
onMessage: (entry: {
|
||||
action: fromEngineActions | toEngineActions;
|
||||
data: any;
|
||||
data: QueueClip | { currentTime: number };
|
||||
}) => void,
|
||||
) {
|
||||
this._subscribers[queueName] = onMessage;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export enum fromEngineActions {
|
||||
FRAME_TICK, // data={currentTime: number}
|
||||
UPDATE_TIME = "update_time",
|
||||
// data={currentTime: number}
|
||||
}
|
||||
@@ -1,4 +1,18 @@
|
||||
export enum toEngineActions {
|
||||
ADD_ANIMATION, // data={id: string, offset: number, length: number}
|
||||
SCRUBBER_TIME, // data={currentTime: number}
|
||||
ADD_CLIP = "add_clip",
|
||||
// data=QueueClip
|
||||
DELETE_CLIP = "delete_clip",
|
||||
// data=QueueClip
|
||||
MUTE = "mute",
|
||||
// data={version, type, group, object_uuid} if lipsync
|
||||
// data={version, type, group} if global_audio
|
||||
PLAY_CLIP = "play_clip",
|
||||
// data=QueueClip
|
||||
UNMUTE = "unmute",
|
||||
// data={version, type, group, object_uuid} if lipsync
|
||||
// data={version, type, group} if global_audio
|
||||
UPDATE_CLIP = "update_clip",
|
||||
// data=QueueClip
|
||||
UPDATE_TIME = "update_time",
|
||||
// data={currentTime: number}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useContext, useEffect } from "react";
|
||||
import { BaseClip } from "~/pages/PageEnigma/models/track";
|
||||
import { MediaClip } from "~/pages/PageEnigma/models/track";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import {
|
||||
canDrop,
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
interface Props {
|
||||
clip: BaseClip;
|
||||
clip: MediaClip;
|
||||
type: "animations" | "lipSync";
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export const ClipElement = ({ clip, type }: Props) => {
|
||||
(event: React.PointerEvent<HTMLDivElement>) => {
|
||||
if (event.button === 0) {
|
||||
console.log("X", event.clientX);
|
||||
startDrag(type, clip.id, clip.length);
|
||||
startDrag(type, clip.media_id, clip.length);
|
||||
currPosition.value = {
|
||||
currX: event.pageX,
|
||||
currY: event.pageY,
|
||||
@@ -62,14 +62,14 @@ export const ClipElement = ({ clip, type }: Props) => {
|
||||
canDrop.value = false;
|
||||
}
|
||||
},
|
||||
[type, clip.id, startDrag, clip.length],
|
||||
[type, clip.media_id, startDrag, clip.length],
|
||||
);
|
||||
|
||||
return (
|
||||
<div key={clip.id} className="relative h-16 w-16">
|
||||
<div className="relative h-16 w-16">
|
||||
<div
|
||||
id={`ani-clip-${clip.id}`}
|
||||
className="absolute block h-16 w-16 bg-brand-secondary-700"
|
||||
id={`ani-clip-${clip.media_id}`}
|
||||
className="absolute block h-16 w-16 rounded-lg bg-brand-secondary-700 p-2"
|
||||
style={{ top: 0, left: 0 }}
|
||||
onPointerDown={onPointerDown}
|
||||
>
|
||||
|
||||
@@ -14,9 +14,11 @@ export const ClipElements = () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap overflow-y-auto" style={{ height }}>
|
||||
<div className="flex flex-wrap gap-3 overflow-y-auto" style={{ height }}>
|
||||
{animationClips.map((clip) => {
|
||||
return <ClipElement key={clip.id} clip={clip} type="animations" />;
|
||||
return (
|
||||
<ClipElement key={clip.media_id} clip={clip} type="animations" />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TrackClip } from "~/pages/PageEnigma/comps/Timeline/TrackClip";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faVolume, faVolumeSlash } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { BaseClip } from "~/pages/PageEnigma/models/track";
|
||||
import { Clip } from "~/pages/PageEnigma/models/track";
|
||||
import { PointerEvent } from "react";
|
||||
import {
|
||||
canDrop,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
clips: BaseClip[];
|
||||
clips: Clip[];
|
||||
title: string;
|
||||
style: "character" | "audio" | "camera" | "objects";
|
||||
type?: "animations" | "positions" | "lipSync";
|
||||
@@ -94,7 +94,7 @@ export const TrackClips = ({
|
||||
>
|
||||
{clips.map((clip, index) => (
|
||||
<TrackClip
|
||||
key={clip.id}
|
||||
key={clip.clip_uuid}
|
||||
min={
|
||||
index > 0 ? clips[index - 1].offset + clips[index - 1].length : 0
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export const useMouseEventsAnimation = () => {
|
||||
setTime(-1);
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.SCRUBBER_TIME,
|
||||
action: toEngineActions.UPDATE_TIME,
|
||||
data: { currentTime: Math.round(time) },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { Dispatch, useCallback, useEffect, useRef } from "react";
|
||||
import { BaseClip } from "~/pages/PageEnigma/models/track";
|
||||
import { Clip } from "~/pages/PageEnigma/models/track";
|
||||
import { canDrop, scale } from "~/pages/PageEnigma/store";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
export const useMouseEventsClip = (
|
||||
clip: BaseClip,
|
||||
clip: Clip,
|
||||
max: number,
|
||||
min: number,
|
||||
updateClip: (args: { id: string; offset: number; length: number }) => void,
|
||||
@@ -21,14 +21,14 @@ export const useMouseEventsClip = (
|
||||
const onPointerUp = useCallback(() => {
|
||||
if (isActive.current) {
|
||||
updateClip({
|
||||
id: clip.id,
|
||||
id: clip.clip_uuid,
|
||||
offset: Math.round(currOffset.current),
|
||||
length: Math.round(currLength.current),
|
||||
});
|
||||
isActive.current = "";
|
||||
canDrop.value = false;
|
||||
}
|
||||
}, [updateClip, clip.id]);
|
||||
}, [updateClip, clip.clip_uuid]);
|
||||
|
||||
const onMouseMove = useCallback(
|
||||
(event: MouseEvent) => {
|
||||
|
||||
@@ -5,18 +5,23 @@ import { currentTime } from "~/pages/PageEnigma/store";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
|
||||
import { QueueClip } from "~/pages/PageEnigma/models/track";
|
||||
|
||||
interface UpdateTime {
|
||||
currentTime: number;
|
||||
}
|
||||
|
||||
interface Arguments {
|
||||
action: fromEngineActions | toEngineActions;
|
||||
data: any;
|
||||
data: QueueClip | UpdateTime;
|
||||
}
|
||||
|
||||
export function useQueueHandler() {
|
||||
useSignals();
|
||||
const handleActions = useCallback(({ action, data }: Arguments) => {
|
||||
switch (action) {
|
||||
case fromEngineActions.FRAME_TICK:
|
||||
currentTime.value = data.currentTime;
|
||||
case fromEngineActions.UPDATE_TIME:
|
||||
currentTime.value = (data as UpdateTime).currentTime;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown action ${action}`);
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { createContext } from "react";
|
||||
import {
|
||||
AnimationClip,
|
||||
AudioClip,
|
||||
AudioGroup,
|
||||
BaseClip,
|
||||
CameraGroup,
|
||||
CharacterGroup,
|
||||
ObjectGroup,
|
||||
ObjectTrack,
|
||||
MediaClip,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
|
||||
export const TrackContext = createContext<{
|
||||
@@ -23,13 +21,13 @@ export const TrackContext = createContext<{
|
||||
addCharacterAnimation: (options: {
|
||||
clipId: string;
|
||||
characterId: string;
|
||||
animationClips: BaseClip[];
|
||||
animationClips: MediaClip[];
|
||||
offset: number;
|
||||
}) => void;
|
||||
addCharacterAudio: (options: {
|
||||
clipId: string;
|
||||
characterId: string;
|
||||
audioClips: BaseClip[];
|
||||
audioClips: MediaClip[];
|
||||
offset: number;
|
||||
}) => void;
|
||||
selectCharacterClip: (clipId: string) => void;
|
||||
@@ -55,7 +53,7 @@ export const TrackContext = createContext<{
|
||||
toggleAudioMute: () => void;
|
||||
addGlobalAudio: (
|
||||
clipId: string,
|
||||
animationClips: BaseClip[],
|
||||
animationClips: MediaClip[],
|
||||
offset: number,
|
||||
) => void;
|
||||
selectAudioClip: (clipId: string) => void;
|
||||
@@ -71,8 +69,8 @@ export const TrackContext = createContext<{
|
||||
selectClip: (clipId: string) => void;
|
||||
|
||||
// sidebar clips
|
||||
animationClips: AnimationClip[];
|
||||
audioClips: AudioClip[];
|
||||
animationClips: MediaClip[];
|
||||
audioClips: MediaClip[];
|
||||
|
||||
// drag and drop
|
||||
startDrag: (
|
||||
|
||||
@@ -4,7 +4,7 @@ import useUpdateCharacters from "~/pages/PageEnigma/contexts/TrackContext/utils/
|
||||
import useUpdateCamera from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera";
|
||||
import useUpdateAudio from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio";
|
||||
import useUpdateObject from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject";
|
||||
import { AnimationClip, AudioClip } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipType, MediaClip } from "~/pages/PageEnigma/models/track";
|
||||
import useUpdateDragDrop from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateDragDrop";
|
||||
import {
|
||||
canDrop,
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
dropId,
|
||||
dropOffset,
|
||||
} from "~/pages/PageEnigma/store";
|
||||
import * as uuid from "uuid";
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
@@ -31,8 +32,8 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
setSelectedClip(clipId);
|
||||
}, []);
|
||||
|
||||
const [animationClips, setAnimationClips] = useState<AnimationClip[]>([]);
|
||||
const [audioClips, setAudioClips] = useState<AudioClip[]>([]);
|
||||
const [animationClips, setAnimationClips] = useState<MediaClip[]>([]);
|
||||
const [audioClips, setAudioClips] = useState<MediaClip[]>([]);
|
||||
|
||||
const [scale, setScale] = useState(1);
|
||||
const [length, setLength] = useState(1);
|
||||
@@ -74,26 +75,30 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
useEffect(() => {
|
||||
setAnimationClips([
|
||||
{
|
||||
id: "ani-id1",
|
||||
offset: 0,
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
type: ClipType.ANIMATION,
|
||||
length: 25,
|
||||
name: "Sit",
|
||||
},
|
||||
{
|
||||
id: "ani-id2",
|
||||
offset: 0,
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
type: ClipType.ANIMATION,
|
||||
length: 25,
|
||||
name: "Idle",
|
||||
},
|
||||
{
|
||||
id: "ani-id3",
|
||||
offset: 0,
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
type: ClipType.ANIMATION,
|
||||
length: 25,
|
||||
name: "Stand",
|
||||
},
|
||||
{
|
||||
id: "ani-id4",
|
||||
offset: 0,
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
type: ClipType.ANIMATION,
|
||||
length: 25,
|
||||
name: "Walk",
|
||||
},
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { AudioGroup, BaseClip } from "~/pages/PageEnigma/models/track";
|
||||
import {
|
||||
AudioGroup,
|
||||
Clip,
|
||||
ClipGroup,
|
||||
ClipType,
|
||||
MediaClip,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
|
||||
import * as uuid from "uuid";
|
||||
|
||||
export default function useUpdateAudio() {
|
||||
const [audio, setAudio] = useState<AudioGroup>({
|
||||
id: "AU1",
|
||||
muted: false,
|
||||
clips: [
|
||||
{
|
||||
id: "AU1-1",
|
||||
length: 200,
|
||||
offset: 0,
|
||||
name: "audio 1",
|
||||
},
|
||||
{
|
||||
id: "AU1-2",
|
||||
length: 180,
|
||||
offset: 300,
|
||||
name: "audio 2",
|
||||
},
|
||||
],
|
||||
clips: [],
|
||||
});
|
||||
|
||||
const updateAudio = useCallback(
|
||||
@@ -33,44 +30,56 @@ export default function useUpdateAudio() {
|
||||
}) => {
|
||||
setAudio((oldAudio) => {
|
||||
const newClips = [...oldAudio.clips];
|
||||
const clipIndex = newClips.findIndex((row) => row.id === id);
|
||||
const clipIndex = newClips.findIndex((row) => row.clip_uuid === id);
|
||||
if (clipIndex === -1) {
|
||||
return { ...oldAudio };
|
||||
}
|
||||
const clip = newClips[clipIndex];
|
||||
clip.offset = offset;
|
||||
clip.length = length;
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.UPDATE_CLIP,
|
||||
data: clip,
|
||||
});
|
||||
|
||||
return {
|
||||
...oldAudio,
|
||||
clips: newClips,
|
||||
};
|
||||
});
|
||||
console.log("message", {
|
||||
action: "UpdateGlobalAudio",
|
||||
id,
|
||||
data: { offset, length },
|
||||
});
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const addGlobalAudio = useCallback(
|
||||
(dragId: string, audioClips: BaseClip[], offset: number) => {
|
||||
const clip = audioClips.find((row) => row.id === dragId);
|
||||
(dragId: string, audioClips: MediaClip[], offset: number) => {
|
||||
const clip = audioClips.find((row) => row.media_id === dragId);
|
||||
if (!clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clip_uuid = uuid.v4();
|
||||
const newClip = {
|
||||
...clip,
|
||||
type: ClipType.AUDIO,
|
||||
group: ClipGroup.GLOBAL_AUDIO,
|
||||
offset,
|
||||
clip_uuid,
|
||||
} as Clip;
|
||||
|
||||
setAudio((oldAudio) => {
|
||||
return {
|
||||
...oldAudio,
|
||||
clips: [...oldAudio.clips, { ...clip, offset }],
|
||||
clips: [...oldAudio.clips, newClip],
|
||||
};
|
||||
});
|
||||
console.log("message", {
|
||||
action: "UpdateGlobalAudio",
|
||||
id: dragId,
|
||||
data: { offset },
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.ADD_CLIP,
|
||||
data: newClip,
|
||||
});
|
||||
},
|
||||
[],
|
||||
@@ -78,15 +87,21 @@ export default function useUpdateAudio() {
|
||||
|
||||
const toggleAudioMute = useCallback(() => {
|
||||
setAudio((oldAudio) => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: oldAudio?.muted ? toEngineActions.UNMUTE : toEngineActions.MUTE,
|
||||
data: {
|
||||
version: 1,
|
||||
type: ClipType.AUDIO,
|
||||
group: ClipGroup.GLOBAL_AUDIO,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...oldAudio,
|
||||
muted: !oldAudio.muted,
|
||||
};
|
||||
});
|
||||
console.log("message", {
|
||||
action: "ToggleGlobalAudioMute",
|
||||
id: "",
|
||||
});
|
||||
}, []);
|
||||
|
||||
const selectAudioClip = useCallback((clipId: string) => {
|
||||
@@ -97,7 +112,8 @@ export default function useUpdateAudio() {
|
||||
...oldAudio.clips.map((clip) => {
|
||||
return {
|
||||
...clip,
|
||||
selected: clip.id === clipId ? !clip.selected : clip.selected,
|
||||
selected:
|
||||
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
|
||||
};
|
||||
}),
|
||||
],
|
||||
@@ -109,13 +125,21 @@ export default function useUpdateAudio() {
|
||||
setAudio((oldAudio) => {
|
||||
return {
|
||||
...oldAudio,
|
||||
clips: [...oldAudio.clips.filter((clip) => clip.id !== clipId)],
|
||||
clips: [
|
||||
...oldAudio.clips.filter((clip) => {
|
||||
if (clip.clip_uuid === clipId) {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.DELETE_CLIP,
|
||||
data: clip!,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
],
|
||||
};
|
||||
});
|
||||
console.log("message", {
|
||||
action: "UpdateGlobalAudio",
|
||||
id: clipId,
|
||||
});
|
||||
}, []);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { CameraGroup } from "~/pages/PageEnigma/models/track";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
|
||||
|
||||
export default function useUpdateCamera() {
|
||||
const [camera, setCamera] = useState<CameraGroup>({
|
||||
id: "CA1",
|
||||
clips: [
|
||||
{
|
||||
id: "CA1-1",
|
||||
length: 200,
|
||||
offset: 0,
|
||||
name: "cam 1",
|
||||
},
|
||||
{
|
||||
id: "CA1-2",
|
||||
length: 180,
|
||||
offset: 300,
|
||||
name: "cam 2",
|
||||
},
|
||||
],
|
||||
clips: [],
|
||||
});
|
||||
|
||||
const updateCamera = useCallback(
|
||||
@@ -32,13 +22,20 @@ export default function useUpdateCamera() {
|
||||
}) => {
|
||||
setCamera((oldCamera) => {
|
||||
const newClips = [...oldCamera.clips];
|
||||
const clipIndex = newClips.findIndex((row) => row.id === id);
|
||||
const clipIndex = newClips.findIndex((row) => row.clip_uuid === id);
|
||||
if (clipIndex === -1) {
|
||||
return { ...oldCamera };
|
||||
}
|
||||
const clip = newClips[clipIndex];
|
||||
clip.offset = offset;
|
||||
clip.length = length;
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.UPDATE_CLIP,
|
||||
data: clip,
|
||||
});
|
||||
|
||||
return {
|
||||
...oldCamera,
|
||||
clips: newClips,
|
||||
@@ -56,7 +53,8 @@ export default function useUpdateCamera() {
|
||||
...oldCamera.clips.map((clip) => {
|
||||
return {
|
||||
...clip,
|
||||
selected: clip.id === clipId ? !clip.selected : clip.selected,
|
||||
selected:
|
||||
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
|
||||
};
|
||||
}),
|
||||
],
|
||||
@@ -68,7 +66,19 @@ export default function useUpdateCamera() {
|
||||
setCamera((oldCamera) => {
|
||||
return {
|
||||
...oldCamera,
|
||||
clips: [...oldCamera.clips.filter((clip) => clip.id !== clipId)],
|
||||
clips: [
|
||||
...oldCamera.clips.filter((clip) => {
|
||||
if (clip.clip_uuid === clipId) {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.DELETE_CLIP,
|
||||
data: clip!,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
],
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { BaseClip, CharacterGroup } from "~/pages/PageEnigma/models/track";
|
||||
import {
|
||||
Clip,
|
||||
CharacterGroup,
|
||||
ClipGroup,
|
||||
ClipType,
|
||||
MediaClip,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
import * as uuid from "uuid";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
@@ -12,16 +18,10 @@ export default function useUpdateCharacters() {
|
||||
muted: false,
|
||||
animationClips: [],
|
||||
positionClips: [],
|
||||
lipSyncClips: [
|
||||
{
|
||||
id: "CH1-L1",
|
||||
length: 400,
|
||||
offset: 150,
|
||||
name: "sync 1",
|
||||
},
|
||||
],
|
||||
lipSyncClips: [],
|
||||
},
|
||||
]);
|
||||
|
||||
const updateCharacters = useCallback(
|
||||
({
|
||||
type,
|
||||
@@ -39,7 +39,7 @@ export default function useUpdateCharacters() {
|
||||
return oldCharacters.map((character) => {
|
||||
const newAnimationClips = [...character.animationClips];
|
||||
const clipIndex = newAnimationClips.findIndex(
|
||||
(row) => row.id === id,
|
||||
(row) => row.clip_uuid === id,
|
||||
);
|
||||
if (clipIndex === -1) {
|
||||
return { ...character };
|
||||
@@ -47,25 +47,28 @@ export default function useUpdateCharacters() {
|
||||
const clip = newAnimationClips[clipIndex];
|
||||
clip.offset = offset;
|
||||
clip.length = length;
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.UPDATE_CLIP,
|
||||
data: clip,
|
||||
});
|
||||
|
||||
return {
|
||||
...character,
|
||||
animationClips: newAnimationClips,
|
||||
};
|
||||
});
|
||||
});
|
||||
console.log("message", {
|
||||
action: "UpdateAnimation",
|
||||
id,
|
||||
data: { offset, length },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "positions") {
|
||||
setCharacters((oldCharacters) => {
|
||||
return oldCharacters.map((character) => {
|
||||
const newPositionClips = [...character.positionClips];
|
||||
const clipIndex = newPositionClips.findIndex(
|
||||
(row) => row.id === id,
|
||||
(row) => row.clip_uuid === id,
|
||||
);
|
||||
if (clipIndex === -1) {
|
||||
return { ...character };
|
||||
@@ -73,6 +76,13 @@ export default function useUpdateCharacters() {
|
||||
const clip = newPositionClips[clipIndex];
|
||||
clip.offset = offset;
|
||||
clip.length = length;
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.UPDATE_CLIP,
|
||||
data: clip,
|
||||
});
|
||||
|
||||
return {
|
||||
...character,
|
||||
positionClips: newPositionClips,
|
||||
@@ -85,24 +95,28 @@ export default function useUpdateCharacters() {
|
||||
setCharacters((oldCharacters) => {
|
||||
return oldCharacters.map((character) => {
|
||||
const newLipSyncClips = [...character.lipSyncClips];
|
||||
const clipIndex = newLipSyncClips.findIndex((row) => row.id === id);
|
||||
const clipIndex = newLipSyncClips.findIndex(
|
||||
(row) => row.clip_uuid === id,
|
||||
);
|
||||
if (clipIndex === -1) {
|
||||
return { ...character };
|
||||
}
|
||||
const clip = newLipSyncClips[clipIndex];
|
||||
clip.offset = offset;
|
||||
clip.length = length;
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.UPDATE_CLIP,
|
||||
data: clip,
|
||||
});
|
||||
|
||||
return {
|
||||
...character,
|
||||
lipSyncClips: newLipSyncClips,
|
||||
};
|
||||
});
|
||||
});
|
||||
console.log("message", {
|
||||
action: "UpdateLipSync",
|
||||
id,
|
||||
data: { offset, length },
|
||||
});
|
||||
}
|
||||
},
|
||||
[],
|
||||
@@ -117,14 +131,23 @@ export default function useUpdateCharacters() {
|
||||
}: {
|
||||
clipId: string;
|
||||
characterId: string;
|
||||
animationClips: BaseClip[];
|
||||
animationClips: MediaClip[];
|
||||
offset: number;
|
||||
}) => {
|
||||
const clip = animationClips.find((row) => row.id === clipId);
|
||||
const clip = animationClips.find((row) => row.media_id === clipId);
|
||||
if (!clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clip_uuid = uuid.v4();
|
||||
const newClip = {
|
||||
...clip,
|
||||
group: ClipGroup.CHARACTER,
|
||||
offset,
|
||||
clip_uuid,
|
||||
object_uuid: characterId,
|
||||
} as Clip;
|
||||
|
||||
setCharacters((oldCharacters) => {
|
||||
return oldCharacters.map((character) => {
|
||||
if (character.id !== characterId) {
|
||||
@@ -132,20 +155,17 @@ export default function useUpdateCharacters() {
|
||||
}
|
||||
return {
|
||||
...character,
|
||||
animationClips: [
|
||||
...character.animationClips,
|
||||
{ ...clip, id: uuid.v4(), offset },
|
||||
].sort((clipA, clipB) => clipA.offset - clipB.offset),
|
||||
animationClips: [...character.animationClips, newClip].sort(
|
||||
(clipA, clipB) => clipA.offset - clipB.offset,
|
||||
),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.ADD_ANIMATION,
|
||||
data: {
|
||||
clipId,
|
||||
offset,
|
||||
},
|
||||
action: toEngineActions.ADD_CLIP,
|
||||
data: newClip,
|
||||
});
|
||||
},
|
||||
[],
|
||||
@@ -160,14 +180,24 @@ export default function useUpdateCharacters() {
|
||||
}: {
|
||||
clipId: string;
|
||||
characterId: string;
|
||||
audioClips: BaseClip[];
|
||||
audioClips: MediaClip[];
|
||||
offset: number;
|
||||
}) => {
|
||||
const clip = audioClips.find((row) => row.id === clipId);
|
||||
const clip = audioClips.find((row) => row.media_id === clipId);
|
||||
if (!clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clip_uuid = uuid.v4();
|
||||
const newClip = {
|
||||
...clip,
|
||||
type: ClipType.AUDIO,
|
||||
group: ClipGroup.CHARACTER,
|
||||
offset,
|
||||
clip_uuid,
|
||||
object_uuid: characterId,
|
||||
} as Clip;
|
||||
|
||||
setCharacters((oldCharacters) => {
|
||||
return oldCharacters.map((character) => {
|
||||
if (character.id !== characterId) {
|
||||
@@ -175,17 +205,17 @@ export default function useUpdateCharacters() {
|
||||
}
|
||||
return {
|
||||
...character,
|
||||
lipSyncClips: [
|
||||
...character.lipSyncClips,
|
||||
{ ...clip, id: uuid.v4(), offset },
|
||||
].sort((clipA, clipB) => clipA.offset - clipB.offset),
|
||||
lipSyncClips: [...character.lipSyncClips, newClip].sort(
|
||||
(clipA, clipB) => clipA.offset - clipB.offset,
|
||||
),
|
||||
};
|
||||
});
|
||||
});
|
||||
console.log("message", {
|
||||
action: "AddLipSync",
|
||||
id: clipId,
|
||||
data: { offset },
|
||||
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.ADD_CLIP,
|
||||
data: newClip,
|
||||
});
|
||||
},
|
||||
[],
|
||||
@@ -193,15 +223,28 @@ export default function useUpdateCharacters() {
|
||||
|
||||
const toggleLipSyncMute = useCallback((characterId: string) => {
|
||||
setCharacters((oldCharacters) => {
|
||||
return oldCharacters.map((character) => ({
|
||||
...character,
|
||||
muted:
|
||||
character.id === characterId ? !character.muted : character.muted,
|
||||
}));
|
||||
});
|
||||
console.log("message", {
|
||||
action: "ToggleLipSync",
|
||||
id: characterId,
|
||||
return oldCharacters.map((character) => {
|
||||
if (character.id === characterId) {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: character?.muted
|
||||
? toEngineActions.UNMUTE
|
||||
: toEngineActions.MUTE,
|
||||
data: {
|
||||
version: 1,
|
||||
type: ClipType.AUDIO,
|
||||
group: ClipGroup.CHARACTER,
|
||||
object_uuid: characterId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...character,
|
||||
muted:
|
||||
character.id === characterId ? !character.muted : character.muted,
|
||||
};
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -212,15 +255,18 @@ export default function useUpdateCharacters() {
|
||||
...character,
|
||||
animationClips: character.animationClips.map((clip) => ({
|
||||
...clip,
|
||||
selected: clip.id === clipId ? !clip.selected : clip.selected,
|
||||
selected:
|
||||
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
|
||||
})),
|
||||
positionClips: character.positionClips.map((clip) => ({
|
||||
...clip,
|
||||
selected: clip.id === clipId ? !clip.selected : clip.selected,
|
||||
selected:
|
||||
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
|
||||
})),
|
||||
lipSyncClips: character.lipSyncClips.map((clip) => ({
|
||||
...clip,
|
||||
selected: clip.id === clipId ? !clip.selected : clip.selected,
|
||||
selected:
|
||||
clip.clip_uuid === clipId ? !clip.selected : clip.selected,
|
||||
})),
|
||||
})),
|
||||
];
|
||||
@@ -232,22 +278,42 @@ export default function useUpdateCharacters() {
|
||||
return [
|
||||
...oldCharacters.map((character) => ({
|
||||
...character,
|
||||
animationClips: character.animationClips.filter(
|
||||
(clip) => clip.id !== clipId,
|
||||
),
|
||||
positionClips: character.positionClips.filter(
|
||||
(clip) => clip.id !== clipId,
|
||||
),
|
||||
lipSyncClips: character.lipSyncClips.filter(
|
||||
(clip) => clip.id !== clipId,
|
||||
),
|
||||
animationClips: character.animationClips.filter((clip) => {
|
||||
if (clip.clip_uuid === clipId) {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.DELETE_CLIP,
|
||||
data: clip!,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
positionClips: character.positionClips.filter((clip) => {
|
||||
if (clip.clip_uuid === clipId) {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.DELETE_CLIP,
|
||||
data: clip!,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
lipSyncClips: character.lipSyncClips.filter((clip) => {
|
||||
if (clip.clip_uuid === clipId) {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_ENGINE,
|
||||
action: toEngineActions.DELETE_CLIP,
|
||||
data: clip!,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
})),
|
||||
];
|
||||
});
|
||||
console.log("message", {
|
||||
action: "DeleteCharacterClip",
|
||||
id: clipId,
|
||||
});
|
||||
}, []);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,11 +1,50 @@
|
||||
export interface BaseClip {
|
||||
id: string;
|
||||
export interface QueueClip {
|
||||
version: number;
|
||||
type: ClipType;
|
||||
group: ClipGroup;
|
||||
object_uuid?: string;
|
||||
clip_uuid?: string;
|
||||
media_id?: string;
|
||||
name?: string;
|
||||
offset?: number;
|
||||
length?: number;
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface MediaClip {
|
||||
version: number;
|
||||
type: ClipType;
|
||||
media_id: string;
|
||||
name: string;
|
||||
length: number;
|
||||
}
|
||||
|
||||
export interface Clip {
|
||||
version: number;
|
||||
clip_uuid: string;
|
||||
type: ClipType;
|
||||
group: ClipGroup;
|
||||
media_id: string;
|
||||
object_uuid?: string;
|
||||
name: string;
|
||||
offset: number;
|
||||
length: number;
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export enum ClipType {
|
||||
TRANSFORM = "transform",
|
||||
AUDIO = "audio",
|
||||
ANIMATION = "animation",
|
||||
}
|
||||
|
||||
export enum ClipGroup {
|
||||
CHARACTER = "character",
|
||||
CAMERA = "camera",
|
||||
GLOBAL_AUDIO = "global_audio",
|
||||
OBJECT = "object",
|
||||
}
|
||||
|
||||
export interface BaseKeyFrame {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -13,35 +52,25 @@ export interface BaseKeyFrame {
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface AnimationClip extends BaseClip {}
|
||||
|
||||
export interface PositionClip extends BaseClip {}
|
||||
|
||||
export interface LipSyncClip extends BaseClip {}
|
||||
|
||||
export interface CharacterGroup {
|
||||
id: string;
|
||||
muted: boolean;
|
||||
animationClips: AnimationClip[];
|
||||
positionClips: PositionClip[];
|
||||
lipSyncClips: LipSyncClip[];
|
||||
animationClips: Clip[];
|
||||
positionClips: Clip[];
|
||||
lipSyncClips: Clip[];
|
||||
}
|
||||
|
||||
export interface CameraGroup {
|
||||
id: string;
|
||||
clips: CameraClip[];
|
||||
clips: Clip[];
|
||||
}
|
||||
|
||||
export interface CameraClip extends BaseClip {}
|
||||
|
||||
export interface AudioGroup {
|
||||
id: string;
|
||||
muted: boolean;
|
||||
clips: AudioClip[];
|
||||
clips: Clip[];
|
||||
}
|
||||
|
||||
export interface AudioClip extends BaseClip {}
|
||||
|
||||
export interface ObjectGroup {
|
||||
id: string;
|
||||
objects: ObjectTrack[];
|
||||
|
||||
Reference in new issue
Block a user