lingo3d
Version:
Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor
123 lines • 5.38 kB
JavaScript
import store, { createEffect } from "@lincode/reactivity";
import { merge, unset } from "@lincode/utils";
import { onTimelineClearKeyframe } from "../events/onTimelineClearKeyframe";
import { getTimelineLayer } from "./useTimelineLayer";
import { getTimeline } from "./useTimeline";
import { getTimelineRecord } from "./useTimelineRecord";
import { uuidMap } from "../collections/idCollections";
import getReactive from "../utils/getReactive";
import { onTransformControls } from "../events/onTransformControls";
import { onEditorEdit } from "../events/onEditorEdit";
import { timelineDataPtr } from "../pointers/timelineDataPtr";
import { addDisposeTimelineInstanceSystem, deleteDisposeTimelineInstanceSystem } from "../systems/eventSystems/disposeTimelineInstanceSystem";
import { timelinePtr } from "../pointers/timelinePtr";
import getTransformControlsData from "../display/utils/getTransformControlsData";
import { timelineFramePtr } from "../pointers/timelineFramePtr";
import getAllSelectionTargets from "../throttle/getAllSelectionTargets";
import { flushMultipleSelectionTargets } from "./useMultipleSelectionTargets";
import { keyframesPtr } from "../pointers/keyframesPtr";
import unsafeGetValue from "../utils/unsafeGetValue";
const [setTimelineData, getTimelineData] = store([
undefined
]);
export { getTimelineData };
getTimelineData(([val]) => (timelineDataPtr[0] = val));
createEffect(() => {
const [timeline] = timelinePtr;
if (!timeline)
return;
const handle = getReactive(timeline, "data").get((data) => setTimelineData([data]));
return () => {
handle.cancel();
setTimelineData([undefined]);
};
}, [getTimeline]);
const diffObjects = (prev, next) => {
const diff = {};
for (const [k, v] of Object.entries(next)) {
const vOld = prev[k];
if (v !== vOld)
diff[k] = [vOld, v];
}
return diff;
};
createEffect(() => {
const [timelineData] = timelineDataPtr;
const [timeline] = timelinePtr;
if (!timelineData || !timeline || !getTimelineRecord())
return;
const timelineInstances = new WeakSet(Object.keys(timelineData).map((uuid) => uuidMap.get(uuid)));
const prevMap = new WeakMap();
const handle0 = onTransformControls((phase) => {
if (phase === "start") {
flushMultipleSelectionTargets(() => {
for (const instance of getAllSelectionTargets()) {
if (!timelineInstances.has(instance))
continue;
prevMap.set(instance, getTransformControlsData(instance));
}
});
return;
}
flushMultipleSelectionTargets(() => {
const changeData = {};
const [frame] = timelineFramePtr;
const [keyframes] = keyframesPtr;
for (const instance of getAllSelectionTargets()) {
if (!timelineInstances.has(instance))
continue;
const { uuid } = instance;
const uuidData = timelineData[uuid];
const keyframeNums = Object.keys(keyframes[uuid]).map(Number);
for (const [property, [valueOld, valueNew]] of Object.entries(diffObjects(prevMap.get(instance), getTransformControlsData(instance)))) {
let prevFrame = 0;
let nextFrame = frame;
for (const frameNum of keyframeNums) {
if (frameNum > frame) {
nextFrame = frameNum;
break;
}
if (frameNum < frame)
prevFrame = frameNum;
}
const propertyData = uuidData[property] ?? {};
merge(changeData, {
[uuid]: {
[property]: {
[prevFrame]: propertyData[prevFrame] ?? valueOld,
[nextFrame]: propertyData[nextFrame] ?? valueNew,
[frame]: unsafeGetValue(instance, property)
}
}
});
}
}
timeline.mergeData(changeData);
});
});
const handle1 = onEditorEdit(({ phase, value, key }) => { });
addDisposeTimelineInstanceSystem(timelineInstances);
return () => {
handle0.cancel();
handle1.cancel();
deleteDisposeTimelineInstanceSystem(timelineInstances);
};
}, [getTimelineData, getTimelineRecord]);
export const processKeyframe = (cb, skipRefresh) => {
const [timelineData] = timelineDataPtr;
const [timeline] = timelinePtr;
if (!timelineData || !timeline)
return;
const layer = getTimelineLayer();
const frame = timelineFramePtr[0] + "";
const path = layer.split(" ");
if (path.length === 1)
for (const property of Object.keys(timelineData[layer]))
cb(timelineData, layer, property, frame);
else
cb(timelineData, path[0], path[1], frame);
if (!skipRefresh)
timeline.data = timelineData;
};
onTimelineClearKeyframe(() => processKeyframe((timelineData, uuid, property, frame) => unset(timelineData, [uuid, property, frame])));
//# sourceMappingURL=useTimelineData.js.map