From ce187874b4cf81ce08dd7d45bc882560609ef0f0 Mon Sep 17 00:00:00 2001 From: Christopher Oliphant Date: Mon, 8 Apr 2024 10:57:42 -0400 Subject: [PATCH] refactor --- app/pages/PageEnigma/store/audioGroup.ts | 18 ++ app/pages/PageEnigma/store/cameraGroup.ts | 16 ++ .../store/characterGroups/addCharacter.ts | 28 ++ .../store/characterGroups/characterGroups.ts | 239 ++++++++++++++++++ .../PageEnigma/store/characterGroups/index.ts | 4 + .../characterGroups/loadCharacterData.ts | 89 +++++++ .../store/characterGroups/updateCharacters.ts | 94 +++++++ app/pages/PageEnigma/store/media.ts | 8 +- .../PageEnigma/store/objectGroup/index.ts | 3 + .../store/objectGroup/loadObjectData.ts | 48 ++++ .../store/objectGroup/objectGroup.ts | 124 +++++++++ .../store/objectGroup/updateObjectGroup.ts | 59 +++++ 12 files changed, 726 insertions(+), 4 deletions(-) create mode 100644 app/pages/PageEnigma/store/characterGroups/addCharacter.ts create mode 100644 app/pages/PageEnigma/store/characterGroups/characterGroups.ts create mode 100644 app/pages/PageEnigma/store/characterGroups/index.ts create mode 100644 app/pages/PageEnigma/store/characterGroups/loadCharacterData.ts create mode 100644 app/pages/PageEnigma/store/characterGroups/updateCharacters.ts create mode 100644 app/pages/PageEnigma/store/objectGroup/index.ts create mode 100644 app/pages/PageEnigma/store/objectGroup/loadObjectData.ts create mode 100644 app/pages/PageEnigma/store/objectGroup/objectGroup.ts create mode 100644 app/pages/PageEnigma/store/objectGroup/updateObjectGroup.ts diff --git a/app/pages/PageEnigma/store/audioGroup.ts b/app/pages/PageEnigma/store/audioGroup.ts index 9a6d7fc2dd..630778507c 100644 --- a/app/pages/PageEnigma/store/audioGroup.ts +++ b/app/pages/PageEnigma/store/audioGroup.ts @@ -10,6 +10,7 @@ import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; import * as uuid from "uuid"; import { signal } from "@preact/signals-core"; +import { ClipUI } from "~/pages/PageEnigma/datastructures/clips/clip_ui"; export const audioGroup = signal({ id: "AG-1", @@ -140,3 +141,20 @@ export function deleteAudioClip(clip: Clip) { ], }; } + +export function loadAudioData(item: ClipUI) { + const existingAudio = audioGroup.value; + const newItem = { + version: item.version, + clip_uuid: item.clip_uuid, + type: item.type, + group: item.group, + object_uuid: item.object_uuid, + media_id: item.media_id, + name: item.name, + offset: item.offset, + length: item.length, + } as Clip; + existingAudio.clips.push(newItem); + existingAudio.clips.sort((clipA, clipB) => clipA.offset - clipB.offset); +} diff --git a/app/pages/PageEnigma/store/cameraGroup.ts b/app/pages/PageEnigma/store/cameraGroup.ts index 029a8b6810..72bf56aad1 100644 --- a/app/pages/PageEnigma/store/cameraGroup.ts +++ b/app/pages/PageEnigma/store/cameraGroup.ts @@ -8,6 +8,7 @@ import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; import * as uuid from "uuid"; import { signal } from "@preact/signals-core"; +import { ClipUI } from "~/pages/PageEnigma/datastructures/clips/clip_ui"; // import { toast } from "react-hot-toast"; export const cameraGroup = signal({ id: "CG1", keyframes: [] }); @@ -112,3 +113,18 @@ export function deleteCameraKeyframe(deleteKeyframe: Keyframe) { ], }; } + +export function loadCameraData(item: ClipUI) { + const existingCamera = cameraGroup.value; + const newKeyframe = { + version: item.version, + keyframe_uuid: item.clip_uuid, + group: item.group, + object_uuid: item.object_uuid, + offset: item.keyframe_offset, + } as Keyframe; + existingCamera.keyframes.push(newKeyframe); + existingCamera.keyframes.sort( + (keyframeA, keyframeB) => keyframeA.offset - keyframeB.offset, + ); +} diff --git a/app/pages/PageEnigma/store/characterGroups/addCharacter.ts b/app/pages/PageEnigma/store/characterGroups/addCharacter.ts new file mode 100644 index 0000000000..c68a300002 --- /dev/null +++ b/app/pages/PageEnigma/store/characterGroups/addCharacter.ts @@ -0,0 +1,28 @@ +import { CharacterGroup, MediaItem } from "~/pages/PageEnigma/models"; +import Queue from "~/pages/PageEnigma/Queue/Queue"; +import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; +import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; +import { characterGroups } from "~/pages/PageEnigma/store"; + +export function addCharacter(character: MediaItem) { + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.ADD_CHARACTER, + data: character, + }); +} + +export function addNewCharacter(data: MediaItem) { + const newCharacter = { + id: data.object_uuid, + name: data.name, + muted: false, + animationClips: [], + positionKeyframes: [], + lipSyncClips: [], + } as CharacterGroup; + + characterGroups.value = [...characterGroups.value, newCharacter].sort( + (charA, charB) => (charA.id < charB.id ? -1 : 1), + ); +} diff --git a/app/pages/PageEnigma/store/characterGroups/characterGroups.ts b/app/pages/PageEnigma/store/characterGroups/characterGroups.ts new file mode 100644 index 0000000000..b7be79cfc1 --- /dev/null +++ b/app/pages/PageEnigma/store/characterGroups/characterGroups.ts @@ -0,0 +1,239 @@ +import { + CharacterGroup, + Clip, + ClipGroup, + ClipType, + Keyframe, + MediaItem, + QueueKeyframe, +} from "~/pages/PageEnigma/models"; +import { signal } from "@preact/signals-core"; +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 const characterGroups = signal([]); + +export function addCharacterAnimation({ + dragItem, + characterId, + offset, +}: { + dragItem: MediaItem; + characterId: string; + offset: number; +}) { + const clip_uuid = uuid.v4(); + const newClip = { + version: 1, + media_id: dragItem.media_id, + group: ClipGroup.CHARACTER, + type: ClipType.ANIMATION, + offset, + length: dragItem.length, + clip_uuid, + name: dragItem.name, + object_uuid: characterId, + } as Clip; + + const oldCharacterGroups = characterGroups.value; + characterGroups.value = oldCharacterGroups.map((character) => { + if (character.id !== characterId) { + return { ...character }; + } + return { + ...character, + animationClips: [...character.animationClips, newClip].sort( + (clipA, clipB) => clipA.offset - clipB.offset, + ), + }; + }); + + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.ADD_CLIP, + data: newClip, + }); +} + +export function addCharacterAudio({ + dragItem, + characterId, + offset, +}: { + dragItem: MediaItem; + characterId: string; + offset: number; +}) { + const clip_uuid = uuid.v4(); + const newClip = { + version: 1, + media_id: dragItem.media_id, + group: ClipGroup.CHARACTER, + type: ClipType.AUDIO, + offset, + length: dragItem.length, + clip_uuid, + object_uuid: characterId, + name: dragItem.name, + } as Clip; + + const oldCharacterGroups = characterGroups.value; + characterGroups.value = oldCharacterGroups.map((character) => { + if (character.id !== characterId) { + return { ...character }; + } + + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.ADD_CLIP, + data: newClip, + }); + + return { + ...character, + lipSyncClips: [...character.lipSyncClips, newClip].sort( + (clipA, clipB) => clipA.offset - clipB.offset, + ), + }; + }); +} + +export function addCharacterKeyframe(keyframe: QueueKeyframe, offset: number) { + const oldCharacterGroups = characterGroups.value; + + if ( + oldCharacterGroups.some((characterGroup) => { + return characterGroup.positionKeyframes.some( + (row) => row.offset === offset, + ); + }) + ) { + return; + } + + const newKeyframe = { + version: keyframe.version, + keyframe_uuid: uuid.v4(), + group: keyframe.group, + object_uuid: keyframe.object_uuid, + offset, + position: keyframe.position, + rotation: keyframe.rotation, + scale: keyframe.scale, + selected: false, + } as Keyframe; + + characterGroups.value = oldCharacterGroups.map((character) => { + if (character.id !== keyframe.object_uuid) { + return { ...character }; + } + return { + ...character, + positionKeyframes: [...character.positionKeyframes, newKeyframe].sort( + (keyFrameA, keyframeB) => keyFrameA.offset - keyframeB.offset, + ), + }; + }); + + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.ADD_KEYFRAME, + data: newKeyframe, + }); +} + +export function toggleLipSyncMute(characterId: string) { + const oldCharacterGroups = characterGroups.value; + characterGroups.value = oldCharacterGroups.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, + }; + }); +} + +export function selectCharacterClip(clipId: string) { + const oldCharacterGroups = characterGroups.value; + characterGroups.value = oldCharacterGroups.map((character) => ({ + ...character, + animationClips: character.animationClips.map((clip) => ({ + ...clip, + selected: clip.clip_uuid === clipId ? !clip.selected : clip.selected, + })), + positionClips: character.positionKeyframes.map((keyframe) => ({ + ...keyframe, + selected: + keyframe.keyframe_uuid === clipId + ? !keyframe.selected + : keyframe.selected, + })), + lipSyncClips: character.lipSyncClips.map((clip) => ({ + ...clip, + selected: clip.clip_uuid === clipId ? !clip.selected : clip.selected, + })), + })); +} + +export function deleteCharacterClip(clip: Clip) { + const oldCharacterGroups = characterGroups.value; + characterGroups.value = oldCharacterGroups.map((character) => ({ + ...character, + animationClips: character.animationClips.filter((row) => { + if (row.clip_uuid === clip.clip_uuid) { + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.DELETE_CLIP, + data: row, + }); + return false; + } + return true; + }), + lipSyncClips: character.lipSyncClips.filter((row) => { + if (row.clip_uuid === clip.clip_uuid) { + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.DELETE_CLIP, + data: row, + }); + return false; + } + return true; + }), + })); +} + +export function deleteCharacterKeyframe(keyframe: Keyframe) { + const oldCharacterGroups = characterGroups.value; + characterGroups.value = oldCharacterGroups.map((character) => ({ + ...character, + positionClips: character.positionKeyframes.filter((row) => { + if (row.keyframe_uuid === keyframe.keyframe_uuid) { + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.DELETE_KEYFRAME, + data: row, + }); + return false; + } + return true; + }), + })); +} diff --git a/app/pages/PageEnigma/store/characterGroups/index.ts b/app/pages/PageEnigma/store/characterGroups/index.ts new file mode 100644 index 0000000000..eb200150c0 --- /dev/null +++ b/app/pages/PageEnigma/store/characterGroups/index.ts @@ -0,0 +1,4 @@ +export * from "./addCharacter"; +export * from "./characterGroups"; +export * from "./loadCharacterData"; +export * from "./updateCharacters"; diff --git a/app/pages/PageEnigma/store/characterGroups/loadCharacterData.ts b/app/pages/PageEnigma/store/characterGroups/loadCharacterData.ts new file mode 100644 index 0000000000..db7722abe1 --- /dev/null +++ b/app/pages/PageEnigma/store/characterGroups/loadCharacterData.ts @@ -0,0 +1,89 @@ +import { ClipUI } from "~/pages/PageEnigma/datastructures/clips/clip_ui"; +import { + CharacterGroup, + Clip, + ClipType, + Keyframe, +} from "~/pages/PageEnigma/models"; +import { characterGroups } from "~/pages/PageEnigma/store"; + +function getAddCharacter(item: ClipUI) { + const existingCharacter = characterGroups.value.find( + (character) => character.id === item.object_uuid, + ); + + if (existingCharacter) { + return existingCharacter; + } + + const newCharacter = { + id: item.object_uuid, + name: item.object_name, + muted: false, + animationClips: [], + positionKeyframes: [], + lipSyncClips: [], + } as CharacterGroup; + + characterGroups.value = [ + ...characterGroups.value.filter( + (character) => character.id !== item.object_uuid, + ), + newCharacter, + ].sort((charA, charB) => (charA.id < charB.id ? -1 : 1)); + + return characterGroups.value.find( + (character) => character.id === item.object_uuid, + ) as CharacterGroup; +} + +export function loadCharacterData(item: ClipUI) { + const existingCharacter = getAddCharacter(item); + if (item.type === ClipType.ANIMATION) { + const newItem = { + version: item.version, + clip_uuid: item.clip_uuid, + type: item.type, + group: item.group, + object_uuid: item.object_uuid, + media_id: item.media_id, + name: item.name, + offset: item.offset, + length: item.length, + } as Clip; + existingCharacter.animationClips.push(newItem); + existingCharacter.animationClips.sort( + (clipA, clipB) => clipA.offset - clipB.offset, + ); + } + if (item.type === ClipType.TRANSFORM) { + const newKeyframe = { + version: item.version, + keyframe_uuid: item.clip_uuid, + group: item.group, + object_uuid: item.object_uuid, + offset: item.keyframe_offset, + } as Keyframe; + existingCharacter.positionKeyframes.push(newKeyframe); + existingCharacter.positionKeyframes.sort( + (keyframeA, keyframeB) => keyframeA.offset - keyframeB.offset, + ); + } + if (item.type === ClipType.AUDIO) { + const newItem = { + version: item.version, + clip_uuid: item.clip_uuid, + type: item.type, + group: item.group, + object_uuid: item.object_uuid, + media_id: item.media_id, + name: item.name, + offset: item.offset, + length: item.length, + } as Clip; + existingCharacter.lipSyncClips.push(newItem); + existingCharacter.lipSyncClips.sort( + (clipA, clipB) => clipA.offset - clipB.offset, + ); + } +} diff --git a/app/pages/PageEnigma/store/characterGroups/updateCharacters.ts b/app/pages/PageEnigma/store/characterGroups/updateCharacters.ts new file mode 100644 index 0000000000..93de4af12a --- /dev/null +++ b/app/pages/PageEnigma/store/characterGroups/updateCharacters.ts @@ -0,0 +1,94 @@ +import { ClipType } from "~/pages/PageEnigma/models"; +import Queue from "~/pages/PageEnigma/Queue/Queue"; +import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; +import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; +import { characterGroups } from "~/pages/PageEnigma/store"; + +export function updateCharacters({ + type, + id, + offset, + length, +}: { + type: ClipType; + id: string; + length?: number; + offset: number; +}) { + const oldCharacterGroups = characterGroups.value; + if (type === ClipType.ANIMATION) { + characterGroups.value = oldCharacterGroups.map((character) => { + const newAnimationClips = [...character.animationClips]; + const clipIndex = newAnimationClips.findIndex( + (row) => row.clip_uuid === id, + ); + if (clipIndex === -1) { + return { ...character }; + } + 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, + }; + }); + } + + if (type === ClipType.TRANSFORM) { + characterGroups.value = oldCharacterGroups.map((character) => { + const newPositionKeyframes = [...character.positionKeyframes]; + const keyframeIndex = newPositionKeyframes.findIndex( + (row) => row.keyframe_uuid === id, + ); + if (keyframeIndex === -1) { + return { ...character }; + } + const keyframe = newPositionKeyframes[keyframeIndex]; + keyframe.offset = offset; + + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.UPDATE_CLIP, + data: keyframe, + }); + + return { + ...character, + positionKeyframes: newPositionKeyframes, + }; + }); + } + if (type === ClipType.AUDIO) { + characterGroups.value = oldCharacterGroups.map((character) => { + const newLipSyncClips = [...character.lipSyncClips]; + 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, + }; + }); + } +} diff --git a/app/pages/PageEnigma/store/media.ts b/app/pages/PageEnigma/store/media.ts index f1579cd77b..b1eee9e62f 100644 --- a/app/pages/PageEnigma/store/media.ts +++ b/app/pages/PageEnigma/store/media.ts @@ -94,7 +94,7 @@ export const cameraItems = signal([ export const characterItems = signal([ { version: 1, - media_id: "", + media_id: "m_fmxy8wjnep1hdaz7qdg4n7y15d2bsp", type: AssetType.CHARACTER, name: "Shrek", thumbnail: "resources/placeholders/placeholder.png", @@ -122,7 +122,7 @@ export const characterItems = signal([ }, { version: 1, - media_id: "m_fmxy8wjnep1hdaz7qdg4n7y15d2bsp ", + media_id: "m_4wva09qznapzk5rcvbxy671d1qx2pr ", type: AssetType.CHARACTER, name: "Story Girl", thumbnail: "resources/characters/img13.png", @@ -132,9 +132,9 @@ export const characterItems = signal([ export const objectItems = signal([ { version: 1, - media_id: "m_w5nn3kjh1fbkmjrdac5b2qaba0pmyt", + media_id: "m_0xfrmekc56satjxn66wt6c9dkw7dxe", type: AssetType.OBJECT, - name: "Item ( Place Holder D.N.W )", + name: "Pikachu Statue", thumbnail: "resources/placeholders/placeholder.png", }, ]); diff --git a/app/pages/PageEnigma/store/objectGroup/index.ts b/app/pages/PageEnigma/store/objectGroup/index.ts new file mode 100644 index 0000000000..43c1cdb480 --- /dev/null +++ b/app/pages/PageEnigma/store/objectGroup/index.ts @@ -0,0 +1,3 @@ +export * from "./loadObjectData"; +export * from "./objectGroup"; +export * from "./updateObjectGroup"; diff --git a/app/pages/PageEnigma/store/objectGroup/loadObjectData.ts b/app/pages/PageEnigma/store/objectGroup/loadObjectData.ts new file mode 100644 index 0000000000..8831681799 --- /dev/null +++ b/app/pages/PageEnigma/store/objectGroup/loadObjectData.ts @@ -0,0 +1,48 @@ +import { ClipUI } from "~/pages/PageEnigma/datastructures/clips/clip_ui"; +import { Keyframe, ObjectTrack } from "~/pages/PageEnigma/models"; +import { objectGroup } from "~/pages/PageEnigma/store"; + +function getAddObject(item: ClipUI) { + const existingObject = objectGroup.value.objects.find( + (obj) => obj.object_uuid === item.object_uuid, + ); + + if (existingObject) { + return existingObject; + } + + const newObject = { + object_uuid: item.object_uuid, + name: item.object_name, + keyframes: [] as Keyframe[], + } as ObjectTrack; + + objectGroup.value = { + id: "OB1", + objects: [ + ...objectGroup.value.objects.filter( + (obj) => obj.object_uuid !== item.object_uuid, + ), + newObject, + ].sort((objA, objB) => (objA.object_uuid < objB.object_uuid ? -1 : 1)), + }; + + return objectGroup.value.objects.find( + (obj) => obj.object_uuid === item.object_uuid, + ) as ObjectTrack; +} + +export function loadObjectData(item: ClipUI) { + const existingObject = getAddObject(item); + const newKeyframe = { + version: item.version, + keyframe_uuid: item.clip_uuid, + group: item.group, + object_uuid: item.object_uuid, + offset: item.keyframe_offset, + } as Keyframe; + existingObject.keyframes.push(newKeyframe); + existingObject.keyframes.sort( + (keyframeA, keyframeB) => keyframeA.offset - keyframeB.offset, + ); +} diff --git a/app/pages/PageEnigma/store/objectGroup/objectGroup.ts b/app/pages/PageEnigma/store/objectGroup/objectGroup.ts new file mode 100644 index 0000000000..80b4b8118f --- /dev/null +++ b/app/pages/PageEnigma/store/objectGroup/objectGroup.ts @@ -0,0 +1,124 @@ +import { signal } from "@preact/signals-core"; +import { + Keyframe, + MediaItem, + ObjectGroup, + ObjectTrack, + QueueKeyframe, +} from "~/pages/PageEnigma/models"; +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"; +import { ClipUI } from "~/pages/PageEnigma/datastructures/clips/clip_ui"; +// import { toast } from "react-hot-toast"; + +export const objectGroup = signal({ + id: "OB1", + objects: [], +}); + +export function addObjectKeyframe(keyframe: QueueKeyframe, offset: number) { + const oldObjectGroup = objectGroup.value; + const obj = oldObjectGroup.objects.find( + (row) => row.object_uuid === keyframe.object_uuid, + ); + + if (obj && obj.keyframes.some((row) => row.offset === offset)) { + //toast.error("There can only be one keyframe at this offset."); + return; + } + + const newObject = obj ?? { + object_uuid: keyframe.object_uuid, + name: keyframe.object_name ?? "unknown", + keyframes: [] as Keyframe[], + }; + const newKeyframe = { + version: keyframe.version, + keyframe_uuid: uuid.v4(), + group: keyframe.group, + object_uuid: keyframe.object_uuid, + offset, + position: keyframe.position, + rotation: keyframe.rotation, + scale: keyframe.scale, + selected: false, + } as Keyframe; + newObject.keyframes.push(newKeyframe); + + newObject.keyframes.sort( + (keyframeA, keyframeB) => keyframeA.offset - keyframeB.offset, + ); + + objectGroup.value = { + ...oldObjectGroup, + objects: [ + ...oldObjectGroup.objects.filter( + (row) => row.object_uuid !== obj?.object_uuid, + ), + newObject, + ].sort((objA, objB) => (objA.object_uuid < objB.object_uuid ? -1 : 1)), + }; + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.ADD_KEYFRAME, + data: newKeyframe, + }); +} + +export function deleteObjectKeyframe(keyframe: Keyframe) { + const oldObjectGroup = objectGroup.value; + const obj = oldObjectGroup.objects.find( + (row) => row.object_uuid === keyframe.object_uuid, + ); + console.log("delete", obj, keyframe.keyframe_uuid); + if (!obj) { + return oldObjectGroup; + } + + const newKeyframes = [ + ...obj.keyframes.filter((row) => { + if (row.keyframe_uuid === keyframe.keyframe_uuid) { + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.DELETE_KEYFRAME, + data: row, + }); + return false; + } + return true; + }), + ]; + + if (newKeyframes.length) { + objectGroup.value = { + ...oldObjectGroup, + objects: [ + ...oldObjectGroup.objects.map((object) => ({ + ...object, + ...(object.object_uuid === keyframe.object_uuid + ? { keyframes: newKeyframes } + : {}), + })), + ], + }; + return; + } + objectGroup.value = { + ...oldObjectGroup, + objects: [ + ...oldObjectGroup.objects.filter( + (object) => object.object_uuid !== keyframe.object_uuid, + ), + ], + }; +} + +export function addObject(object: MediaItem) { + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.ADD_OBJECT, + data: object, + }); +} diff --git a/app/pages/PageEnigma/store/objectGroup/updateObjectGroup.ts b/app/pages/PageEnigma/store/objectGroup/updateObjectGroup.ts new file mode 100644 index 0000000000..0db35259af --- /dev/null +++ b/app/pages/PageEnigma/store/objectGroup/updateObjectGroup.ts @@ -0,0 +1,59 @@ +import Queue from "~/pages/PageEnigma/Queue/Queue"; +import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; +import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; +import { objectGroup } from "~/pages/PageEnigma/store"; + +export function updateObject({ + id, + offset, +}: { + id: string; + offset: number; +}): void { + const oldObjectGroup = objectGroup.value; + const obj = oldObjectGroup.objects.find((objectTrack) => + objectTrack.keyframes.some((row) => row.keyframe_uuid === id), + ); + + if (!obj) { + return; + } + + const existingKeyframe = obj.keyframes.some((row) => { + return row.offset === offset && row.keyframe_uuid !== id; + }); + + if (existingKeyframe) { + //toast.error("There can only be one keyframe at this offset."); + return; + } + + objectGroup.value = { + id: oldObjectGroup.id, + objects: oldObjectGroup.objects.map((object) => ({ + object_uuid: object.object_uuid, + name: object.name, + keyframes: object.keyframes.map((keyframe) => { + if (keyframe.keyframe_uuid !== id) { + return { + ...keyframe, + }; + } + + Queue.publish({ + queueName: QueueNames.TO_ENGINE, + action: toEngineActions.UPDATE_KEYFRAME, + data: { + ...keyframe, + offset, + }, + }); + + return { + ...keyframe, + offset, + }; + }), + })), + }; +}