UNPKG

mdx-m3-viewer

Version:

A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.

227 lines (177 loc) 6.09 kB
ModelViewer = ModelViewer.default; let common = ModelViewer.common; let quat = common.glMatrix.quat; let vec3 = common.glMatrix.vec3; let math = common.math; let geometry = common.geometry; var keyboard = {}; var mouse = { buttons: [false, false, false], x: 0, y: 0, x2: 0, y2: 0 }; var canvas = document.getElementById('canvas'); var viewer = new ModelViewer.viewer.ModelViewer(canvas, { alpha: true }); var model; var instance; viewer.on('error', (target, error, reason) => console.error(`Error: ${error}, reason: ${reason}`, target)); viewer.addHandler(ModelViewer.viewer.handlers.mdx); viewer.gl.clearColor(0, 0, 0, 1); let backgroundOpaque = true; let turnTable = false; let turnTableSpeed = 0; let turnTableQuat = quat.create(); let isRecording = false; let recordingFrame = 0; let oneTimeRecord = false; let zip = new JSZip(); let frameCounterElement = document.getElementById('frame_counter'); let sequenceNameElement = document.getElementById('sequence_name'); (function step() { viewer.updateAndRender(); if (instance && instance.model.loaded) { instance.rotate(turnTableQuat); if (isRecording || oneTimeRecord) { oneTimeRecord = false; zip.file( `${recordingFrame++}_${model.name}_${Math.floor(instance.frame)}.png`, viewer.canvas.toDataURL().substring(22), { base64: true } ); frameCounterElement.textContent = recordingFrame; } } requestAnimationFrame(step); })(); let scene = viewer.addScene(); console.log(scene); setupCamera(scene, 500); console.log('Viewer version', ModelViewer.version); // Run the next sequence for the given instance at e. function runNextSequence(e) { let instance = e.target; instance.setSequence((instance.sequence + 1) % instance.model.sequences.length); } // Log load starts to the console. viewer.on('loadstart', target => { let path = target.fetchUrl; if (path) { console.log('Loading ' + target.fetchUrl); } }); // Log load ends to the console. viewer.on('load', target => { let path = target.fetchUrl; if (path) { console.log('Finished loading ' + target.fetchUrl); } }); // Log errors to the console. viewer.on('error', (target, error, reason) => console.log(`Error: ${error}, reason: ${reason}`, target)); function normalizePath(path) { return path.toLocaleLowerCase().replace(/\\/g, '/'); } // Load a local file function onLocalFileLoaded(name, buffer) { if (name.endsWith('.mdx')) { let pathSolver = src => { if (src === buffer) { return [src, '.mdx', false]; } else { return [localOrHive(normalizePath(src)), src.substr(src.lastIndexOf('.')), true]; } }; turnTableSpeed = 0; quat.identity(turnTableQuat); isRecording = false; scene.clear(); (model = viewer.load(buffer, pathSolver)), (instance = model.addInstance()); instance.setSequenceLoopMode(2); instance.setSequence(0); sequenceNameElement.textContent = model.sequences[0].name; scene.addInstance(instance); } else if (name.endsWith('.blp')) { if (model && model.loaded) { for (let texture of model.textures) { if (texture.fetchUrl.toLowerCase().endsWith(name.toLowerCase())) { texture.onload(buffer); } } } } } canvas.addEventListener('contextmenu', function(e) { e.preventDefault(); }); canvas.addEventListener('selectstart', function(e) { e.preventDefault(); }); function onFileDrop(e) { let file = e.dataTransfer.files[0]; if (file) { let name = file.name.toLowerCase(); if (name.endsWith('.mdx') || name.endsWith('.blp')) { let reader = new FileReader(); reader.addEventListener('loadend', e => onLocalFileLoaded(name, e.target.result)); reader.readAsArrayBuffer(file); } } } document.addEventListener('dragover', e => { e.preventDefault(); }); document.addEventListener('dragend', e => { e.preventDefault(); onFileDrop(e); }); document.addEventListener('drop', e => { e.preventDefault(); onFileDrop(e); }); window.addEventListener('keydown', e => { let key = e.key; if (instance && instance.model.loaded) { if (key === ' ') { isRecording = !isRecording; } else if (key === 'ArrowLeft') { if (instance.sequence === 0) { instance.setSequence(model.sequences.length - 1); } else { instance.setSequence(instance.sequence - 1); } sequenceNameElement.textContent = model.sequences[instance.sequence].name; } else if (key === 'ArrowRight') { if (instance.sequence === model.sequences.length - 1) { instance.setSequence(0); } else { instance.setSequence(instance.sequence + 1); } sequenceNameElement.textContent = model.sequences[instance.sequence].name; } else if (key === 'ArrowUp') { turnTableSpeed += 0.2; quat.setAxisAngle(turnTableQuat, [0, 0, 1], math.degToRad(turnTableSpeed)); } else if (key === 'ArrowDown') { turnTableSpeed -= 0.2; quat.setAxisAngle(turnTableQuat, [0, 0, 1], math.degToRad(turnTableSpeed)); } else if (key === 'Enter') { oneTimeRecord = true; } else if (key === 'Escape') { if (recordingFrame > 0) { zip.generateAsync({ type: 'blob' }).then(blob => { saveAs(blob, `recorded_frames_${recordingFrame}.zip`); zip = new JSZip(); recordingFrame = 0; frameCounterElement.textContent = ''; }); } } } if (key === 'b') { backgroundOpaque = !backgroundOpaque; if (backgroundOpaque) { viewer.gl.clearColor(0, 0, 0, 1); sequenceNameElement.style.color = 'white'; frameCounterElement.style.color = 'white'; } else { viewer.gl.clearColor(0, 0, 0, 0); sequenceNameElement.style.color = 'black'; frameCounterElement.style.color = 'black'; } } });