This commit is contained in:
Christopher Oliphant committed 2024-04-08 10:57:42 -04:00
1 parent 3e6a8e1120
commit ce187874b4
12 files changed
+726 -4

No files matched your search

+18
View File
@@ -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<AudioGroup>({
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);
}
+16
View File
@@ -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<CameraGroup>({ 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,
);
}
@@ -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),
);
}
@@ -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<CharacterGroup[]>([]);
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;
}),
}));
}
@@ -0,0 +1,4 @@
export * from "./addCharacter";
export * from "./characterGroups";
export * from "./loadCharacterData";
export * from "./updateCharacters";
@@ -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,
);
}
}
@@ -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,
};
});
}
}
+4 -4
View File
@@ -94,7 +94,7 @@ export const cameraItems = signal<MediaItem[]>([
export const characterItems = signal<MediaItem[]>([
{
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<MediaItem[]>([
},
{
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<MediaItem[]>([
export const objectItems = signal<MediaItem[]>([
{
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",
},
]);
@@ -0,0 +1,3 @@
export * from "./loadObjectData";
export * from "./objectGroup";
export * from "./updateObjectGroup";
@@ -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,
);
}
@@ -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<ObjectGroup>({
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,
});
}
@@ -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,
};
}),
})),
};
}