|
@@ -7,10 +7,10 @@
|
|
* More information about the AMF format: http://amf.wikispaces.com
|
|
* More information about the AMF format: http://amf.wikispaces.com
|
|
*
|
|
*
|
|
* Usage:
|
|
* Usage:
|
|
- * var loader = new AMFLoader();
|
|
|
|
- * loader.load('/path/to/project.amf', function(objecttree) {
|
|
|
|
- * scene.add(objecttree);
|
|
|
|
- * });
|
|
|
|
|
|
+ * var loader = new AMFLoader();
|
|
|
|
+ * loader.load('/path/to/project.amf', function(objecttree) {
|
|
|
|
+ * scene.add(objecttree);
|
|
|
|
+ * });
|
|
*
|
|
*
|
|
* Materials now supported, material colors supported
|
|
* Materials now supported, material colors supported
|
|
* Zip support, requires jszip
|
|
* Zip support, requires jszip
|
|
@@ -19,337 +19,484 @@
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
|
|
|
|
-THREE.AMFLoader = function( manager ) {
|
|
|
|
- this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager;
|
|
|
|
|
|
+THREE.AMFLoader = function ( manager ) {
|
|
|
|
+
|
|
|
|
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
|
|
|
|
+
|
|
};
|
|
};
|
|
|
|
|
|
THREE.AMFLoader.prototype = {
|
|
THREE.AMFLoader.prototype = {
|
|
|
|
|
|
- constructor: THREE.AMFLoader,
|
|
|
|
|
|
+ constructor: THREE.AMFLoader,
|
|
|
|
+
|
|
|
|
+ load: function ( url, onLoad, onProgress, onError ) {
|
|
|
|
+
|
|
|
|
+ var scope = this;
|
|
|
|
+
|
|
|
|
+ var loader = new THREE.XHRLoader( scope.manager );
|
|
|
|
+ loader.setCrossOrigin( this.crossOrigin );
|
|
|
|
+ loader.setResponseType( 'arraybuffer' );
|
|
|
|
+ loader.load( url, function( text ) {
|
|
|
|
+
|
|
|
|
+ onLoad( scope.parse( text ) );
|
|
|
|
+
|
|
|
|
+ }, onProgress, onError );
|
|
|
|
+
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ parse: function ( data ) {
|
|
|
|
+
|
|
|
|
+ function loadDocument( data ) {
|
|
|
|
+
|
|
|
|
+ var view = new DataView( data );
|
|
|
|
+ var magic = String.fromCharCode( view.getUint8( 0 ), view.getUint8( 1 ) );
|
|
|
|
+
|
|
|
|
+ if ( magic === "PK" ) {
|
|
|
|
+
|
|
|
|
+ var zip = null;
|
|
|
|
+ var file = null;
|
|
|
|
+
|
|
|
|
+ console.log( "Loading Zip" );
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+
|
|
|
|
+ zip = new JSZip( data );
|
|
|
|
+
|
|
|
|
+ } catch ( e ) {
|
|
|
|
+
|
|
|
|
+ if ( e instanceof ReferenceError ) {
|
|
|
|
+
|
|
|
|
+ console.log( " jszip missing and file is compressed." );
|
|
|
|
+ return null;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for ( file in zip.files ) {
|
|
|
|
+
|
|
|
|
+ if ( file.toLowerCase().substr( - 4 ) === '.amf' ) {
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ console.log( " Trying to load file asset: " + file );
|
|
|
|
+ view = new DataView( zip.file( file ).asArrayBuffer() );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ( TextDecoder === undefined ) {
|
|
|
|
+
|
|
|
|
+ console.log( " TextDecoder not present. Please use TextDecoder polyfill." );
|
|
|
|
+ return null;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var fileText = new TextDecoder( 'utf-8' ).decode( view );
|
|
|
|
+ var xmlData = new DOMParser().parseFromString( fileText, 'application/xml' );
|
|
|
|
+
|
|
|
|
+ if ( xmlData.documentElement.nodeName.toLowerCase() !== "amf" ) {
|
|
|
|
+
|
|
|
|
+ console.log( " Error loading AMF - no AMF document found." );
|
|
|
|
+ return null;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return xmlData;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function loadDocumentScale( node ) {
|
|
|
|
+
|
|
|
|
+ var scale = 1.0;
|
|
|
|
+ var unit = 'millimeter';
|
|
|
|
+
|
|
|
|
+ if ( node.documentElement.attributes[ 'unit' ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ unit = node.documentElement.attributes[ 'unit' ].value.toLowerCase();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var scaleUnits = {
|
|
|
|
+ 'millimeter': 1.0,
|
|
|
|
+ 'inch': 25.4,
|
|
|
|
+ 'feet': 304.8,
|
|
|
|
+ 'meter': 1000.0,
|
|
|
|
+ 'micron': 0.001
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ if ( scaleUnits[ unit ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ scale = scaleUnits[ unit ];
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ console.log( " Unit scale: " + scale );
|
|
|
|
+ return scale;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function loadMaterials( node ) {
|
|
|
|
+
|
|
|
|
+ var matName = "AMF Material";
|
|
|
|
+ var matId = node.attributes[ 'id' ].textContent;
|
|
|
|
+ var color = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
|
|
|
|
+
|
|
|
|
+ var loadedMaterial = null;
|
|
|
|
+
|
|
|
|
+ for ( var i = 0; i < node.children.length; i ++ ) {
|
|
|
|
+
|
|
|
|
+ var matChildEl = node.children[ i ];
|
|
|
|
+
|
|
|
|
+ if ( matChildEl.nodeName === "metadata" && matChildEl.attributes[ 'type' ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ if ( matChildEl.attributes[ 'type' ].value === 'name' ) {
|
|
|
|
+
|
|
|
|
+ matname = matChildEl.textContent;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } else if ( matChildEl.nodeName === 'color' ) {
|
|
|
|
+
|
|
|
|
+ color = loadColor( matChildEl );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ loadedMaterial = new THREE.MeshPhongMaterial( {
|
|
|
|
+ shading: THREE.FlatShading,
|
|
|
|
+ color: new THREE.Color( color.r, color.g, color.b ),
|
|
|
|
+ name: matName
|
|
|
|
+ } );
|
|
|
|
+
|
|
|
|
+ if ( color.a !== 1.0 ) {
|
|
|
|
+
|
|
|
|
+ loadedMaterial.transparent = true;
|
|
|
|
+ loadedMaterial.opacity = color.a;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return { 'id': matId, 'material': loadedMaterial };
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function loadColor( node ) {
|
|
|
|
+
|
|
|
|
+ var color = { 'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0 };
|
|
|
|
+
|
|
|
|
+ for ( var i = 0; i < node.children.length; i ++ ) {
|
|
|
|
+
|
|
|
|
+ var matColor = node.children[ i ];
|
|
|
|
+
|
|
|
|
+ if ( matColor.nodeName === 'r' ) {
|
|
|
|
+
|
|
|
|
+ color.r = matColor.textContent;
|
|
|
|
+
|
|
|
|
+ } else if ( matColor.nodeName === 'g' ) {
|
|
|
|
+
|
|
|
|
+ color.g = matColor.textContent;
|
|
|
|
+
|
|
|
|
+ } else if ( matColor.nodeName === 'b' ) {
|
|
|
|
+
|
|
|
|
+ color.b = matColor.textContent;
|
|
|
|
+
|
|
|
|
+ } else if ( matColor.nodeName === 'a' ) {
|
|
|
|
+
|
|
|
|
+ color.a = matColor.textContent;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return color;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function loadMeshVolume( node ) {
|
|
|
|
+
|
|
|
|
+ var volume = { "name": "", "triangles": [], "materialid": null };
|
|
|
|
+
|
|
|
|
+ var currVolumeNode = node.firstElementChild;
|
|
|
|
+
|
|
|
|
+ if ( node.attributes[ 'materialid' ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ volume.materialId = node.attributes[ 'materialid' ].nodeValue;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while ( currVolumeNode ) {
|
|
|
|
+
|
|
|
|
+ if ( currVolumeNode.nodeName === "metadata" ) {
|
|
|
|
+
|
|
|
|
+ if ( currVolumeNode.attributes[ 'type' ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ if ( currVolumeNode.attributes[ 'type' ].value === 'name' ) {
|
|
|
|
+
|
|
|
|
+ volume.name = currVolumeNode.textContent;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } else if ( currVolumeNode.nodeName === "triangle" ) {
|
|
|
|
+
|
|
|
|
+ var v1 = currVolumeNode.getElementsByTagName("v1")[0].textContent;
|
|
|
|
+ var v2 = currVolumeNode.getElementsByTagName("v2")[0].textContent;
|
|
|
|
+ var v3 = currVolumeNode.getElementsByTagName("v3")[0].textContent;
|
|
|
|
+
|
|
|
|
+ volume.triangles.push( v1 );
|
|
|
|
+ volume.triangles.push( v2 );
|
|
|
|
+ volume.triangles.push( v3 );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ currVolumeNode = currVolumeNode.nextElementSibling;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return volume;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function loadMeshVertices( node ) {
|
|
|
|
+
|
|
|
|
+ var vertArray = [];
|
|
|
|
+ var normalArray = [];
|
|
|
|
+ var currVerticesNode = node.firstElementChild;
|
|
|
|
+
|
|
|
|
+ while ( currVerticesNode ) {
|
|
|
|
+
|
|
|
|
+ if ( currVerticesNode.nodeName === "vertex" ) {
|
|
|
|
+
|
|
|
|
+ var vNode = currVerticesNode.firstElementChild;
|
|
|
|
+
|
|
|
|
+ while ( vNode ) {
|
|
|
|
+
|
|
|
|
+ if ( vNode.nodeName === "coordinates" ) {
|
|
|
|
+
|
|
|
|
+ var x = vNode.getElementsByTagName("x")[0].textContent;
|
|
|
|
+ var y = vNode.getElementsByTagName("y")[0].textContent;
|
|
|
|
+ var z = vNode.getElementsByTagName("z")[0].textContent;
|
|
|
|
+
|
|
|
|
+ vertArray.push(x);
|
|
|
|
+ vertArray.push(y);
|
|
|
|
+ vertArray.push(z);
|
|
|
|
+
|
|
|
|
+ } else if ( vNode.nodeName === "normal" ) {
|
|
|
|
+
|
|
|
|
+ var nx = vNode.getElementsByTagName("nx")[0].textContent;
|
|
|
|
+ var ny = vNode.getElementsByTagName("ny")[0].textContent;
|
|
|
|
+ var nz = vNode.getElementsByTagName("nz")[0].textContent;
|
|
|
|
+
|
|
|
|
+ normalArray.push(nx);
|
|
|
|
+ normalArray.push(ny);
|
|
|
|
+ normalArray.push(nz);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ vNode = vNode.nextElementSibling;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ currVerticesNode = currVerticesNode.nextElementSibling;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return { "vertices": vertArray, "normals": normalArray };
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function loadObject( node ) {
|
|
|
|
+
|
|
|
|
+ var objId = node.attributes[ 'id' ].textContent;
|
|
|
|
+ var loadedObject = { "name": "amfobject", "meshes": [] };
|
|
|
|
+ var currColor = null;
|
|
|
|
+ var currObjNode = node.firstElementChild;
|
|
|
|
+
|
|
|
|
+ while ( currObjNode ) {
|
|
|
|
+
|
|
|
|
+ if ( currObjNode.nodeName === "metadata" ) {
|
|
|
|
+
|
|
|
|
+ if ( currObjNode.attributes[ 'type' ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ if ( currObjNode.attributes[ 'type' ].value === 'name' ) {
|
|
|
|
+
|
|
|
|
+ loadedObject.name = currObjNode.textContent;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } else if ( currObjNode.nodeName === "color" ) {
|
|
|
|
+
|
|
|
|
+ currColor = loadColor( currObjNode );
|
|
|
|
+
|
|
|
|
+ } else if ( currObjNode.nodeName === "mesh" ) {
|
|
|
|
+
|
|
|
|
+ var currMeshNode = currObjNode.firstElementChild;
|
|
|
|
+ var mesh = { "vertices": [], "normals": [], "volumes": [], "color": currColor };
|
|
|
|
+
|
|
|
|
+ while ( currMeshNode ) {
|
|
|
|
+
|
|
|
|
+ if ( currMeshNode.nodeName === "vertices" ) {
|
|
|
|
+
|
|
|
|
+ var loadedVertices = loadMeshVertices( currMeshNode );
|
|
|
|
+
|
|
|
|
+ mesh.normals = mesh.normals.concat( loadedVertices.normals );
|
|
|
|
+ mesh.vertices = mesh.vertices.concat( loadedVertices.vertices );
|
|
|
|
+
|
|
|
|
+ } else if ( currMeshNode.nodeName === "volume" ) {
|
|
|
|
+
|
|
|
|
+ mesh.volumes.push( loadMeshVolume( currMeshNode ) );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ currMeshNode = currMeshNode.nextElementSibling;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ loadedObject.meshes.push( mesh );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ currObjNode = currObjNode.nextElementSibling;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return { 'id': objId, 'obj': loadedObject };
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var xmlData = loadDocument( data );
|
|
|
|
+ var amfName = "";
|
|
|
|
+ var amfAuthor = "";
|
|
|
|
+ var amfScale = loadDocumentScale( xmlData );
|
|
|
|
+ var amfMaterials = {};
|
|
|
|
+ var amfObjects = {};
|
|
|
|
+ var children = xmlData.documentElement.children;
|
|
|
|
+
|
|
|
|
+ for ( var i = 0; i < children.length; i ++ ) {
|
|
|
|
+
|
|
|
|
+ var child = children[ i ];
|
|
|
|
+
|
|
|
|
+ if ( child.nodeName === 'metadata' ) {
|
|
|
|
+
|
|
|
|
+ if ( child.attributes[ 'type' ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ if ( child.attributes[ 'type' ].value === 'name' ) {
|
|
|
|
+
|
|
|
|
+ amfName = child.textContent;
|
|
|
|
+
|
|
|
|
+ } else if ( child.attributes[ 'type' ].value === 'author' ) {
|
|
|
|
+
|
|
|
|
+ amfAuthor = child.textContent;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } else if ( child.nodeName === 'material' ) {
|
|
|
|
+
|
|
|
|
+ var loadedMaterial = loadMaterials( child );
|
|
|
|
+
|
|
|
|
+ amfMaterials[ loadedMaterial.id ] = loadedMaterial.material;
|
|
|
|
+
|
|
|
|
+ } else if ( child.nodeName === 'object' ) {
|
|
|
|
+
|
|
|
|
+ var loadedObject = loadObject( child );
|
|
|
|
+
|
|
|
|
+ amfObjects[ loadedObject.id ] = loadedObject.obj;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var sceneObject = new THREE.Group();
|
|
|
|
+ var defaultMaterial = new THREE.MeshPhongMaterial( { color: 0xaaaaff, shading: THREE.FlatShading } );
|
|
|
|
+
|
|
|
|
+ sceneObject.name = amfName;
|
|
|
|
+ sceneObject.userData.author = amfAuthor;
|
|
|
|
+ sceneObject.userData.loader = "AMF";
|
|
|
|
+
|
|
|
|
+ for ( var id in amfObjects ) {
|
|
|
|
+
|
|
|
|
+ var meshes = amfObjects[ id ].meshes;
|
|
|
|
+ var newObject = new THREE.Group();
|
|
|
|
+
|
|
|
|
+ for ( var i = 0; i < meshes.length; i ++ ) {
|
|
|
|
+
|
|
|
|
+ var objDefaultMaterial = defaultMaterial;
|
|
|
|
+ var mesh = meshes[ i ];
|
|
|
|
+ var meshVertices = Float32Array.from( mesh.vertices );
|
|
|
|
+ var vertices = new THREE.BufferAttribute( Float32Array.from( meshVertices ), 3 );
|
|
|
|
+ var meshNormals = null;
|
|
|
|
+ var normals = null;
|
|
|
|
+
|
|
|
|
+ if ( mesh.normals.length ) {
|
|
|
|
+
|
|
|
|
+ meshNormals = Float32Array.from( mesh.normals );
|
|
|
|
+ normals = new THREE.BufferAttribute( Float32Array.from( meshNormals ), 3 );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ( mesh.color ) {
|
|
|
|
+
|
|
|
|
+ var color = mesh.color;
|
|
|
|
+
|
|
|
|
+ objDefaultMaterial = defaultMaterial.clone();
|
|
|
|
+ objDefaultMaterial.color = new THREE.Color( color.r, color.g, color.b );
|
|
|
|
+
|
|
|
|
+ if ( color.a !== 1.0 ) {
|
|
|
|
+
|
|
|
|
+ objDefaultMaterial.transparent = true;
|
|
|
|
+ objDefaultMaterial.opacity = color.a;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var volumes = mesh.volumes;
|
|
|
|
+
|
|
|
|
+ for ( var j = 0; j < volumes.length; j ++ ) {
|
|
|
|
+
|
|
|
|
+ var volume = volumes[ j ];
|
|
|
|
+ var newGeometry = new THREE.BufferGeometry();
|
|
|
|
+ var indexes = Uint32Array.from( volume.triangles );
|
|
|
|
+ var material = objDefaultMaterial;
|
|
|
|
+
|
|
|
|
+ newGeometry.setIndex( new THREE.BufferAttribute( indexes, 1 ) );
|
|
|
|
+ newGeometry.addAttribute( 'position', vertices.clone() );
|
|
|
|
+
|
|
|
|
+ if( normals ) {
|
|
|
|
+
|
|
|
|
+ newGeometry.addAttribute( 'normal', normals.clone() );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ( amfMaterials[ volume.materialId ] !== undefined ) {
|
|
|
|
+
|
|
|
|
+ material = amfMaterials[ volume.materialId ];
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ newGeometry.scale( amfScale, amfScale, amfScale );
|
|
|
|
+ newObject.add( new THREE.Mesh( newGeometry, material.clone() ) );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
|
|
- load: function(url, onLoad, onProgress, onError) {
|
|
|
|
- var scope = this;
|
|
|
|
|
|
+ sceneObject.add( newObject );
|
|
|
|
|
|
- var loader = new THREE.XHRLoader(scope.manager);
|
|
|
|
- loader.setCrossOrigin(this.crossOrigin);
|
|
|
|
- loader.setResponseType('arraybuffer');
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- loader.load(url, function(text) {
|
|
|
|
- var amfobject = scope.parse(text);
|
|
|
|
- onLoad(amfobject);
|
|
|
|
- }, onProgress, onError);
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- parse: function(data) {
|
|
|
|
- var amfName = "";
|
|
|
|
- var amfAuthor = "";
|
|
|
|
- var amfScale = 1.0;
|
|
|
|
- var amfMaterials = {};
|
|
|
|
- var amfObjects = {};
|
|
|
|
-
|
|
|
|
- var xmldata = this.loaddocument(data);
|
|
|
|
-
|
|
|
|
- amfScale = this.loaddocumentscale(xmldata);
|
|
|
|
-
|
|
|
|
- var documentchildren = xmldata.documentElement.children;
|
|
|
|
-
|
|
|
|
- for(var i = 0; i < documentchildren.length; i++) {
|
|
|
|
- if(documentchildren[i].nodeName === 'metadata') {
|
|
|
|
- if(documentchildren[i].attributes['type'] !== undefined) {
|
|
|
|
- if(documentchildren[i].attributes['type'].value === 'name') {
|
|
|
|
- amfName = documentchildren[i].textContent;
|
|
|
|
- } else if(documentchildren[i].attributes['type'].value === 'author') {
|
|
|
|
- amfAuthor = documentchildren[i].textContent;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else if(documentchildren[i].nodeName === 'material') {
|
|
|
|
- var loadedmaterial = this.loadmaterials(documentchildren[i]);
|
|
|
|
- amfMaterials[loadedmaterial.id] = loadedmaterial.material;
|
|
|
|
- } else if(documentchildren[i].nodeName === 'object') {
|
|
|
|
- var loadedobject = this.loadobject(documentchildren[i]);
|
|
|
|
- amfObjects[loadedobject.id] = loadedobject.obj;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var sceneobject = new THREE.Object3D();
|
|
|
|
-
|
|
|
|
- sceneobject.name = amfName;
|
|
|
|
- sceneobject.userData.author = amfAuthor;
|
|
|
|
- sceneobject.userData.loader = "AMF";
|
|
|
|
|
|
+ return sceneObject;
|
|
|
|
|
|
- var defaultmaterial = new THREE.MeshPhongMaterial({shading: THREE.FlatShading, color: 0xaaaaff});
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- for(var objid in amfObjects) {
|
|
|
|
- var newobject = new THREE.Object3D();
|
|
|
|
-
|
|
|
|
- for(var meshi = 0; meshi < amfObjects[objid].meshes.length; meshi++) {
|
|
|
|
- var meshvertices = Float32Array.from(amfObjects[objid].meshes[meshi].vertices);
|
|
|
|
- var vertices = new THREE.BufferAttribute(Float32Array.from(meshvertices), 3);
|
|
|
|
- var objdefaultmaterial = defaultmaterial;
|
|
|
|
-
|
|
|
|
- if(amfObjects[objid].meshes[meshi].color) {
|
|
|
|
- var color = amfObjects[objid].meshes[meshi].color;
|
|
|
|
- objdefaultmaterial = defaultmaterial.clone();
|
|
|
|
- objdefaultmaterial.color = new THREE.Color(color.r, color.g, color.b);
|
|
|
|
-
|
|
|
|
- if(color.a != 1.0) {
|
|
|
|
- objdefaultmaterial.transparent = true;
|
|
|
|
- objdefaultmaterial.opacity = color.a;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for(var voli = 0; voli < amfObjects[objid].meshes[meshi].volumes.length; voli++) {
|
|
|
|
- var currvolume = amfObjects[objid].meshes[meshi].volumes[voli];
|
|
|
|
- var newgeometry = new THREE.BufferGeometry();
|
|
|
|
- var indexes = Uint32Array.from(currvolume.triangles);
|
|
|
|
- var normals = new Uint32Array(vertices.length);
|
|
|
|
-
|
|
|
|
- var material = objdefaultmaterial;
|
|
|
|
-
|
|
|
|
- newgeometry.addAttribute('position', vertices.clone());
|
|
|
|
- newgeometry.addAttribute('index', new THREE.BufferAttribute(indexes, 1));
|
|
|
|
-
|
|
|
|
- if(amfMaterials[currvolume.materialid] !== undefined) {
|
|
|
|
- material = amfMaterials[currvolume.materialid];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- newgeometry.scale(amfScale, amfScale, amfScale);
|
|
|
|
-
|
|
|
|
- var newmesh = new THREE.Mesh(newgeometry, material.clone());
|
|
|
|
-
|
|
|
|
- newobject.add(newmesh);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- sceneobject.add(newobject);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return sceneobject;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loaddocument: function ( data ) {
|
|
|
|
- var view = new DataView(data);
|
|
|
|
-
|
|
|
|
- var magic = String.fromCharCode(view.getUint8(0), view.getUint8(1));
|
|
|
|
-
|
|
|
|
- if(magic === "PK") {
|
|
|
|
- console.log("Loading Zip");
|
|
|
|
- var zip = null;
|
|
|
|
- var file = null;
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- zip = new JSZip(data);
|
|
|
|
- } catch (e) {
|
|
|
|
- if (e instanceof ReferenceError) {
|
|
|
|
- console.log(" jszip missing and file is compressed.");
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for(file in zip.files) {
|
|
|
|
- if(file.toLowerCase().endsWith(".amf")) {
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- console.log(" Trying to load file asset: " + file);
|
|
|
|
- view = new DataView(zip.file(file).asArrayBuffer());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(TextDecoder === undefined) {
|
|
|
|
- console.log(" TextDecoder not present. Please use TextDecoder polyfill.");
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var filetext = new TextDecoder('utf-8').decode(view);
|
|
|
|
-
|
|
|
|
- var xmldata = new DOMParser().parseFromString(filetext, 'application/xml');
|
|
|
|
-
|
|
|
|
- if(xmldata.documentElement.nodeName.toLowerCase() !== "amf") {
|
|
|
|
- console.log(" Error loading AMF - no AMF document found.");
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return xmldata;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loaddocumentscale: function ( xmldata ) {
|
|
|
|
- var scale = 1.0;
|
|
|
|
-
|
|
|
|
- var unit = xmldata.documentElement.attributes['unit'].value.toLowerCase();
|
|
|
|
-
|
|
|
|
- var scale_units = {
|
|
|
|
- 'millimeter': 1.0,
|
|
|
|
- 'inch': 25.4,
|
|
|
|
- 'feet': 304.8,
|
|
|
|
- 'meter': 1000.0,
|
|
|
|
- 'micron': 0.001
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- if(scale_units[unit] !== undefined) {
|
|
|
|
- scale = scale_units[unit];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- console.log(" Unit scale: " + scale);
|
|
|
|
- return scale;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loadmaterials: function ( node ) {
|
|
|
|
- var mat = node;
|
|
|
|
-
|
|
|
|
- var loadedmaterial = null;
|
|
|
|
- var matname = "AMF Material";
|
|
|
|
- var matid = mat.attributes['id'].textContent;
|
|
|
|
- var color;
|
|
|
|
-
|
|
|
|
- for(var i = 0; i < mat.children.length; i++) {
|
|
|
|
- var matchildel = mat.children[i];
|
|
|
|
-
|
|
|
|
- if(matchildel.nodeName === "metadata" && matchildel.attributes['type'] !== undefined) {
|
|
|
|
- if(matchildel.attributes['type'].value === 'name') {
|
|
|
|
- matname = matchildel.textContent;
|
|
|
|
- }
|
|
|
|
- } else if(matchildel.nodeName === 'color') {
|
|
|
|
- color = this.loadcolor(matchildel);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- loadedmaterial = new THREE.MeshPhongMaterial({
|
|
|
|
- shading: THREE.FlatShading,
|
|
|
|
- color: new THREE.Color(color.r, color.g, color.b),
|
|
|
|
- name: matname});
|
|
|
|
-
|
|
|
|
- if(color.opacity !== 1.0) {
|
|
|
|
- loadedmaterial.transparent = true;
|
|
|
|
- loadedmaterial.opacity = color.opacity;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return { 'id': matid, 'material': loadedmaterial };
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loadcolor: function ( node ) {
|
|
|
|
- var color = {'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0, opacity: 1.0};
|
|
|
|
-
|
|
|
|
- for(var i = 0; i < node.children.length; i++) {
|
|
|
|
- var matcolor = node.children[i];
|
|
|
|
-
|
|
|
|
- if(matcolor.nodeName === 'r') {
|
|
|
|
- color.r = matcolor.textContent;
|
|
|
|
- } else if(matcolor.nodeName === 'g') {
|
|
|
|
- color.g = matcolor.textContent;
|
|
|
|
- } else if(matcolor.nodeName === 'b') {
|
|
|
|
- color.b = matcolor.textContent;
|
|
|
|
- } else if(matcolor.nodeName === 'a') {
|
|
|
|
- color.opacity = matcolor.textContent;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return color;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loadmeshvolume: function( node ) {
|
|
|
|
- var volume = { "name": "", "triangles": [], "materialid": null };
|
|
|
|
-
|
|
|
|
- var currvolumenode = node.firstElementChild;
|
|
|
|
-
|
|
|
|
- if(node.attributes['materialid'] !== undefined) {
|
|
|
|
- volume.materialid = node.attributes['materialid'].nodeValue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- while( currvolumenode ) {
|
|
|
|
- if( currvolumenode.nodeName === "metadata" ) {
|
|
|
|
- if(currvolumenode.attributes['type'] !== undefined) {
|
|
|
|
- if(currvolumenode.attributes['type'].value === 'name') {
|
|
|
|
- volume.name = currvolumenode.textContent;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else if ( currvolumenode.nodeName === "triangle" ) {
|
|
|
|
- var trianglenode = currvolumenode.firstElementChild;
|
|
|
|
-
|
|
|
|
- while( trianglenode ) {
|
|
|
|
- if( trianglenode.nodeName === "v1" ||
|
|
|
|
- trianglenode.nodeName === "v2" ||
|
|
|
|
- trianglenode.nodeName === "v3") {
|
|
|
|
- volume.triangles.push(trianglenode.textContent);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- trianglenode = trianglenode.nextElementSibling;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- currvolumenode = currvolumenode.nextElementSibling;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return volume;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loadmeshvertices: function( node ) {
|
|
|
|
- var vert_array = [];
|
|
|
|
-
|
|
|
|
- var currverticesnode = node.firstElementChild;
|
|
|
|
-
|
|
|
|
- while( currverticesnode ) {
|
|
|
|
- if ( currverticesnode.nodeName === "vertex" ) {
|
|
|
|
- var vnode = currverticesnode.firstElementChild;
|
|
|
|
-
|
|
|
|
- while( vnode ) {
|
|
|
|
- if( vnode.nodeName === "coordinates") {
|
|
|
|
- var coordnode = vnode.firstElementChild;
|
|
|
|
-
|
|
|
|
- while( coordnode ) {
|
|
|
|
-
|
|
|
|
- if( coordnode.nodeName === "x" ||
|
|
|
|
- coordnode.nodeName === "y" ||
|
|
|
|
- coordnode.nodeName === "z") {
|
|
|
|
- vert_array.push(coordnode.textContent);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- coordnode = coordnode.nextElementSibling;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- vnode = vnode.nextElementSibling;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- currverticesnode = currverticesnode.nextElementSibling;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return vert_array;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
- loadobject: function ( node ) {
|
|
|
|
- "use strict";
|
|
|
|
- var objid = node.attributes['id'].textContent;
|
|
|
|
- var loadedobject = { "name": "amfobject", "meshes": [] };
|
|
|
|
-
|
|
|
|
- var currcolor = null;
|
|
|
|
-
|
|
|
|
- var currobjnode = node.firstElementChild;
|
|
|
|
-
|
|
|
|
- while( currobjnode ) {
|
|
|
|
- if(currobjnode.nodeName === "metadata") {
|
|
|
|
- if(currobjnode.attributes['type'] !== undefined) {
|
|
|
|
- if(currobjnode.attributes['type'].value === 'name') {
|
|
|
|
- loadedobject.name = currobjnode.textContent;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else if(currobjnode.nodeName === "color") {
|
|
|
|
- currcolor = this.loadcolor(currobjnode);
|
|
|
|
- } else if(currobjnode.nodeName === "mesh") {
|
|
|
|
- var currmeshnode = currobjnode.firstElementChild;
|
|
|
|
- var mesh = {"vertices": [], "volumes": [], "color": currcolor };
|
|
|
|
-
|
|
|
|
- while( currmeshnode ) {
|
|
|
|
- if(currmeshnode.nodeName === "vertices") {
|
|
|
|
- mesh.vertices = mesh.vertices.concat(this.loadmeshvertices(currmeshnode));
|
|
|
|
- } else if(currmeshnode.nodeName === "volume") {
|
|
|
|
- mesh.volumes.push(this.loadmeshvolume(currmeshnode));
|
|
|
|
- }
|
|
|
|
- currmeshnode = currmeshnode.nextElementSibling;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- loadedobject.meshes.push(mesh);
|
|
|
|
- }
|
|
|
|
- currobjnode = currobjnode.nextElementSibling;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return { 'id': objid, 'obj': loadedobject };
|
|
|
|
- }
|
|
|
|
};
|
|
};
|