522 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			522 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									BufferGeometry,
							 | 
						||
| 
								 | 
							
									Color,
							 | 
						||
| 
								 | 
							
									FileLoader,
							 | 
						||
| 
								 | 
							
									Float32BufferAttribute,
							 | 
						||
| 
								 | 
							
									Group,
							 | 
						||
| 
								 | 
							
									Loader,
							 | 
						||
| 
								 | 
							
									Mesh,
							 | 
						||
| 
								 | 
							
									MeshPhongMaterial
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								import * as fflate from '../libs/fflate.module.js';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Description: Early release of an AMF Loader following the pattern of the
							 | 
						||
| 
								 | 
							
								 * example loaders in the three.js project.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Usage:
							 | 
						||
| 
								 | 
							
								 *	const loader = new AMFLoader();
							 | 
						||
| 
								 | 
							
								 *	loader.load('/path/to/project.amf', function(objecttree) {
							 | 
						||
| 
								 | 
							
								 *		scene.add(objecttree);
							 | 
						||
| 
								 | 
							
								 *	});
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Materials now supported, material colors supported
							 | 
						||
| 
								 | 
							
								 * Zip support, requires fflate
							 | 
						||
| 
								 | 
							
								 * No constellation support (yet)!
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class AMFLoader extends Loader {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor( manager ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										super( manager );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									load( url, onLoad, onProgress, onError ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const scope = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const loader = new FileLoader( scope.manager );
							 | 
						||
| 
								 | 
							
										loader.setPath( scope.path );
							 | 
						||
| 
								 | 
							
										loader.setResponseType( 'arraybuffer' );
							 | 
						||
| 
								 | 
							
										loader.setRequestHeader( scope.requestHeader );
							 | 
						||
| 
								 | 
							
										loader.setWithCredentials( scope.withCredentials );
							 | 
						||
| 
								 | 
							
										loader.load( url, function ( text ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											try {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												onLoad( scope.parse( text ) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											} catch ( e ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( onError ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													onError( e );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													console.error( e );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												scope.manager.itemError( url );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}, onProgress, onError );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									parse( data ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function loadDocument( data ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let view = new DataView( data );
							 | 
						||
| 
								 | 
							
											const magic = String.fromCharCode( view.getUint8( 0 ), view.getUint8( 1 ) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( magic === 'PK' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												let zip = null;
							 | 
						||
| 
								 | 
							
												let file = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												console.log( 'THREE.AMFLoader: Loading Zip' );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												try {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													zip = fflate.unzipSync( new Uint8Array( data ) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												} catch ( e ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( e instanceof ReferenceError ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														console.log( 'THREE.AMFLoader: fflate missing and file is compressed.' );
							 | 
						||
| 
								 | 
							
														return null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for ( file in zip ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( file.toLowerCase().slice( - 4 ) === '.amf' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												console.log( 'THREE.AMFLoader: Trying to load file asset: ' + file );
							 | 
						||
| 
								 | 
							
												view = new DataView( zip[ file ].buffer );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const fileText = new TextDecoder().decode( view );
							 | 
						||
| 
								 | 
							
											const xmlData = new DOMParser().parseFromString( fileText, 'application/xml' );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( xmlData.documentElement.nodeName.toLowerCase() !== 'amf' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												console.log( 'THREE.AMFLoader: Error loading AMF - no AMF document found.' );
							 | 
						||
| 
								 | 
							
												return null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return xmlData;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function loadDocumentScale( node ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let scale = 1.0;
							 | 
						||
| 
								 | 
							
											let unit = 'millimeter';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( node.documentElement.attributes.unit !== undefined ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												unit = node.documentElement.attributes.unit.value.toLowerCase();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const 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( 'THREE.AMFLoader: Unit scale: ' + scale );
							 | 
						||
| 
								 | 
							
											return scale;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function loadMaterials( node ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let matName = 'AMF Material';
							 | 
						||
| 
								 | 
							
											const matId = node.attributes.id.textContent;
							 | 
						||
| 
								 | 
							
											let color = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let loadedMaterial = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for ( let i = 0; i < node.childNodes.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const matChildEl = node.childNodes[ 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 MeshPhongMaterial( {
							 | 
						||
| 
								 | 
							
												flatShading: true,
							 | 
						||
| 
								 | 
							
												color: new 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 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const color = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for ( let i = 0; i < node.childNodes.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const matColor = node.childNodes[ 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 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const volume = { name: '', triangles: [], materialid: null };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let 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' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const v1 = currVolumeNode.getElementsByTagName( 'v1' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
													const v2 = currVolumeNode.getElementsByTagName( 'v2' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
													const v3 = currVolumeNode.getElementsByTagName( 'v3' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													volume.triangles.push( v1, v2, v3 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												currVolumeNode = currVolumeNode.nextElementSibling;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return volume;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function loadMeshVertices( node ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const vertArray = [];
							 | 
						||
| 
								 | 
							
											const normalArray = [];
							 | 
						||
| 
								 | 
							
											let currVerticesNode = node.firstElementChild;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											while ( currVerticesNode ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( currVerticesNode.nodeName === 'vertex' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													let vNode = currVerticesNode.firstElementChild;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													while ( vNode ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														if ( vNode.nodeName === 'coordinates' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															const x = vNode.getElementsByTagName( 'x' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
															const y = vNode.getElementsByTagName( 'y' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
															const z = vNode.getElementsByTagName( 'z' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															vertArray.push( x, y, z );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														} else if ( vNode.nodeName === 'normal' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															const nx = vNode.getElementsByTagName( 'nx' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
															const ny = vNode.getElementsByTagName( 'ny' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
															const nz = vNode.getElementsByTagName( 'nz' )[ 0 ].textContent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															normalArray.push( nx, ny, nz );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														vNode = vNode.nextElementSibling;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												currVerticesNode = currVerticesNode.nextElementSibling;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return { 'vertices': vertArray, 'normals': normalArray };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										function loadObject( node ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const objId = node.attributes.id.textContent;
							 | 
						||
| 
								 | 
							
											const loadedObject = { name: 'amfobject', meshes: [] };
							 | 
						||
| 
								 | 
							
											let currColor = null;
							 | 
						||
| 
								 | 
							
											let 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' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													let currMeshNode = currObjNode.firstElementChild;
							 | 
						||
| 
								 | 
							
													const mesh = { vertices: [], normals: [], volumes: [], color: currColor };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													while ( currMeshNode ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														if ( currMeshNode.nodeName === 'vertices' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
															const 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 };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const xmlData = loadDocument( data );
							 | 
						||
| 
								 | 
							
										let amfName = '';
							 | 
						||
| 
								 | 
							
										let amfAuthor = '';
							 | 
						||
| 
								 | 
							
										const amfScale = loadDocumentScale( xmlData );
							 | 
						||
| 
								 | 
							
										const amfMaterials = {};
							 | 
						||
| 
								 | 
							
										const amfObjects = {};
							 | 
						||
| 
								 | 
							
										const childNodes = xmlData.documentElement.childNodes;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										let i, j;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( i = 0; i < childNodes.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const child = childNodes[ 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' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const loadedMaterial = loadMaterials( child );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												amfMaterials[ loadedMaterial.id ] = loadedMaterial.material;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											} else if ( child.nodeName === 'object' ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const loadedObject = loadObject( child );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												amfObjects[ loadedObject.id ] = loadedObject.obj;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const sceneObject = new Group();
							 | 
						||
| 
								 | 
							
										const defaultMaterial = new MeshPhongMaterial( {
							 | 
						||
| 
								 | 
							
											name: Loader.DEFAULT_MATERIAL_NAME,
							 | 
						||
| 
								 | 
							
											color: 0xaaaaff,
							 | 
						||
| 
								 | 
							
											flatShading: true
							 | 
						||
| 
								 | 
							
										} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										sceneObject.name = amfName;
							 | 
						||
| 
								 | 
							
										sceneObject.userData.author = amfAuthor;
							 | 
						||
| 
								 | 
							
										sceneObject.userData.loader = 'AMF';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( const id in amfObjects ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const part = amfObjects[ id ];
							 | 
						||
| 
								 | 
							
											const meshes = part.meshes;
							 | 
						||
| 
								 | 
							
											const newObject = new Group();
							 | 
						||
| 
								 | 
							
											newObject.name = part.name || '';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for ( i = 0; i < meshes.length; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												let objDefaultMaterial = defaultMaterial;
							 | 
						||
| 
								 | 
							
												const mesh = meshes[ i ];
							 | 
						||
| 
								 | 
							
												const vertices = new Float32BufferAttribute( mesh.vertices, 3 );
							 | 
						||
| 
								 | 
							
												let normals = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( mesh.normals.length ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													normals = new Float32BufferAttribute( mesh.normals, 3 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( mesh.color ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const color = mesh.color;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													objDefaultMaterial = defaultMaterial.clone();
							 | 
						||
| 
								 | 
							
													objDefaultMaterial.color = new Color( color.r, color.g, color.b );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( color.a !== 1.0 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														objDefaultMaterial.transparent = true;
							 | 
						||
| 
								 | 
							
														objDefaultMaterial.opacity = color.a;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const volumes = mesh.volumes;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for ( j = 0; j < volumes.length; j ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													const volume = volumes[ j ];
							 | 
						||
| 
								 | 
							
													const newGeometry = new BufferGeometry();
							 | 
						||
| 
								 | 
							
													let material = objDefaultMaterial;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													newGeometry.setIndex( volume.triangles );
							 | 
						||
| 
								 | 
							
													newGeometry.setAttribute( 'position', vertices.clone() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( normals ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														newGeometry.setAttribute( 'normal', normals.clone() );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( amfMaterials[ volume.materialId ] !== undefined ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														material = amfMaterials[ volume.materialId ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													newGeometry.scale( amfScale, amfScale, amfScale );
							 | 
						||
| 
								 | 
							
													newObject.add( new Mesh( newGeometry, material.clone() ) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											sceneObject.add( newObject );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return sceneObject;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { AMFLoader };
							 |