From 4f80ad8bfbff17224cccf08c26bdfc016010bde3 Mon Sep 17 00:00:00 2001 From: Donovan Hutchence Date: Mon, 24 Feb 2025 12:31:12 +0000 Subject: [PATCH] Fix PLY sequences (#418) --- src/file-handler.ts | 12 +++--- src/main.ts | 4 +- src/{animation.ts => ply-sequence.ts} | 57 ++++++++++--------------- src/ui/timeline-panel.ts | 60 ++++----------------------- 4 files changed, 39 insertions(+), 94 deletions(-) rename src/{animation.ts => ply-sequence.ts} (62%) diff --git a/src/file-handler.ts b/src/file-handler.ts index 5a754b4..530c962 100644 --- a/src/file-handler.ts +++ b/src/file-handler.ts @@ -212,13 +212,13 @@ const initFileHandler = (scene: Scene, events: Events, dropTarget: HTMLElement, const isSequence = () => { // eslint-disable-next-line regexp/no-super-linear-backtracking const regex = /(.*?)(\d+).ply$/; - const baseMatch = entries[0].file.name?.match(regex); + const baseMatch = entries[0].file.name?.toLowerCase().match(regex); if (!baseMatch) { return false; } for (let i = 1; i < entries.length; i++) { - const thisMatch = entries[i].file.name?.match(regex); + const thisMatch = entries[i].file.name?.toLowerCase().match(regex); if (!thisMatch || thisMatch[1] !== baseMatch[1]) { return false; } @@ -228,8 +228,8 @@ const initFileHandler = (scene: Scene, events: Events, dropTarget: HTMLElement, }; if (entries.length > 1 && isSequence()) { - events.fire('animation.setFrames', entries.map(e => e.file)); - events.fire('animation.setFrame', 0); + events.fire('plysequence.setFrames', entries.map(e => e.file)); + events.fire('timeline.frame', 0); } else { for (let i = 0; i < entries.length; i++) { const entry = entries[i]; @@ -307,8 +307,8 @@ const initFileHandler = (scene: Scene, events: Events, dropTarget: HTMLElement, } } } - events.fire('animation.setFrames', files); - events.fire('animation.setFrame', 0); + events.fire('plysequence.setFrames', files); + events.fire('timeline.frame', 0); } } catch (error) { if (error.name !== 'AbortError') { diff --git a/src/main.ts b/src/main.ts index ee900c1..f857376 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,12 @@ import { Color, createGraphicsDevice } from 'playcanvas'; -import { registerAnimationEvents } from './animation'; import { registerCameraPosesEvents } from './camera-poses'; import { registerDocEvents } from './doc'; import { EditHistory } from './edit-history'; import { registerEditorEvents } from './editor'; import { Events } from './events'; import { initFileHandler } from './file-handler'; +import { registerPlySequenceEvents } from './ply-sequence'; import { registerPublishEvents } from './publish'; import { Scene } from './scene'; import { getSceneConfig } from './scene-config'; @@ -246,7 +246,7 @@ const main = async () => { registerTimelineEvents(events); registerCameraPosesEvents(events); registerTransformHandlerEvents(events); - registerAnimationEvents(events); + registerPlySequenceEvents(events); registerPublishEvents(events); registerDocEvents(scene, events); initShortcuts(events); diff --git a/src/animation.ts b/src/ply-sequence.ts similarity index 62% rename from src/animation.ts rename to src/ply-sequence.ts index bb105fa..4bdf0a8 100644 --- a/src/animation.ts +++ b/src/ply-sequence.ts @@ -1,12 +1,11 @@ import { Events } from './events'; import { Splat } from './splat'; -const registerAnimationEvents = (events: Events) => { - // animation support - let animationFiles: File[] = []; - let animationSplat: Splat = null; - let animationFrame = -1; - let animationLoading = false; +const registerPlySequenceEvents = (events: Events) => { + let sequenceFiles: File[] = []; + let sequenceSplat: Splat = null; + let sequenceFrame = -1; + let sequenceLoading = false; let nextFrame = -1; const setFrames = (files: File[]) => { @@ -20,9 +19,9 @@ const registerAnimationEvents = (events: Events) => { return (avalue && bvalue) ? parseInt(avalue, 10) - parseInt(bvalue, 10) : 0; }; - animationFiles = files.slice(); - animationFiles.sort(sorter); - events.fire('animation.frames', animationFiles.length); + sequenceFiles = files.slice(); + sequenceFiles.sort(sorter); + events.fire('timeline.frames', sequenceFiles.length); }; // resolves on first render frame @@ -35,16 +34,16 @@ const registerAnimationEvents = (events: Events) => { }; const setFrame = async (frame: number) => { - if (frame < 0 || frame >= animationFiles.length) { + if (frame < 0 || frame >= sequenceFiles.length) { return; } - if (animationLoading) { + if (sequenceLoading) { nextFrame = frame; return; } - if (frame === animationFrame) { + if (frame === sequenceFrame) { return; } @@ -61,28 +60,26 @@ const registerAnimationEvents = (events: Events) => { } events.fire('scene.clear'); - animationSplat = null; + sequenceSplat = null; } - animationLoading = true; + sequenceLoading = true; - const file = animationFiles[frame]; + const file = sequenceFiles[frame]; const url = URL.createObjectURL(file); - const newSplat = await events.invoke('import', url, file.name, !animationSplat, true) as Splat; + const newSplat = await events.invoke('import', url, file.name, !sequenceSplat, true) as Splat; URL.revokeObjectURL(url); // wait for first frame render await firstRender(newSplat); // destroy the previous frame - if (animationSplat) { - animationSplat.destroy(); + if (sequenceSplat) { + sequenceSplat.destroy(); } - animationFrame = frame; - animationSplat = newSplat; - animationLoading = false; - - events.fire('animation.frame', frame); + sequenceFrame = frame; + sequenceSplat = newSplat; + sequenceLoading = false; // initiate the next frame load if (nextFrame !== -1) { @@ -92,21 +89,13 @@ const registerAnimationEvents = (events: Events) => { } }; - events.function('animation.frames', () => { - return animationFiles?.length ?? 0; - }); - - events.function('animation.frame', () => { - return animationFrame; - }); - - events.on('animation.setFrames', (files: File[]) => { + events.on('plysequence.setFrames', (files: File[]) => { setFrames(files); }); - events.on('animation.setFrame', async (frame: number) => { + events.on('timeline.frame', async (frame: number) => { await setFrame(frame); }); }; -export { registerAnimationEvents }; +export { registerPlySequenceEvents }; diff --git a/src/ui/timeline-panel.ts b/src/ui/timeline-panel.ts index 025f42a..e83336d 100644 --- a/src/ui/timeline-panel.ts +++ b/src/ui/timeline-panel.ts @@ -1,7 +1,6 @@ -import { Button, Container, Label, NumericInput, SelectInput, SliderInput } from 'pcui'; +import { Button, Container, NumericInput, SelectInput } from 'pcui'; import { Events } from '../events'; -import { localize } from './localization'; import { Tooltips } from './tooltips'; class Ticks extends Container { @@ -273,6 +272,13 @@ class TimelinePanel extends Container { } else { events.fire('timeline.setFrame', orderedKeys[dir === 'back' ? (nextKey + l - 1) % l : nextKey].frame); } + } else { + // if there are no keys, just to start of timeline or end + if (dir === 'back') { + events.fire('timeline.setFrame', 0); + } else { + events.fire('timeline.setFrame', events.invoke('timeline.frames') - 1); + } } }; @@ -325,56 +331,6 @@ class TimelinePanel extends Container { // stop } }); - - // ply animations - - const slider = new SliderInput({ - id: 'frame-slider', - min: 0, - max: 0, - precision: 0, - value: 0, - hidden: true - }); - - this.append(slider); - - const prevFrame = () => { - const frames = events.invoke('animation.frames'); - if (frames > 0) { - const frame = events.invoke('animation.frame'); - events.fire('animation.setFrame', (frame - 1 + frames) % frames); - } - }; - - const nextFrame = () => { - const frames = events.invoke('animation.frames'); - if (frames > 0) { - const frame = events.invoke('animation.frame'); - events.fire('animation.setFrame', (frame + 1) % frames); - } - }; - - slider.on('change', (value: number) => { - events.fire('animation.setFrame', value); - }); - - events.on('animation.frames', (frames: number) => { - this.hidden = frames === 0; - slider.max = slider.sliderMax = frames - 1; - }); - - events.on('animation.frame', (frame: number) => { - slider.value = frame; - }); - - tooltips.register(prev, localize('timeline.prev-key'), 'top'); - tooltips.register(play, localize('timeline.play'), 'top'); - tooltips.register(next, localize('timeline.next-key'), 'top'); - tooltips.register(addKey, localize('timeline.add-key'), 'top'); - tooltips.register(removeKey, localize('timeline.remove-key'), 'top'); - tooltips.register(speed, localize('timeline.frame-rate'), 'top'); - tooltips.register(frames, localize('timeline.total-frames'), 'top'); } }