You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1047 lines
21 KiB
1047 lines
21 KiB
2 years ago
|
import * as THREE from 'three';
|
||
|
|
||
|
import { TGALoader } from 'three/addons/loaders/TGALoader.js';
|
||
|
|
||
|
import { AddObjectCommand } from './commands/AddObjectCommand.js';
|
||
|
import { SetSceneCommand } from './commands/SetSceneCommand.js';
|
||
|
|
||
|
import { LoaderUtils } from './LoaderUtils.js';
|
||
|
|
||
|
import { unzipSync, strFromU8 } from 'three/addons/libs/fflate.module.js';
|
||
|
|
||
|
function Loader( editor ) {
|
||
|
|
||
|
const scope = this;
|
||
|
|
||
|
this.texturePath = '';
|
||
|
|
||
|
this.loadItemList = function ( items ) {
|
||
|
|
||
|
LoaderUtils.getFilesFromItemList( items, function ( files, filesMap ) {
|
||
|
|
||
|
scope.loadFiles( files, filesMap );
|
||
|
|
||
|
} );
|
||
|
|
||
|
};
|
||
|
|
||
|
this.loadFiles = function ( files, filesMap ) {
|
||
|
debugger;
|
||
|
|
||
|
if ( files.length > 0 ) {
|
||
|
|
||
|
filesMap = filesMap || LoaderUtils.createFilesMap( files );
|
||
|
|
||
|
const manager = new THREE.LoadingManager();
|
||
|
manager.setURLModifier( function ( url ) {
|
||
|
|
||
|
url = url.replace( /^(\.?\/)/, '' ); // remove './'
|
||
|
|
||
|
const file = filesMap[ url ];
|
||
|
|
||
|
if ( file ) {
|
||
|
|
||
|
console.log( 'Loading', url );
|
||
|
|
||
|
return URL.createObjectURL( file );
|
||
|
|
||
|
}
|
||
|
|
||
|
return url;
|
||
|
|
||
|
} );
|
||
|
|
||
|
manager.addHandler( /\.tga$/i, new TGALoader() );
|
||
|
|
||
|
for ( let i = 0; i < files.length; i ++ ) {
|
||
|
|
||
|
scope.loadFile( files[ i ], manager );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
this.loadFile = function ( file, manager ) {
|
||
|
|
||
|
const filename = file.name;
|
||
|
const extension = filename.split( '.' ).pop().toLowerCase();
|
||
|
|
||
|
const reader = new FileReader();
|
||
|
reader.addEventListener( 'progress', function ( event ) {
|
||
|
|
||
|
const size = '(' + Math.floor( event.total / 1000 ).format() + ' KB)';
|
||
|
const progress = Math.floor( ( event.loaded / event.total ) * 100 ) + '%';
|
||
|
|
||
|
console.log( 'Loading', filename, size, progress );
|
||
|
|
||
|
} );
|
||
|
|
||
|
switch ( extension ) {
|
||
|
|
||
|
case '3dm':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { Rhino3dmLoader } = await import( 'three/addons/loaders/3DMLoader.js' );
|
||
|
|
||
|
const loader = new Rhino3dmLoader();
|
||
|
loader.setLibraryPath( '../examples/jsm/libs/rhino3dm/' );
|
||
|
loader.parse( contents, function ( object ) {
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
} );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case '3ds':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const { TDSLoader } = await import( 'three/addons/loaders/TDSLoader.js' );
|
||
|
|
||
|
const loader = new TDSLoader();
|
||
|
const object = loader.parse( event.target.result );
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case '3mf':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const { ThreeMFLoader } = await import( 'three/addons/loaders/3MFLoader.js' );
|
||
|
|
||
|
const loader = new ThreeMFLoader();
|
||
|
const object = loader.parse( event.target.result );
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'amf':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const { AMFLoader } = await import( 'three/addons/loaders/AMFLoader.js' );
|
||
|
|
||
|
const loader = new AMFLoader();
|
||
|
const amfobject = loader.parse( event.target.result );
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, amfobject ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'dae':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { ColladaLoader } = await import( 'three/addons/loaders/ColladaLoader.js' );
|
||
|
|
||
|
const loader = new ColladaLoader( manager );
|
||
|
const collada = loader.parse( contents );
|
||
|
|
||
|
collada.scene.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, collada.scene ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsText( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'drc':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { DRACOLoader } = await import( 'three/addons/loaders/DRACOLoader.js' );
|
||
|
|
||
|
const loader = new DRACOLoader();
|
||
|
loader.setDecoderPath( '../examples/js/libs/draco/' );
|
||
|
loader.decodeDracoFile( contents, function ( geometry ) {
|
||
|
|
||
|
let object;
|
||
|
|
||
|
if ( geometry.index !== null ) {
|
||
|
|
||
|
const material = new THREE.MeshStandardMaterial();
|
||
|
|
||
|
object = new THREE.Mesh( geometry, material );
|
||
|
object.name = filename;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
const material = new THREE.PointsMaterial( { size: 0.01 } );
|
||
|
material.vertexColors = geometry.hasAttribute( 'color' );
|
||
|
|
||
|
object = new THREE.Points( geometry, material );
|
||
|
object.name = filename;
|
||
|
|
||
|
}
|
||
|
|
||
|
loader.dispose();
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
} );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'fbx':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { FBXLoader } = await import( 'three/addons/loaders/FBXLoader.js' );
|
||
|
|
||
|
const loader = new FBXLoader( manager );
|
||
|
const object = loader.parse( contents );
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'glb':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { DRACOLoader } = await import( 'three/addons/loaders/DRACOLoader.js' );
|
||
|
const { GLTFLoader } = await import( 'three/addons/loaders/GLTFLoader.js' );
|
||
|
|
||
|
const dracoLoader = new DRACOLoader();
|
||
|
dracoLoader.setDecoderPath( '../examples/js/libs/draco/gltf/' );
|
||
|
|
||
|
const loader = new GLTFLoader();
|
||
|
loader.setDRACOLoader( dracoLoader );
|
||
|
loader.parse( contents, '', function ( result ) {
|
||
|
|
||
|
const scene = result.scene;
|
||
|
scene.name = filename;
|
||
|
|
||
|
scene.animations.push( ...result.animations );
|
||
|
editor.execute( new AddObjectCommand( editor, scene ) );
|
||
|
|
||
|
} );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'gltf':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
let loader;
|
||
|
|
||
|
if ( isGLTF1( contents ) ) {
|
||
|
|
||
|
alert( 'Import of glTF asset not possible. Only versions >= 2.0 are supported. Please try to upgrade the file to glTF 2.0 using glTF-Pipeline.' );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
const { DRACOLoader } = await import( 'three/addons/loaders/DRACOLoader.js' );
|
||
|
const { GLTFLoader } = await import( 'three/addons/loaders/GLTFLoader.js' );
|
||
|
|
||
|
const dracoLoader = new DRACOLoader();
|
||
|
dracoLoader.setDecoderPath( '../examples/js/libs/draco/gltf/' );
|
||
|
|
||
|
loader = new GLTFLoader( manager );
|
||
|
loader.setDRACOLoader( dracoLoader );
|
||
|
|
||
|
}
|
||
|
|
||
|
loader.parse( contents, '', function ( result ) {
|
||
|
|
||
|
const scene = result.scene;
|
||
|
scene.name = filename;
|
||
|
|
||
|
scene.animations.push( ...result.animations );
|
||
|
editor.execute( new AddObjectCommand( editor, scene ) );
|
||
|
|
||
|
} );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'js':
|
||
|
case 'json':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
// 2.0
|
||
|
|
||
|
if ( contents.indexOf( 'postMessage' ) !== - 1 ) {
|
||
|
|
||
|
const blob = new Blob( [ contents ], { type: 'text/javascript' } );
|
||
|
const url = URL.createObjectURL( blob );
|
||
|
|
||
|
const worker = new Worker( url );
|
||
|
|
||
|
worker.onmessage = function ( event ) {
|
||
|
|
||
|
event.data.metadata = { version: 2 };
|
||
|
handleJSON( event.data );
|
||
|
|
||
|
};
|
||
|
|
||
|
worker.postMessage( Date.now() );
|
||
|
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
// >= 3.0
|
||
|
|
||
|
let data;
|
||
|
|
||
|
try {
|
||
|
|
||
|
data = JSON.parse( contents );
|
||
|
|
||
|
} catch ( error ) {
|
||
|
|
||
|
alert( error );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
handleJSON( data );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsText( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'ifc':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const { IFCLoader } = await import( 'three/addons/loaders/IFCLoader.js' );
|
||
|
|
||
|
var loader = new IFCLoader();
|
||
|
loader.ifcManager.setWasmPath( 'three/addons/loaders/ifc/' );
|
||
|
|
||
|
const model = await loader.parse( event.target.result );
|
||
|
model.mesh.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, model.mesh ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'kmz':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const { KMZLoader } = await import( 'three/addons/loaders/KMZLoader.js' );
|
||
|
|
||
|
const loader = new KMZLoader();
|
||
|
const collada = loader.parse( event.target.result );
|
||
|
|
||
|
collada.scene.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, collada.scene ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'ldr':
|
||
|
case 'mpd':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const { LDrawLoader } = await import( 'three/addons/loaders/LDrawLoader.js' );
|
||
|
|
||
|
const loader = new LDrawLoader();
|
||
|
loader.setPath( '../../examples/models/ldraw/officialLibrary/' );
|
||
|
loader.parse( event.target.result, undefined, function ( group ) {
|
||
|
|
||
|
group.name = filename;
|
||
|
// Convert from LDraw coordinates: rotate 180 degrees around OX
|
||
|
group.rotation.x = Math.PI;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, group ) );
|
||
|
|
||
|
} );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsText( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'md2':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { MD2Loader } = await import( 'three/addons/loaders/MD2Loader.js' );
|
||
|
|
||
|
const geometry = new MD2Loader().parse( contents );
|
||
|
const material = new THREE.MeshStandardMaterial();
|
||
|
|
||
|
const mesh = new THREE.Mesh( geometry, material );
|
||
|
mesh.mixer = new THREE.AnimationMixer( mesh );
|
||
|
mesh.name = filename;
|
||
|
|
||
|
mesh.animations.push( ...geometry.animations );
|
||
|
editor.execute( new AddObjectCommand( editor, mesh ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'obj':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { OBJLoader } = await import( 'three/addons/loaders/OBJLoader.js' );
|
||
|
|
||
|
const object = new OBJLoader().parse( contents );
|
||
|
object.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsText( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'pcd':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { PCDLoader } = await import( '../../examples/jsm/loaders/PCDLoader.js' );
|
||
|
|
||
|
const points = new PCDLoader().parse( contents );
|
||
|
points.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, points ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'ply':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { PLYLoader } = await import( 'three/addons/loaders/PLYLoader.js' );
|
||
|
|
||
|
const geometry = new PLYLoader().parse( contents );
|
||
|
let object;
|
||
|
|
||
|
if ( geometry.index !== null ) {
|
||
|
|
||
|
const material = new THREE.MeshStandardMaterial();
|
||
|
|
||
|
object = new THREE.Mesh( geometry, material );
|
||
|
object.name = filename;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
const material = new THREE.PointsMaterial( { size: 0.01 } );
|
||
|
material.vertexColors = geometry.hasAttribute( 'color' );
|
||
|
|
||
|
object = new THREE.Points( geometry, material );
|
||
|
object.name = filename;
|
||
|
|
||
|
}
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'stl':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { STLLoader } = await import( 'three/addons/loaders/STLLoader.js' );
|
||
|
|
||
|
const geometry = new STLLoader().parse( contents );
|
||
|
const material = new THREE.MeshStandardMaterial();
|
||
|
|
||
|
const mesh = new THREE.Mesh( geometry, material );
|
||
|
mesh.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, mesh ) );
|
||
|
|
||
|
}, false );
|
||
|
|
||
|
if ( reader.readAsBinaryString !== undefined ) {
|
||
|
|
||
|
reader.readAsBinaryString( file );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'svg':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { SVGLoader } = await import( 'three/addons/loaders/SVGLoader.js' );
|
||
|
|
||
|
const loader = new SVGLoader();
|
||
|
const paths = loader.parse( contents ).paths;
|
||
|
|
||
|
//
|
||
|
|
||
|
const group = new THREE.Group();
|
||
|
group.scale.multiplyScalar( 0.1 );
|
||
|
group.scale.y *= - 1;
|
||
|
|
||
|
for ( let i = 0; i < paths.length; i ++ ) {
|
||
|
|
||
|
const path = paths[ i ];
|
||
|
|
||
|
const material = new THREE.MeshBasicMaterial( {
|
||
|
color: path.color,
|
||
|
depthWrite: false
|
||
|
} );
|
||
|
|
||
|
const shapes = SVGLoader.createShapes( path );
|
||
|
|
||
|
for ( let j = 0; j < shapes.length; j ++ ) {
|
||
|
|
||
|
const shape = shapes[ j ];
|
||
|
|
||
|
const geometry = new THREE.ShapeGeometry( shape );
|
||
|
const mesh = new THREE.Mesh( geometry, material );
|
||
|
|
||
|
group.add( mesh );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, group ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsText( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'usdz':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { USDZLoader } = await import( '../../examples/jsm/loaders/USDZLoader.js' );
|
||
|
|
||
|
const group = new USDZLoader().parse( contents );
|
||
|
group.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, group ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'vox':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { VOXLoader, VOXMesh } = await import( 'three/addons/loaders/VOXLoader.js' );
|
||
|
|
||
|
const chunks = new VOXLoader().parse( contents );
|
||
|
|
||
|
const group = new THREE.Group();
|
||
|
group.name = filename;
|
||
|
|
||
|
for ( let i = 0; i < chunks.length; i ++ ) {
|
||
|
|
||
|
const chunk = chunks[ i ];
|
||
|
|
||
|
const mesh = new VOXMesh( chunk );
|
||
|
group.add( mesh );
|
||
|
|
||
|
}
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, group ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'vtk':
|
||
|
case 'vtp':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { VTKLoader } = await import( 'three/addons/loaders/VTKLoader.js' );
|
||
|
|
||
|
const geometry = new VTKLoader().parse( contents );
|
||
|
const material = new THREE.MeshStandardMaterial();
|
||
|
|
||
|
const mesh = new THREE.Mesh( geometry, material );
|
||
|
mesh.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, mesh ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'wrl':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { VRMLLoader } = await import( 'three/addons/loaders/VRMLLoader.js' );
|
||
|
|
||
|
const result = new VRMLLoader().parse( contents );
|
||
|
|
||
|
editor.execute( new SetSceneCommand( editor, result ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsText( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'xyz':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', async function ( event ) {
|
||
|
|
||
|
const contents = event.target.result;
|
||
|
|
||
|
const { XYZLoader } = await import( 'three/addons/loaders/XYZLoader.js' );
|
||
|
|
||
|
const geometry = new XYZLoader().parse( contents );
|
||
|
|
||
|
const material = new THREE.PointsMaterial();
|
||
|
material.vertexColors = geometry.hasAttribute( 'color' );
|
||
|
|
||
|
const points = new THREE.Points( geometry, material );
|
||
|
points.name = filename;
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, points ) );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsText( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'zip':
|
||
|
|
||
|
{
|
||
|
|
||
|
reader.addEventListener( 'load', function ( event ) {
|
||
|
|
||
|
handleZIP( event.target.result );
|
||
|
|
||
|
}, false );
|
||
|
reader.readAsArrayBuffer( file );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
|
||
|
console.error( 'Unsupported file format (' + extension + ').' );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
function handleJSON( data ) {
|
||
|
|
||
|
if ( data.metadata === undefined ) { // 2.0
|
||
|
|
||
|
data.metadata = { type: 'Geometry' };
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( data.metadata.type === undefined ) { // 3.0
|
||
|
|
||
|
data.metadata.type = 'Geometry';
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( data.metadata.formatVersion !== undefined ) {
|
||
|
|
||
|
data.metadata.version = data.metadata.formatVersion;
|
||
|
|
||
|
}
|
||
|
|
||
|
switch ( data.metadata.type.toLowerCase() ) {
|
||
|
|
||
|
case 'buffergeometry':
|
||
|
|
||
|
{
|
||
|
|
||
|
const loader = new THREE.BufferGeometryLoader();
|
||
|
const result = loader.parse( data );
|
||
|
|
||
|
const mesh = new THREE.Mesh( result );
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, mesh ) );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'geometry':
|
||
|
|
||
|
console.error( 'Loader: "Geometry" is no longer supported.' );
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'object':
|
||
|
|
||
|
{
|
||
|
|
||
|
const loader = new THREE.ObjectLoader();
|
||
|
loader.setResourcePath( scope.texturePath );
|
||
|
|
||
|
loader.parse( data, function ( result ) {
|
||
|
|
||
|
if ( result.isScene ) {
|
||
|
|
||
|
editor.execute( new SetSceneCommand( editor, result ) );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, result ) );
|
||
|
|
||
|
}
|
||
|
|
||
|
} );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'app':
|
||
|
|
||
|
editor.fromJSON( data );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
async function handleZIP( contents ) {
|
||
|
|
||
|
const zip = unzipSync( new Uint8Array( contents ) );
|
||
|
|
||
|
// Poly
|
||
|
|
||
|
if ( zip[ 'model.obj' ] && zip[ 'materials.mtl' ] ) {
|
||
|
|
||
|
const { MTLLoader } = await import( 'three/addons/loaders/MTLLoader.js' );
|
||
|
const { OBJLoader } = await import( 'three/addons/loaders/OBJLoader.js' );
|
||
|
|
||
|
const materials = new MTLLoader().parse( strFromU8( zip[ 'materials.mtl' ] ) );
|
||
|
const object = new OBJLoader().setMaterials( materials ).parse( strFromU8( zip[ 'model.obj' ] ) );
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
|
||
|
for ( const path in zip ) {
|
||
|
|
||
|
const file = zip[ path ];
|
||
|
|
||
|
const manager = new THREE.LoadingManager();
|
||
|
manager.setURLModifier( function ( url ) {
|
||
|
|
||
|
const file = zip[ url ];
|
||
|
|
||
|
if ( file ) {
|
||
|
|
||
|
console.log( 'Loading', url );
|
||
|
|
||
|
const blob = new Blob( [ file.buffer ], { type: 'application/octet-stream' } );
|
||
|
return URL.createObjectURL( blob );
|
||
|
|
||
|
}
|
||
|
|
||
|
return url;
|
||
|
|
||
|
} );
|
||
|
|
||
|
const extension = path.split( '.' ).pop().toLowerCase();
|
||
|
|
||
|
switch ( extension ) {
|
||
|
|
||
|
case 'fbx':
|
||
|
|
||
|
{
|
||
|
|
||
|
const { FBXLoader } = await import( 'three/addons/loaders/FBXLoader.js' );
|
||
|
|
||
|
const loader = new FBXLoader( manager );
|
||
|
const object = loader.parse( file.buffer );
|
||
|
|
||
|
editor.execute( new AddObjectCommand( editor, object ) );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'glb':
|
||
|
|
||
|
{
|
||
|
|
||
|
const { DRACOLoader } = await import( 'three/addons/loaders/DRACOLoader.js' );
|
||
|
const { GLTFLoader } = await import( 'three/addons/loaders/GLTFLoader.js' );
|
||
|
|
||
|
const dracoLoader = new DRACOLoader();
|
||
|
dracoLoader.setDecoderPath( '../examples/js/libs/draco/gltf/' );
|
||
|
|
||
|
const loader = new GLTFLoader();
|
||
|
loader.setDRACOLoader( dracoLoader );
|
||
|
|
||
|
loader.parse( file.buffer, '', function ( result ) {
|
||
|
|
||
|
const scene = result.scene;
|
||
|
|
||
|
scene.animations.push( ...result.animations );
|
||
|
editor.execute( new AddObjectCommand( editor, scene ) );
|
||
|
|
||
|
} );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
case 'gltf':
|
||
|
|
||
|
{
|
||
|
|
||
|
const { DRACOLoader } = await import( 'three/addons/loaders/DRACOLoader.js' );
|
||
|
const { GLTFLoader } = await import( 'three/addons/loaders/GLTFLoader.js' );
|
||
|
|
||
|
const dracoLoader = new DRACOLoader();
|
||
|
dracoLoader.setDecoderPath( '../examples/js/libs/draco/gltf/' );
|
||
|
|
||
|
const loader = new GLTFLoader( manager );
|
||
|
loader.setDRACOLoader( dracoLoader );
|
||
|
loader.parse( strFromU8( file ), '', function ( result ) {
|
||
|
|
||
|
const scene = result.scene;
|
||
|
|
||
|
scene.animations.push( ...result.animations );
|
||
|
editor.execute( new AddObjectCommand( editor, scene ) );
|
||
|
|
||
|
} );
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
function isGLTF1( contents ) {
|
||
|
|
||
|
let resultContent;
|
||
|
|
||
|
if ( typeof contents === 'string' ) {
|
||
|
|
||
|
// contents is a JSON string
|
||
|
resultContent = contents;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
const magic = THREE.LoaderUtils.decodeText( new Uint8Array( contents, 0, 4 ) );
|
||
|
|
||
|
if ( magic === 'glTF' ) {
|
||
|
|
||
|
// contents is a .glb file; extract the version
|
||
|
const version = new DataView( contents ).getUint32( 4, true );
|
||
|
|
||
|
return version < 2;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// contents is a .gltf file
|
||
|
resultContent = THREE.LoaderUtils.decodeText( new Uint8Array( contents ) );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
const json = JSON.parse( resultContent );
|
||
|
|
||
|
return ( json.asset != undefined && json.asset.version[ 0 ] < 2 );
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
export { Loader };
|