Refactoring: split into directories
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import * as THREE from 'three';
|
||||
import { state } from '../state.js';
|
||||
import { updateVcrDisplay } from '../vcr-display.js';
|
||||
import { updateVcrDisplay } from '../scene/vcr-display.js';
|
||||
|
||||
|
||||
function updateCamera() {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as THREE from 'three';
|
||||
import { state, initState } from '../state.js';
|
||||
import { EffectsManager } from '../EffectsManager.js';
|
||||
import { createSceneObjects } from '../scene.js';
|
||||
import { EffectsManager } from '../effects/EffectsManager.js';
|
||||
import { createSceneObjects } from '../scene/scene.js';
|
||||
import { animate, onWindowResize } from './animate.js';
|
||||
import { loadVideoFile, playNextVideo } from '../video-player.js';
|
||||
import { loadVideoFile, playNextVideo } from './video-player.js';
|
||||
|
||||
// --- Initialization ---
|
||||
export function init() {
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import * as THREE from 'three';
|
||||
import { state } from '../state.js';
|
||||
|
||||
// --- Play video by index ---
|
||||
export function playVideoByIndex(index) {
|
||||
state.currentVideoIndex = index;
|
||||
const url = state.videoUrls[index];
|
||||
|
||||
// Dispose of previous texture to free resources
|
||||
if (state.videoTexture) {
|
||||
state.videoTexture.dispose();
|
||||
state.videoTexture = null;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= state.videoUrls.length) {
|
||||
console.info('End of playlist reached. Reload tapes to start again.');
|
||||
state.screenLight.intensity = 0.0;
|
||||
state.tvScreen.material.dispose();
|
||||
state.tvScreen.material = new THREE.MeshPhongMaterial({
|
||||
color: 0x0a0a0a, // Deep black
|
||||
shininess: 5,
|
||||
specular: 0x111111
|
||||
});
|
||||
state.tvScreen.material.needsUpdate = true;
|
||||
state.isVideoLoaded = false;
|
||||
state.lastUpdateTime = -1; // force VCR to redraw
|
||||
return;
|
||||
}
|
||||
|
||||
state.videoElement.src = url;
|
||||
state.videoElement.muted = true;
|
||||
state.videoElement.load();
|
||||
|
||||
// Set loop property: only loop if it's the only video loaded
|
||||
state.videoElement.loop = false; //state.videoUrls.length === 1;
|
||||
|
||||
|
||||
state.videoElement.onloadeddata = () => {
|
||||
// 1. Create the Three.js texture
|
||||
state.videoTexture = new THREE.VideoTexture(state.videoElement);
|
||||
state.videoTexture.minFilter = THREE.LinearFilter;
|
||||
state.videoTexture.magFilter = THREE.LinearFilter;
|
||||
state.videoTexture.format = THREE.RGBAFormat;
|
||||
state.videoTexture.needsUpdate = true;
|
||||
|
||||
// 2. Apply the video texture to the screen mesh
|
||||
state.tvScreen.material.dispose();
|
||||
state.tvScreen.material = new THREE.MeshBasicMaterial({ map: state.videoTexture });
|
||||
state.tvScreen.material.needsUpdate = true;
|
||||
|
||||
// 3. Start playback
|
||||
state.videoElement.play().then(() => {
|
||||
state.isVideoLoaded = true;
|
||||
// Use the defined base intensity for screen glow
|
||||
state.screenLight.intensity = state.originalScreenIntensity;
|
||||
// Initial status message with tape count
|
||||
console.info(`Playing tape ${state.currentVideoIndex + 1} of ${state.videoUrls.length}.`);
|
||||
}).catch(error => {
|
||||
state.screenLight.intensity = state.originalScreenIntensity * 0.5; // Dim the light if playback fails
|
||||
console.error(`Playback blocked for tape ${state.currentVideoIndex + 1}. Click Next Tape to try again.`);
|
||||
console.error('Playback Error: Could not start video playback.', error);
|
||||
});
|
||||
};
|
||||
|
||||
state.videoElement.onerror = (e) => {
|
||||
state.screenLight.intensity = 0.1; // Keep minimum intensity for shadow map
|
||||
console.error(`Error loading tape ${state.currentVideoIndex + 1}.`);
|
||||
console.error('Video Load Error:', e);
|
||||
};
|
||||
}
|
||||
|
||||
// --- Cycle to the next video ---
|
||||
export function playNextVideo() {
|
||||
// Determine the next index, cycling back to 0 if we reach the end
|
||||
let nextIndex = state.currentVideoIndex + 1;
|
||||
if (nextIndex < state.videoUrls.length) {
|
||||
state.baseTime += state.videoElement.duration;
|
||||
}
|
||||
playVideoByIndex(nextIndex);
|
||||
}
|
||||
|
||||
|
||||
// --- Video Loading Logic (handles multiple files) ---
|
||||
export function loadVideoFile(event) {
|
||||
const files = event.target.files;
|
||||
if (files.length === 0) {
|
||||
console.info('File selection cancelled.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Clear previous URLs and revoke object URLs to prevent memory leaks
|
||||
state.videoUrls.forEach(url => URL.revokeObjectURL(url));
|
||||
state.videoUrls = [];
|
||||
|
||||
// 2. Populate the new videoUrls array
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (file.type.startsWith('video/')) {
|
||||
state.videoUrls.push(URL.createObjectURL(file));
|
||||
}
|
||||
}
|
||||
|
||||
if (state.videoUrls.length === 0) {
|
||||
console.info('No valid video files selected.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Start playback of the first video
|
||||
console.info(`Loaded ${state.videoUrls.length} tapes. Starting playback...`);
|
||||
state.loadTapeButton.classList.add("hidden");
|
||||
|
||||
const startDelay = 5;
|
||||
console.info(`Video will start in ${startDelay} seconds.`);
|
||||
setTimeout(() => { playVideoByIndex(0); }, startDelay * 1000);
|
||||
}
|
||||
Reference in New Issue
Block a user