FBXLoader.js 118.2 KB
Newer Older
Y
yamahigashi 已提交
1
/**
K
Kyle Larson 已提交
2
 * @author Kyle-Larson https://github.com/Kyle-Larson
M
Mr.doob 已提交
3
 * @author Takahiro https://github.com/takahirox
Y
yamahigashi 已提交
4
 *
M
Mr.doob 已提交
5 6
 * Loader loads FBX file and generates Group representing FBX scene.
 * Requires FBX file to be >= 7.0 and in ASCII or to be any version in Binary format.
Y
yamahigashi 已提交
7
 *
M
Mr.doob 已提交
8 9 10 11 12 13 14 15 16
 * Supports:
 * 	Mesh Generation (Positional Data)
 * 	Normal Data (Per Vertex Drawing Instance)
 *  UV Data (Per Vertex Drawing Instance)
 *  Skinning
 *  Animation
 * 	- Separated Animations based on stacks.
 * 	- Skeletal & Non-Skeletal Animations
 *  NURBS (Open, Closed and Periodic forms)
Y
yamahigashi 已提交
17
 *
M
Mr.doob 已提交
18 19 20
 * Needs Support:
 * 	Indexed Buffers
 * 	PreRotation support.
Y
yamahigashi 已提交
21 22
 */

23
( function () {
Y
yamahigashi 已提交
24

M
Mr.doob 已提交
25 26 27 28 29
	/**
	 * Generates a loader for loading FBX files from URL and parsing into
	 * a THREE.Group.
	 * @param {THREE.LoadingManager} manager - Loading Manager for loader to use.
	 */
M
Mr.doob 已提交
30
	THREE.FBXLoader = function ( manager ) {
Y
yamahigashi 已提交
31

Y
yamahigashi 已提交
32
		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
Y
yamahigashi 已提交
33

Y
yamahigashi 已提交
34
	};
Y
yamahigashi 已提交
35

36
	Object.assign( THREE.FBXLoader.prototype, {
Y
yamahigashi 已提交
37

M
Mr.doob 已提交
38 39 40 41 42 43 44 45 46
		/**
		 * Loads an ASCII/Binary FBX file from URL and parses into a THREE.Group.
		 * THREE.Group will have an animations property of AnimationClips
		 * of the different animations exported with the FBX.
		 * @param {string} url - URL of the FBX file.
		 * @param {function(THREE.Group):void} onLoad - Callback for when FBX file is loaded and parsed.
		 * @param {function(ProgressEvent):void} onProgress - Callback fired periodically when file is being retrieved from server.
		 * @param {function(Event):void} onError - Callback fired when error occurs (Currently only with retrieving file, not with parsing errors).
		 */
47
		load: function ( url, onLoad, onProgress, onError ) {
Y
yamahigashi 已提交
48

M
Mr.doob 已提交
49
			var self = this;
Y
yamahigashi 已提交
50

M
Mugen87 已提交
51
			var resourceDirectory = THREE.Loader.prototype.extractUrlBase( url );
Y
yamahigashi 已提交
52

M
Mr.doob 已提交
53 54 55
			var loader = new THREE.FileLoader( this.manager );
			loader.setResponseType( 'arraybuffer' );
			loader.load( url, function ( buffer ) {
Y
yamahigashi 已提交
56

M
Mr.doob 已提交
57
				try {
Y
yamahigashi 已提交
58

M
Mr.doob 已提交
59
					var scene = self.parse( buffer, resourceDirectory );
Y
yamahigashi 已提交
60

M
Mr.doob 已提交
61
					onLoad( scene );
Y
yamahigashi 已提交
62

M
Mr.doob 已提交
63
				} catch ( error ) {
Y
yamahigashi 已提交
64

M
Mr.doob 已提交
65
					window.setTimeout( function () {
Y
yamahigashi 已提交
66

M
Mr.doob 已提交
67
						if ( onError ) onError( error );
Y
yamahigashi 已提交
68

M
Mr.doob 已提交
69
						self.manager.itemError( url );
Y
yamahigashi 已提交
70

M
Mr.doob 已提交
71
					}, 0 );
Y
yamahigashi 已提交
72

M
Mr.doob 已提交
73
				}
Y
yamahigashi 已提交
74

M
Mr.doob 已提交
75
			}, onProgress, onError );
Y
yamahigashi 已提交
76

77
		},
Y
yamahigashi 已提交
78

M
Mr.doob 已提交
79 80 81 82 83 84 85 86 87
		/**
		 * Parses an ASCII/Binary FBX file and returns a THREE.Group.
		 * THREE.Group will have an animations property of AnimationClips
		 * of the different animations within the FBX file.
		 * @param {ArrayBuffer} FBXBuffer - Contents of FBX file to parse.
		 * @param {string} resourceDirectory - Directory to load external assets (e.g. textures ) from.
		 * @returns {THREE.Group}
		 */
		parse: function ( FBXBuffer, resourceDirectory ) {
Y
yamahigashi 已提交
88

M
Mr.doob 已提交
89
			var FBXTree;
Y
yamahigashi 已提交
90

M
Mr.doob 已提交
91
			if ( isFbxFormatBinary( FBXBuffer ) ) {
Y
yamahigashi 已提交
92

M
Mr.doob 已提交
93
				FBXTree = new BinaryParser().parse( FBXBuffer );
Y
yamahigashi 已提交
94

M
Mr.doob 已提交
95
			} else {
Y
yamahigashi 已提交
96

M
Mr.doob 已提交
97
				var FBXText = convertArrayBufferToString( FBXBuffer );
Y
yamahigashi 已提交
98

M
Mr.doob 已提交
99
				if ( ! isFbxFormatASCII( FBXText ) ) {
Y
yamahigashi 已提交
100

M
Mugen87 已提交
101
					throw new Error( 'THREE.FBXLoader: Unknown format.' );
Y
yamahigashi 已提交
102

103
				}
Y
yamahigashi 已提交
104

M
Mr.doob 已提交
105
				if ( getFbxVersion( FBXText ) < 7000 ) {
Y
yamahigashi 已提交
106

M
Mugen87 已提交
107
					throw new Error( 'THREE.FBXLoader: FBX version not supported, FileVersion: ' + getFbxVersion( FBXText ) );
Y
yamahigashi 已提交
108

M
Mr.doob 已提交
109
				}
Y
yamahigashi 已提交
110

M
Mr.doob 已提交
111
				FBXTree = new TextParser().parse( FBXText );
Y
yamahigashi 已提交
112

113
			}
M
Mr.doob 已提交
114

L
Lewy Blue 已提交
115
			// console.log( FBXTree );
M
Mr.doob 已提交
116

M
Mr.doob 已提交
117 118 119 120 121 122 123
			var connections = parseConnections( FBXTree );
			var images = parseImages( FBXTree );
			var textures = parseTextures( FBXTree, new THREE.TextureLoader( this.manager ).setPath( resourceDirectory ), images, connections );
			var materials = parseMaterials( FBXTree, textures, connections );
			var deformers = parseDeformers( FBXTree, connections );
			var geometryMap = parseGeometries( FBXTree, connections, deformers );
			var sceneGraph = parseScene( FBXTree, connections, deformers, geometryMap, materials );
Y
yamahigashi 已提交
124

M
Mr.doob 已提交
125
			return sceneGraph;
Y
yamahigashi 已提交
126

M
Mr.doob 已提交
127
		}
M
Mr.doob 已提交
128

M
Mr.doob 已提交
129
	} );
Y
yamahigashi 已提交
130

M
Mr.doob 已提交
131 132 133 134 135 136
	/**
	 * Parses map of relationships between objects.
	 * @param {{Connections: { properties: { connections: [number, number, string][]}}}} FBXTree
	 * @returns {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>}
	 */
	function parseConnections( FBXTree ) {
Y
yamahigashi 已提交
137

M
Mr.doob 已提交
138 139 140 141
		/**
		 * @type {Map<number, { parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>}
		 */
		var connectionMap = new Map();
K
Kyle Larson 已提交
142

M
Mr.doob 已提交
143
		if ( 'Connections' in FBXTree ) {
Y
yamahigashi 已提交
144

M
Mr.doob 已提交
145 146 147 148 149
			/**
			 * @type {[number, number, string][]}
			 */
			var connectionArray = FBXTree.Connections.properties.connections;
			for ( var connectionArrayIndex = 0, connectionArrayLength = connectionArray.length; connectionArrayIndex < connectionArrayLength; ++ connectionArrayIndex ) {
Y
yamahigashi 已提交
150

M
Mr.doob 已提交
151
				var connection = connectionArray[ connectionArrayIndex ];
Y
yamahigashi 已提交
152

M
Mr.doob 已提交
153
				if ( ! connectionMap.has( connection[ 0 ] ) ) {
Y
yamahigashi 已提交
154

M
Mr.doob 已提交
155 156 157 158
					connectionMap.set( connection[ 0 ], {
						parents: [],
						children: []
					} );
Y
yamahigashi 已提交
159

160
				}
Y
yamahigashi 已提交
161

M
Mr.doob 已提交
162 163
				var parentRelationship = { ID: connection[ 1 ], relationship: connection[ 2 ] };
				connectionMap.get( connection[ 0 ] ).parents.push( parentRelationship );
Y
yamahigashi 已提交
164

M
Mr.doob 已提交
165
				if ( ! connectionMap.has( connection[ 1 ] ) ) {
Y
yamahigashi 已提交
166

M
Mr.doob 已提交
167 168 169 170
					connectionMap.set( connection[ 1 ], {
						parents: [],
						children: []
					} );
Y
yamahigashi 已提交
171

M
Mr.doob 已提交
172
				}
Y
yamahigashi 已提交
173

M
Mr.doob 已提交
174 175
				var childRelationship = { ID: connection[ 0 ], relationship: connection[ 2 ] };
				connectionMap.get( connection[ 1 ] ).children.push( childRelationship );
Y
yamahigashi 已提交
176

177
			}
Y
yamahigashi 已提交
178

M
Mr.doob 已提交
179
		}
Y
yamahigashi 已提交
180

M
Mr.doob 已提交
181
		return connectionMap;
K
Kyle Larson 已提交
182

M
Mr.doob 已提交
183
	}
K
Kyle Larson 已提交
184

M
Mr.doob 已提交
185 186 187
	/**
	 * Parses map of images referenced in FBXTree.
	 * @param {{Objects: {subNodes: {Texture: Object.<string, FBXTextureNode>}}}} FBXTree
188
	 * @returns {Map<number, string(image blob/data URL)>}
M
Mr.doob 已提交
189 190
	 */
	function parseImages( FBXTree ) {
K
Kyle Larson 已提交
191

M
Mr.doob 已提交
192
		/**
193
		 * @type {Map<number, string(image blob/data URL)>}
M
Mr.doob 已提交
194 195
		 */
		var imageMap = new Map();
K
Kyle Larson 已提交
196

M
Mr.doob 已提交
197
		if ( 'Video' in FBXTree.Objects.subNodes ) {
K
Kyle Larson 已提交
198

M
Mr.doob 已提交
199
			var videoNodes = FBXTree.Objects.subNodes.Video;
K
Kyle Larson 已提交
200

M
Mr.doob 已提交
201
			for ( var nodeID in videoNodes ) {
K
Kyle Larson 已提交
202

M
Mr.doob 已提交
203
				var videoNode = videoNodes[ nodeID ];
K
Kyle Larson 已提交
204

M
Mr.doob 已提交
205 206
				// raw image data is in videoNode.properties.Content
				if ( 'Content' in videoNode.properties ) {
K
Kyle Larson 已提交
207

M
Mr.doob 已提交
208 209
					var image = parseImage( videoNodes[ nodeID ] );
					imageMap.set( parseInt( nodeID ), image );
K
Kyle Larson 已提交
210

M
Mr.doob 已提交
211
				}
K
Kyle Larson 已提交
212

M
Mr.doob 已提交
213
			}
K
Kyle Larson 已提交
214

M
Mr.doob 已提交
215
		}
K
Kyle Larson 已提交
216

M
Mr.doob 已提交
217
		return imageMap;
K
Kyle Larson 已提交
218

M
Mr.doob 已提交
219
	}
K
Kyle Larson 已提交
220

M
Mr.doob 已提交
221 222
	/**
	 * @param {videoNode} videoNode - Node to get texture image information from.
223
	 * @returns {string} - image blob/data URL
M
Mr.doob 已提交
224 225
	 */
	function parseImage( videoNode ) {
K
Kyle Larson 已提交
226

227
		var content = videoNode.properties.Content;
M
Mr.doob 已提交
228 229
		var fileName = videoNode.properties.RelativeFilename || videoNode.properties.Filename;
		var extension = fileName.slice( fileName.lastIndexOf( '.' ) + 1 ).toLowerCase();
K
Kyle Larson 已提交
230

M
Mr.doob 已提交
231
		var type;
K
Kyle Larson 已提交
232

M
Mr.doob 已提交
233
		switch ( extension ) {
K
Kyle Larson 已提交
234

M
Mr.doob 已提交
235
			case 'bmp':
K
Kyle Larson 已提交
236

M
Mr.doob 已提交
237 238
				type = 'image/bmp';
				break;
K
Kyle Larson 已提交
239

M
Mr.doob 已提交
240
			case 'jpg':
K
Kyle Larson 已提交
241

M
Mr.doob 已提交
242 243
				type = 'image/jpeg';
				break;
K
Kyle Larson 已提交
244

M
Mr.doob 已提交
245
			case 'png':
K
Kyle Larson 已提交
246

M
Mr.doob 已提交
247 248
				type = 'image/png';
				break;
K
Kyle Larson 已提交
249

M
Mr.doob 已提交
250
			case 'tif':
K
Kyle Larson 已提交
251

M
Mr.doob 已提交
252 253
				type = 'image/tiff';
				break;
K
Kyle Larson 已提交
254

M
Mr.doob 已提交
255
			default:
K
Kyle Larson 已提交
256

M
Mr.doob 已提交
257 258
				console.warn( 'FBXLoader: No support image type ' + extension );
				return;
K
Kyle Larson 已提交
259

M
Mr.doob 已提交
260
		}
K
Kyle Larson 已提交
261

262 263 264 265 266 267 268 269 270 271
		if ( typeof content === 'string' ) {

			return 'data:' + type + ';base64,' + content;

		} else {

			var array = new Uint8Array( content );
			return window.URL.createObjectURL( new Blob( [ array ], { type: type } ) );

		}
K
Kyle Larson 已提交
272

M
Mr.doob 已提交
273
	}
K
Kyle Larson 已提交
274

M
Mr.doob 已提交
275 276 277 278
	/**
	 * Parses map of textures referenced in FBXTree.
	 * @param {{Objects: {subNodes: {Texture: Object.<string, FBXTextureNode>}}}} FBXTree
	 * @param {THREE.TextureLoader} loader
279
	 * @param {Map<number, string(image blob/data URL)>} imageMap
M
Mr.doob 已提交
280 281 282 283
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @returns {Map<number, THREE.Texture>}
	 */
	function parseTextures( FBXTree, loader, imageMap, connections ) {
K
Kyle Larson 已提交
284

M
Mr.doob 已提交
285 286 287 288
		/**
		 * @type {Map<number, THREE.Texture>}
		 */
		var textureMap = new Map();
K
Kyle Larson 已提交
289

M
Mr.doob 已提交
290
		if ( 'Texture' in FBXTree.Objects.subNodes ) {
K
Kyle Larson 已提交
291

M
Mr.doob 已提交
292 293
			var textureNodes = FBXTree.Objects.subNodes.Texture;
			for ( var nodeID in textureNodes ) {
K
Kyle Larson 已提交
294

M
Mr.doob 已提交
295 296
				var texture = parseTexture( textureNodes[ nodeID ], loader, imageMap, connections );
				textureMap.set( parseInt( nodeID ), texture );
K
Kyle Larson 已提交
297

M
Mr.doob 已提交
298
			}
K
Kyle Larson 已提交
299

M
Mr.doob 已提交
300
		}
K
Kyle Larson 已提交
301

M
Mr.doob 已提交
302
		return textureMap;
K
Kyle Larson 已提交
303

M
Mr.doob 已提交
304
	}
K
Kyle Larson 已提交
305

M
Mr.doob 已提交
306 307 308
	/**
	 * @param {textureNode} textureNode - Node to get texture information from.
	 * @param {THREE.TextureLoader} loader
309
	 * @param {Map<number, string(image blob/data URL)>} imageMap
M
Mr.doob 已提交
310 311 312 313
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @returns {THREE.Texture}
	 */
	function parseTexture( textureNode, loader, imageMap, connections ) {
K
Kyle Larson 已提交
314

M
Mr.doob 已提交
315
		var FBX_ID = textureNode.id;
K
Kyle Larson 已提交
316

M
Mr.doob 已提交
317
		var name = textureNode.name;
K
Kyle Larson 已提交
318

M
Mr.doob 已提交
319
		var fileName;
K
Kyle Larson 已提交
320

M
Mr.doob 已提交
321 322
		var filePath = textureNode.properties.FileName;
		var relativeFilePath = textureNode.properties.RelativeFilename;
K
Kyle Larson 已提交
323

M
Mr.doob 已提交
324
		var children = connections.get( FBX_ID ).children;
K
Kyle Larson 已提交
325

M
Mr.doob 已提交
326
		if ( children !== undefined && children.length > 0 && imageMap.has( children[ 0 ].ID ) ) {
K
Kyle Larson 已提交
327

M
Mr.doob 已提交
328
			fileName = imageMap.get( children[ 0 ].ID );
K
Kyle Larson 已提交
329

M
Mr.doob 已提交
330 331
		} else if ( relativeFilePath !== undefined && relativeFilePath[ 0 ] !== '/' &&
				relativeFilePath.match( /^[a-zA-Z]:/ ) === null ) {
K
Kyle Larson 已提交
332

M
Mr.doob 已提交
333 334
			// use textureNode.properties.RelativeFilename
			// if it exists and it doesn't seem an absolute path
K
Kyle Larson 已提交
335

M
Mr.doob 已提交
336
			fileName = relativeFilePath;
K
Kyle Larson 已提交
337

M
Mr.doob 已提交
338
		} else {
K
Kyle Larson 已提交
339

M
Mr.doob 已提交
340
			var split = filePath.split( /[\\\/]/ );
K
Kyle Larson 已提交
341

M
Mr.doob 已提交
342
			if ( split.length > 0 ) {
K
Kyle Larson 已提交
343

M
Mr.doob 已提交
344
				fileName = split[ split.length - 1 ];
K
Kyle Larson 已提交
345

M
Mr.doob 已提交
346
			} else {
K
Kyle Larson 已提交
347

M
Mr.doob 已提交
348
				fileName = filePath;
349

M
Mr.doob 已提交
350
			}
351

M
Mr.doob 已提交
352
		}
K
Kyle Larson 已提交
353

M
Mr.doob 已提交
354
		var currentPath = loader.path;
K
Kyle Larson 已提交
355

356
		if ( fileName.indexOf( 'blob:' ) === 0 || fileName.indexOf( 'data:' ) === 0 ) {
K
Kyle Larson 已提交
357

M
Mr.doob 已提交
358
			loader.setPath( undefined );
K
Kyle Larson 已提交
359

M
Mr.doob 已提交
360
		}
361

M
Mr.doob 已提交
362 363 364 365 366 367
		/**
		 * @type {THREE.Texture}
		 */
		var texture = loader.load( fileName );
		texture.name = name;
		texture.FBX_ID = FBX_ID;
368

369 370 371 372 373 374 375 376 377 378 379 380
		var wrapModeU = textureNode.properties.WrapModeU;
		var wrapModeV = textureNode.properties.WrapModeV;

		var valueU = wrapModeU !== undefined ? wrapModeU.value : 0;
		var valueV = wrapModeV !== undefined ? wrapModeV.value : 0;

		// http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a
		// 0: repeat(default), 1: clamp

		texture.wrapS = valueU === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
		texture.wrapT = valueV === 0 ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;

M
Mr.doob 已提交
381
		loader.setPath( currentPath );
382

M
Mr.doob 已提交
383
		return texture;
384

M
Mr.doob 已提交
385
	}
386

M
Mr.doob 已提交
387 388 389 390 391 392 393 394
	/**
	 * Parses map of Material information.
	 * @param {{Objects: {subNodes: {Material: Object.<number, FBXMaterialNode>}}}} FBXTree
	 * @param {Map<number, THREE.Texture>} textureMap
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @returns {Map<number, THREE.Material>}
	 */
	function parseMaterials( FBXTree, textureMap, connections ) {
395

M
Mr.doob 已提交
396
		var materialMap = new Map();
397

M
Mr.doob 已提交
398
		if ( 'Material' in FBXTree.Objects.subNodes ) {
399

M
Mr.doob 已提交
400 401
			var materialNodes = FBXTree.Objects.subNodes.Material;
			for ( var nodeID in materialNodes ) {
402

M
Mr.doob 已提交
403
				var material = parseMaterial( materialNodes[ nodeID ], textureMap, connections );
T
Takahiro 已提交
404
				if ( material !== null ) materialMap.set( parseInt( nodeID ), material );
405

M
Mr.doob 已提交
406
			}
407

M
Mr.doob 已提交
408
		}
409

M
Mr.doob 已提交
410
		return materialMap;
411

M
Mr.doob 已提交
412
	}
413

M
Mr.doob 已提交
414 415 416 417 418 419 420 421
	/**
	 * Takes information from Material node and returns a generated THREE.Material
	 * @param {FBXMaterialNode} materialNode
	 * @param {Map<number, THREE.Texture>} textureMap
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @returns {THREE.Material}
	 */
	function parseMaterial( materialNode, textureMap, connections ) {
422

M
Mr.doob 已提交
423 424 425
		var FBX_ID = materialNode.id;
		var name = materialNode.attrName;
		var type = materialNode.properties.ShadingModel;
426

M
Mr.doob 已提交
427 428
		//Case where FBXs wrap shading model in property object.
		if ( typeof type === 'object' ) {
429

M
Mr.doob 已提交
430
			type = type.value;
431

M
Mr.doob 已提交
432
		}
433

T
Takahiro 已提交
434 435 436 437
		// Seems like FBX can include unused materials which don't have any connections.
		// Ignores them so far.
		if ( ! connections.has( FBX_ID ) ) return null;

M
Mr.doob 已提交
438
		var children = connections.get( FBX_ID ).children;
439

M
Mr.doob 已提交
440
		var parameters = parseParameters( materialNode.properties, textureMap, children );
441

M
Mr.doob 已提交
442
		var material;
443

M
Mugen87 已提交
444
		switch ( type.toLowerCase() ) {
445

M
Mr.doob 已提交
446 447 448 449 450 451 452
			case 'phong':
				material = new THREE.MeshPhongMaterial();
				break;
			case 'lambert':
				material = new THREE.MeshLambertMaterial();
				break;
			default:
453 454
				console.warn( 'THREE.FBXLoader: No implementation given for material type %s in FBXLoader.js. Defaulting to standard material.', type );
				material = new THREE.MeshStandardMaterial( { color: 0x3300ff } );
M
Mr.doob 已提交
455
				break;
456

M
Mr.doob 已提交
457
		}
458

M
Mr.doob 已提交
459 460
		material.setValues( parameters );
		material.name = name;
461

M
Mr.doob 已提交
462
		return material;
463

M
Mr.doob 已提交
464
	}
465

M
Mr.doob 已提交
466 467 468 469 470 471 472 473 474 475 476 477 478
	/**
	 * @typedef {{Diffuse: FBXVector3, Specular: FBXVector3, Shininess: FBXValue, Emissive: FBXVector3, EmissiveFactor: FBXValue, Opacity: FBXValue}} FBXMaterialProperties
	 */
	/**
	 * @typedef {{color: THREE.Color=, specular: THREE.Color=, shininess: number=, emissive: THREE.Color=, emissiveIntensity: number=, opacity: number=, transparent: boolean=, map: THREE.Texture=}} THREEMaterialParameterPack
	 */
	/**
	 * @param {FBXMaterialProperties} properties
	 * @param {Map<number, THREE.Texture>} textureMap
	 * @param {{ID: number, relationship: string}[]} childrenRelationships
	 * @returns {THREEMaterialParameterPack}
	 */
	function parseParameters( properties, textureMap, childrenRelationships ) {
479

M
Mr.doob 已提交
480
		var parameters = {};
481

M
Mr.doob 已提交
482
		if ( properties.Diffuse ) {
483

M
Mr.doob 已提交
484
			parameters.color = parseColor( properties.Diffuse );
485

M
Mr.doob 已提交
486 487
		}
		if ( properties.Specular ) {
488

M
Mr.doob 已提交
489
			parameters.specular = parseColor( properties.Specular );
490

M
Mr.doob 已提交
491 492
		}
		if ( properties.Shininess ) {
493

M
Mr.doob 已提交
494
			parameters.shininess = properties.Shininess.value;
495

M
Mr.doob 已提交
496 497
		}
		if ( properties.Emissive ) {
498

M
Mr.doob 已提交
499
			parameters.emissive = parseColor( properties.Emissive );
500

M
Mr.doob 已提交
501 502
		}
		if ( properties.EmissiveFactor ) {
503

M
Mr.doob 已提交
504
			parameters.emissiveIntensity = properties.EmissiveFactor.value;
505

M
Mr.doob 已提交
506 507
		}
		if ( properties.Opacity ) {
508

M
Mr.doob 已提交
509
			parameters.opacity = properties.Opacity.value;
510

M
Mr.doob 已提交
511 512
		}
		if ( parameters.opacity < 1.0 ) {
K
Kyle Larson 已提交
513

M
Mr.doob 已提交
514
			parameters.transparent = true;
K
Kyle Larson 已提交
515

M
Mr.doob 已提交
516
		}
K
Kyle Larson 已提交
517

M
Mr.doob 已提交
518
		for ( var childrenRelationshipsIndex = 0, childrenRelationshipsLength = childrenRelationships.length; childrenRelationshipsIndex < childrenRelationshipsLength; ++ childrenRelationshipsIndex ) {
K
Kyle Larson 已提交
519

M
Mr.doob 已提交
520
			var relationship = childrenRelationships[ childrenRelationshipsIndex ];
K
Kyle Larson 已提交
521

M
Mr.doob 已提交
522
			var type = relationship.relationship;
K
Kyle Larson 已提交
523

M
Mr.doob 已提交
524
			switch ( type ) {
K
Kyle Larson 已提交
525

M
Mugen87 已提交
526 527
				case 'DiffuseColor':
				case ' "DiffuseColor':
M
Mr.doob 已提交
528 529
					parameters.map = textureMap.get( relationship.ID );
					break;
K
Kyle Larson 已提交
530

M
Mugen87 已提交
531 532
				case 'Bump':
				case ' "Bump':
533 534 535
					parameters.bumpMap = textureMap.get( relationship.ID );
					break;

M
Mugen87 已提交
536 537
				case 'NormalMap':
				case ' "NormalMap':
538 539 540
					parameters.normalMap = textureMap.get( relationship.ID );
					break;

M
Mugen87 已提交
541 542 543 544
				case 'AmbientColor':
				case 'EmissiveColor':
				case ' "AmbientColor':
				case ' "EmissiveColor':
M
Mr.doob 已提交
545
				default:
M
Mugen87 已提交
546
					console.warn( 'THREE.FBXLoader: Unknown texture application of type %s, skipping texture.', type );
M
Mr.doob 已提交
547
					break;
K
Kyle Larson 已提交
548 549 550

			}

M
Mr.doob 已提交
551
		}
K
Kyle Larson 已提交
552

M
Mr.doob 已提交
553
		return parameters;
K
Kyle Larson 已提交
554

M
Mr.doob 已提交
555
	}
K
Kyle Larson 已提交
556

M
Mr.doob 已提交
557 558 559 560 561 562 563
	/**
	 * Generates map of Skeleton-like objects for use later when generating and binding skeletons.
	 * @param {{Objects: {subNodes: {Deformer: Object.<number, FBXSubDeformerNode>}}}} FBXTree
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @returns {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}>}
	 */
	function parseDeformers( FBXTree, connections ) {
K
Kyle Larson 已提交
564

M
Mr.doob 已提交
565
		var deformers = {};
K
Kyle Larson 已提交
566

M
Mr.doob 已提交
567
		if ( 'Deformer' in FBXTree.Objects.subNodes ) {
K
Kyle Larson 已提交
568

M
Mr.doob 已提交
569
			var DeformerNodes = FBXTree.Objects.subNodes.Deformer;
570

M
Mr.doob 已提交
571
			for ( var nodeID in DeformerNodes ) {
572

M
Mr.doob 已提交
573
				var deformerNode = DeformerNodes[ nodeID ];
574

M
Mr.doob 已提交
575
				if ( deformerNode.attrType === 'Skin' ) {
576

M
Mr.doob 已提交
577 578 579
					var conns = connections.get( parseInt( nodeID ) );
					var skeleton = parseSkeleton( conns, DeformerNodes );
					skeleton.FBX_ID = parseInt( nodeID );
580

M
Mr.doob 已提交
581
					deformers[ nodeID ] = skeleton;
582 583 584

				}

K
Kyle Larson 已提交
585 586
			}

M
Mr.doob 已提交
587
		}
K
Kyle Larson 已提交
588

M
Mr.doob 已提交
589
		return deformers;
K
Kyle Larson 已提交
590

M
Mr.doob 已提交
591
	}
K
Kyle Larson 已提交
592

M
Mr.doob 已提交
593 594 595 596 597 598 599
	/**
	 * Generates a "Skeleton Representation" of FBX nodes based on an FBX Skin Deformer's connections and an object containing SubDeformer nodes.
	 * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} connections
	 * @param {Object.<number, FBXSubDeformerNode>} DeformerNodes
	 * @returns {{map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}}
	 */
	function parseSkeleton( connections, DeformerNodes ) {
K
Kyle Larson 已提交
600

M
Mr.doob 已提交
601 602
		var subDeformers = {};
		var children = connections.children;
K
Kyle Larson 已提交
603

M
Mr.doob 已提交
604
		for ( var i = 0, l = children.length; i < l; ++ i ) {
Y
yamahigashi 已提交
605

M
Mr.doob 已提交
606
			var child = children[ i ];
Y
yamahigashi 已提交
607

M
Mr.doob 已提交
608
			var subDeformerNode = DeformerNodes[ child.ID ];
Y
yamahigashi 已提交
609

M
Mr.doob 已提交
610 611 612 613 614 615 616 617 618
			var subDeformer = {
				FBX_ID: child.ID,
				index: i,
				indices: [],
				weights: [],
				transform: parseMatrixArray( subDeformerNode.subNodes.Transform.properties.a ),
				transformLink: parseMatrixArray( subDeformerNode.subNodes.TransformLink.properties.a ),
				linkMode: subDeformerNode.properties.Mode
			};
Y
yamahigashi 已提交
619

M
Mr.doob 已提交
620
			if ( 'Indexes' in subDeformerNode.subNodes ) {
Y
yamahigashi 已提交
621

M
Mr.doob 已提交
622 623
				subDeformer.indices = parseIntArray( subDeformerNode.subNodes.Indexes.properties.a );
				subDeformer.weights = parseFloatArray( subDeformerNode.subNodes.Weights.properties.a );
Y
yamahigashi 已提交
624

M
Mr.doob 已提交
625
			}
Y
yamahigashi 已提交
626

M
Mr.doob 已提交
627
			subDeformers[ child.ID ] = subDeformer;
Y
yamahigashi 已提交
628

M
Mr.doob 已提交
629
		}
Y
yamahigashi 已提交
630

M
Mr.doob 已提交
631 632 633 634
		return {
			map: subDeformers,
			bones: []
		};
Y
yamahigashi 已提交
635

M
Mr.doob 已提交
636
	}
Y
yamahigashi 已提交
637

M
Mr.doob 已提交
638 639 640 641 642 643 644 645
	/**
	 * Generates Buffer geometries from geometry information in FBXTree, and generates map of THREE.BufferGeometries
	 * @param {{Objects: {subNodes: {Geometry: Object.<number, FBXGeometryNode}}}} FBXTree
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}>} deformers
	 * @returns {Map<number, THREE.BufferGeometry>}
	 */
	function parseGeometries( FBXTree, connections, deformers ) {
Y
yamahigashi 已提交
646

M
Mr.doob 已提交
647
		var geometryMap = new Map();
Y
yamahigashi 已提交
648

M
Mr.doob 已提交
649
		if ( 'Geometry' in FBXTree.Objects.subNodes ) {
Y
yamahigashi 已提交
650

M
Mr.doob 已提交
651
			var geometryNodes = FBXTree.Objects.subNodes.Geometry;
Y
yamahigashi 已提交
652

M
Mr.doob 已提交
653
			for ( var nodeID in geometryNodes ) {
Y
yamahigashi 已提交
654

M
Mr.doob 已提交
655 656 657
				var relationships = connections.get( parseInt( nodeID ) );
				var geo = parseGeometry( geometryNodes[ nodeID ], relationships, deformers );
				geometryMap.set( parseInt( nodeID ), geo );
Y
yamahigashi 已提交
658

M
Mr.doob 已提交
659
			}
Y
yamahigashi 已提交
660

M
Mr.doob 已提交
661
		}
Y
yamahigashi 已提交
662

M
Mr.doob 已提交
663
		return geometryMap;
Y
yamahigashi 已提交
664

M
Mr.doob 已提交
665
	}
Y
yamahigashi 已提交
666

M
Mr.doob 已提交
667 668 669 670 671 672 673 674
	/**
	 * Generates BufferGeometry from FBXGeometryNode.
	 * @param {FBXGeometryNode} geometryNode
	 * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships
	 * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}>} deformers
	 * @returns {THREE.BufferGeometry}
	 */
	function parseGeometry( geometryNode, relationships, deformers ) {
Y
yamahigashi 已提交
675

M
Mr.doob 已提交
676
		switch ( geometryNode.attrType ) {
Y
yamahigashi 已提交
677

M
Mr.doob 已提交
678 679 680
			case 'Mesh':
				return parseMeshGeometry( geometryNode, relationships, deformers );
				break;
Y
yamahigashi 已提交
681

M
Mr.doob 已提交
682 683 684
			case 'NurbsCurve':
				return parseNurbsGeometry( geometryNode );
				break;
Y
yamahigashi 已提交
685

M
Mr.doob 已提交
686
		}
Y
yamahigashi 已提交
687

M
Mr.doob 已提交
688
	}
Y
yamahigashi 已提交
689

M
Mr.doob 已提交
690 691 692 693 694 695 696 697
	/**
	 * Specialty function for parsing Mesh based Geometry Nodes.
	 * @param {FBXGeometryNode} geometryNode
	 * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships - Object representing relationships between specific geometry node and other nodes.
	 * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}>} deformers - Map object of deformers and subDeformers by ID.
	 * @returns {THREE.BufferGeometry}
	 */
	function parseMeshGeometry( geometryNode, relationships, deformers ) {
Y
yamahigashi 已提交
698

M
Mr.doob 已提交
699
		for ( var i = 0; i < relationships.children.length; ++ i ) {
Y
yamahigashi 已提交
700

M
Mr.doob 已提交
701 702
			var deformer = deformers[ relationships.children[ i ].ID ];
			if ( deformer !== undefined ) break;
Y
yamahigashi 已提交
703

M
Mr.doob 已提交
704
		}
Y
yamahigashi 已提交
705

M
Mr.doob 已提交
706
		return genGeometry( geometryNode, deformer );
Y
yamahigashi 已提交
707

M
Mr.doob 已提交
708
	}
Y
yamahigashi 已提交
709

M
Mr.doob 已提交
710 711 712 713 714
	/**
	 * @param {{map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[]}} deformer - Skeleton representation for geometry instance.
	 * @returns {THREE.BufferGeometry}
	 */
	function genGeometry( geometryNode, deformer ) {
Y
yamahigashi 已提交
715

M
Mr.doob 已提交
716
		var geometry = new Geometry();
Y
yamahigashi 已提交
717

M
Mr.doob 已提交
718
		var subNodes = geometryNode.subNodes;
Y
yamahigashi 已提交
719

M
Mr.doob 已提交
720
		// First, each index is going to be its own vertex.
Y
yamahigashi 已提交
721

M
Mr.doob 已提交
722 723
		var vertexBuffer = parseFloatArray( subNodes.Vertices.properties.a );
		var indexBuffer = parseIntArray( subNodes.PolygonVertexIndex.properties.a );
Y
yamahigashi 已提交
724

M
Mr.doob 已提交
725 726 727
		if ( subNodes.LayerElementNormal ) {

			var normalInfo = getNormals( subNodes.LayerElementNormal[ 0 ] );
Y
yamahigashi 已提交
728

M
Mr.doob 已提交
729
		}
Y
yamahigashi 已提交
730

M
Mr.doob 已提交
731
		if ( subNodes.LayerElementUV ) {
Y
yamahigashi 已提交
732

M
Mr.doob 已提交
733
			var uvInfo = getUVs( subNodes.LayerElementUV[ 0 ] );
Y
yamahigashi 已提交
734

M
Mr.doob 已提交
735
		}
Y
yamahigashi 已提交
736

M
Mr.doob 已提交
737
		if ( subNodes.LayerElementColor ) {
Y
yamahigashi 已提交
738

M
Mr.doob 已提交
739
			var colorInfo = getColors( subNodes.LayerElementColor[ 0 ] );
Y
yamahigashi 已提交
740

M
Mr.doob 已提交
741
		}
Y
yamahigashi 已提交
742

M
Mr.doob 已提交
743
		if ( subNodes.LayerElementMaterial ) {
Y
yamahigashi 已提交
744

M
Mr.doob 已提交
745
			var materialInfo = getMaterials( subNodes.LayerElementMaterial[ 0 ] );
Y
yamahigashi 已提交
746

M
Mr.doob 已提交
747
		}
Y
yamahigashi 已提交
748

T
Takahiro 已提交
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
		var weightTable = {};

		if ( deformer ) {

			var subDeformers = deformer.map;

			for ( var key in subDeformers ) {

				var subDeformer = subDeformers[ key ];
				var indices = subDeformer.indices;

				for ( var j = 0; j < indices.length; j ++ ) {

					var index = indices[ j ];
					var weight = subDeformer.weights[ j ];

					if ( weightTable[ index ] === undefined ) weightTable[ index ] = [];

					weightTable[ index ].push( {
						id: subDeformer.index,
						weight: weight
					} );

				}

			}

		}

M
Mr.doob 已提交
778 779
		var faceVertexBuffer = [];
		var polygonIndex = 0;
T
Takahiro 已提交
780
		var displayedWeightsWarning = false;
Y
yamahigashi 已提交
781

M
Mr.doob 已提交
782
		for ( var polygonVertexIndex = 0; polygonVertexIndex < indexBuffer.length; polygonVertexIndex ++ ) {
Y
yamahigashi 已提交
783

M
Mr.doob 已提交
784
			var vertexIndex = indexBuffer[ polygonVertexIndex ];
Y
yamahigashi 已提交
785

M
Mr.doob 已提交
786
			var endOfFace = false;
Y
yamahigashi 已提交
787

M
Mr.doob 已提交
788
			if ( vertexIndex < 0 ) {
Y
yamahigashi 已提交
789

M
Mr.doob 已提交
790 791 792
				vertexIndex = vertexIndex ^ - 1;
				indexBuffer[ polygonVertexIndex ] = vertexIndex;
				endOfFace = true;
Y
yamahigashi 已提交
793

M
Mr.doob 已提交
794
			}
Y
yamahigashi 已提交
795

M
Mr.doob 已提交
796 797 798
			var vertex = new Vertex();
			var weightIndices = [];
			var weights = [];
Y
yamahigashi 已提交
799

M
Mr.doob 已提交
800
			vertex.position.fromArray( vertexBuffer, vertexIndex * 3 );
Y
yamahigashi 已提交
801

M
Mr.doob 已提交
802
			if ( deformer ) {
Y
yamahigashi 已提交
803

T
Takahiro 已提交
804
				if ( weightTable[ vertexIndex ] !== undefined ) {
Y
yamahigashi 已提交
805

T
Takahiro 已提交
806
					var array = weightTable[ vertexIndex ];
Y
yamahigashi 已提交
807

T
Takahiro 已提交
808
					for ( var j = 0, jl = array.length; j < jl; j ++ ) {
Y
yamahigashi 已提交
809

T
Takahiro 已提交
810 811
						weights.push( array[ j ].weight );
						weightIndices.push( array[ j ].id );
Y
yamahigashi 已提交
812

813
					}
Y
yamahigashi 已提交
814

815
				}
Y
yamahigashi 已提交
816

M
Mr.doob 已提交
817
				if ( weights.length > 4 ) {
Y
yamahigashi 已提交
818

T
Takahiro 已提交
819 820
					if ( ! displayedWeightsWarning ) {

M
Mugen87 已提交
821
						console.warn( 'THREE.FBXLoader: Vertex has more than 4 skinning weights assigned to vertex. Deleting additional weights.' );
T
Takahiro 已提交
822 823 824
						displayedWeightsWarning = true;

					}
Y
yamahigashi 已提交
825

M
Mr.doob 已提交
826 827
					var WIndex = [ 0, 0, 0, 0 ];
					var Weight = [ 0, 0, 0, 0 ];
Y
yamahigashi 已提交
828

M
Mr.doob 已提交
829
					weights.forEach( function ( weight, weightIndex ) {
Y
yamahigashi 已提交
830

M
Mr.doob 已提交
831 832
						var currentWeight = weight;
						var currentIndex = weightIndices[ weightIndex ];
Y
yamahigashi 已提交
833

M
Mr.doob 已提交
834
						Weight.forEach( function ( comparedWeight, comparedWeightIndex, comparedWeightArray ) {
Y
yamahigashi 已提交
835

M
Mr.doob 已提交
836
							if ( currentWeight > comparedWeight ) {
Y
yamahigashi 已提交
837

M
Mr.doob 已提交
838 839
								comparedWeightArray[ comparedWeightIndex ] = currentWeight;
								currentWeight = comparedWeight;
Y
yamahigashi 已提交
840

M
Mr.doob 已提交
841 842 843
								var tmp = WIndex[ comparedWeightIndex ];
								WIndex[ comparedWeightIndex ] = currentIndex;
								currentIndex = tmp;
Y
yamahigashi 已提交
844

M
Mr.doob 已提交
845
							}
Y
yamahigashi 已提交
846

M
Mr.doob 已提交
847
						} );
Y
yamahigashi 已提交
848

M
Mr.doob 已提交
849
					} );
Y
yamahigashi 已提交
850

M
Mr.doob 已提交
851 852
					weightIndices = WIndex;
					weights = Weight;
Y
yamahigashi 已提交
853

M
Mr.doob 已提交
854
				}
Y
yamahigashi 已提交
855

M
Mr.doob 已提交
856
				for ( var i = weights.length; i < 4; ++ i ) {
Y
yamahigashi 已提交
857

M
Mr.doob 已提交
858 859
					weights[ i ] = 0;
					weightIndices[ i ] = 0;
Y
yamahigashi 已提交
860

M
Mr.doob 已提交
861
				}
Y
yamahigashi 已提交
862

M
Mr.doob 已提交
863 864
				vertex.skinWeights.fromArray( weights );
				vertex.skinIndices.fromArray( weightIndices );
Y
yamahigashi 已提交
865

M
Mr.doob 已提交
866
			}
Y
yamahigashi 已提交
867

M
Mr.doob 已提交
868
			if ( normalInfo ) {
Y
yamahigashi 已提交
869

M
Mr.doob 已提交
870
				vertex.normal.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, normalInfo ) );
Y
yamahigashi 已提交
871

M
Mr.doob 已提交
872
			}
Y
yamahigashi 已提交
873

M
Mr.doob 已提交
874
			if ( uvInfo ) {
Y
yamahigashi 已提交
875

M
Mr.doob 已提交
876
				vertex.uv.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, uvInfo ) );
Y
yamahigashi 已提交
877

M
Mr.doob 已提交
878
			}
Y
yamahigashi 已提交
879

M
Mr.doob 已提交
880
			if ( colorInfo ) {
Y
yamahigashi 已提交
881

M
Mr.doob 已提交
882
				vertex.color.fromArray( getData( polygonVertexIndex, polygonIndex, vertexIndex, colorInfo ) );
Y
yamahigashi 已提交
883

884
			}
Y
yamahigashi 已提交
885

M
Mr.doob 已提交
886
			faceVertexBuffer.push( vertex );
Y
yamahigashi 已提交
887

M
Mr.doob 已提交
888
			if ( endOfFace ) {
Y
yamahigashi 已提交
889

M
Mr.doob 已提交
890 891
				var face = new Face();
				face.genTrianglesFromVertices( faceVertexBuffer );
Y
yamahigashi 已提交
892

M
Mr.doob 已提交
893
				if ( materialInfo !== undefined ) {
Y
yamahigashi 已提交
894

M
Mr.doob 已提交
895 896
					var materials = getData( polygonVertexIndex, polygonIndex, vertexIndex, materialInfo );
					face.materialIndex = materials[ 0 ];
Y
yamahigashi 已提交
897

M
Mr.doob 已提交
898
				} else {
Y
yamahigashi 已提交
899

M
Mr.doob 已提交
900 901 902
					// Seems like some models don't have materialInfo(subNodes.LayerElementMaterial).
					// Set 0 in such a case.
					face.materialIndex = 0;
Y
yamahigashi 已提交
903

M
Mr.doob 已提交
904
				}
905

M
Mr.doob 已提交
906 907 908
				geometry.faces.push( face );
				faceVertexBuffer = [];
				polygonIndex ++;
909

M
Mr.doob 已提交
910
				endOfFace = false;
Y
yamahigashi 已提交
911

Y
yamahigashi 已提交
912
			}
Y
yamahigashi 已提交
913

M
Mr.doob 已提交
914
		}
Y
yamahigashi 已提交
915

M
Mr.doob 已提交
916 917 918 919
		/**
		 * @type {{vertexBuffer: number[], normalBuffer: number[], uvBuffer: number[], skinIndexBuffer: number[], skinWeightBuffer: number[], materialIndexBuffer: number[]}}
		 */
		var bufferInfo = geometry.flattenToBuffers();
Y
yamahigashi 已提交
920

M
Mr.doob 已提交
921 922 923
		var geo = new THREE.BufferGeometry();
		geo.name = geometryNode.name;
		geo.addAttribute( 'position', new THREE.Float32BufferAttribute( bufferInfo.vertexBuffer, 3 ) );
Y
yamahigashi 已提交
924

M
Mr.doob 已提交
925
		if ( bufferInfo.normalBuffer.length > 0 ) {
Y
yamahigashi 已提交
926

M
Mr.doob 已提交
927
			geo.addAttribute( 'normal', new THREE.Float32BufferAttribute( bufferInfo.normalBuffer, 3 ) );
Y
yamahigashi 已提交
928

M
Mr.doob 已提交
929 930
		}
		if ( bufferInfo.uvBuffer.length > 0 ) {
Y
yamahigashi 已提交
931

M
Mr.doob 已提交
932
			geo.addAttribute( 'uv', new THREE.Float32BufferAttribute( bufferInfo.uvBuffer, 2 ) );
Y
yamahigashi 已提交
933

M
Mr.doob 已提交
934 935
		}
		if ( subNodes.LayerElementColor ) {
Y
yamahigashi 已提交
936

M
Mr.doob 已提交
937
			geo.addAttribute( 'color', new THREE.Float32BufferAttribute( bufferInfo.colorBuffer, 3 ) );
Y
yamahigashi 已提交
938

M
Mr.doob 已提交
939
		}
Y
yamahigashi 已提交
940

M
Mr.doob 已提交
941
		if ( deformer ) {
Y
yamahigashi 已提交
942

M
Mr.doob 已提交
943
			geo.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( bufferInfo.skinIndexBuffer, 4 ) );
Y
yamahigashi 已提交
944

M
Mr.doob 已提交
945
			geo.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( bufferInfo.skinWeightBuffer, 4 ) );
Y
yamahigashi 已提交
946

M
Mr.doob 已提交
947
			geo.FBX_Deformer = deformer;
Y
yamahigashi 已提交
948

M
Mr.doob 已提交
949
		}
Y
yamahigashi 已提交
950

M
Mr.doob 已提交
951
		// Convert the material indices of each vertex into rendering groups on the geometry.
Y
yamahigashi 已提交
952

M
Mr.doob 已提交
953 954 955
		var materialIndexBuffer = bufferInfo.materialIndexBuffer;
		var prevMaterialIndex = materialIndexBuffer[ 0 ];
		var startIndex = 0;
Y
yamahigashi 已提交
956

M
Mr.doob 已提交
957
		for ( var i = 0; i < materialIndexBuffer.length; ++ i ) {
Y
yamahigashi 已提交
958

M
Mr.doob 已提交
959
			if ( materialIndexBuffer[ i ] !== prevMaterialIndex ) {
Y
yamahigashi 已提交
960

M
Mr.doob 已提交
961 962 963 964
				geo.addGroup( startIndex, i - startIndex, prevMaterialIndex );

				prevMaterialIndex = materialIndexBuffer[ i ];
				startIndex = i;
Y
yamahigashi 已提交
965

Y
yamahigashi 已提交
966
			}
Y
yamahigashi 已提交
967

M
Mr.doob 已提交
968
		}
Y
yamahigashi 已提交
969

M
Mr.doob 已提交
970
		return geo;
Y
yamahigashi 已提交
971

M
Mr.doob 已提交
972
	}
Y
yamahigashi 已提交
973

M
Mr.doob 已提交
974 975 976 977 978 979
	/**
	 * Parses normal information for geometry.
	 * @param {FBXGeometryNode} geometryNode
	 * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
	 */
	function getNormals( NormalNode ) {
Y
yamahigashi 已提交
980

M
Mr.doob 已提交
981 982 983 984 985
		var mappingType = NormalNode.properties.MappingInformationType;
		var referenceType = NormalNode.properties.ReferenceInformationType;
		var buffer = parseFloatArray( NormalNode.subNodes.Normals.properties.a );
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
986

M
Mr.doob 已提交
987
			if ( 'NormalIndex' in NormalNode.subNodes ) {
Y
yamahigashi 已提交
988

M
Mr.doob 已提交
989
				indexBuffer = parseIntArray( NormalNode.subNodes.NormalIndex.properties.a );
Y
yamahigashi 已提交
990

M
Mr.doob 已提交
991
			} else if ( 'NormalsIndex' in NormalNode.subNodes ) {
Y
yamahigashi 已提交
992

M
Mr.doob 已提交
993
				indexBuffer = parseIntArray( NormalNode.subNodes.NormalsIndex.properties.a );
Y
yamahigashi 已提交
994

995
			}
Y
yamahigashi 已提交
996

M
Mr.doob 已提交
997
		}
Y
yamahigashi 已提交
998

M
Mr.doob 已提交
999 1000 1001 1002 1003 1004 1005
		return {
			dataSize: 3,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1006

M
Mr.doob 已提交
1007
	}
Y
yamahigashi 已提交
1008

M
Mr.doob 已提交
1009 1010 1011 1012 1013 1014
	/**
	 * Parses UV information for geometry.
	 * @param {FBXGeometryNode} geometryNode
	 * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
	 */
	function getUVs( UVNode ) {
Y
yamahigashi 已提交
1015

M
Mr.doob 已提交
1016 1017 1018 1019 1020
		var mappingType = UVNode.properties.MappingInformationType;
		var referenceType = UVNode.properties.ReferenceInformationType;
		var buffer = parseFloatArray( UVNode.subNodes.UV.properties.a );
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1021

M
Mr.doob 已提交
1022
			indexBuffer = parseIntArray( UVNode.subNodes.UVIndex.properties.a );
Y
yamahigashi 已提交
1023

M
Mr.doob 已提交
1024
		}
Y
yamahigashi 已提交
1025

M
Mr.doob 已提交
1026 1027 1028 1029 1030 1031 1032
		return {
			dataSize: 2,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1033

M
Mr.doob 已提交
1034
	}
Y
yamahigashi 已提交
1035

M
Mr.doob 已提交
1036 1037 1038 1039 1040 1041
	/**
	 * Parses Vertex Color information for geometry.
	 * @param {FBXGeometryNode} geometryNode
	 * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
	 */
	function getColors( ColorNode ) {
Y
yamahigashi 已提交
1042

M
Mr.doob 已提交
1043 1044 1045 1046 1047
		var mappingType = ColorNode.properties.MappingInformationType;
		var referenceType = ColorNode.properties.ReferenceInformationType;
		var buffer = parseFloatArray( ColorNode.subNodes.Colors.properties.a );
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1048

M
Mr.doob 已提交
1049
			indexBuffer = parseFloatArray( ColorNode.subNodes.ColorIndex.properties.a );
1050

Y
yamahigashi 已提交
1051
		}
Y
yamahigashi 已提交
1052

M
Mr.doob 已提交
1053 1054 1055 1056 1057 1058 1059
		return {
			dataSize: 4,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1060

M
Mr.doob 已提交
1061
	}
Y
yamahigashi 已提交
1062

M
Mr.doob 已提交
1063 1064 1065 1066 1067 1068
	/**
	 * Parses material application information for geometry.
	 * @param {FBXGeometryNode}
	 * @returns {{dataSize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}}
	 */
	function getMaterials( MaterialNode ) {
Y
yamahigashi 已提交
1069

M
Mr.doob 已提交
1070 1071
		var mappingType = MaterialNode.properties.MappingInformationType;
		var referenceType = MaterialNode.properties.ReferenceInformationType;
Y
yamahigashi 已提交
1072

M
Mr.doob 已提交
1073
		if ( mappingType === 'NoMappingInformation' ) {
Y
yamahigashi 已提交
1074

M
Mr.doob 已提交
1075 1076 1077 1078 1079 1080 1081
			return {
				dataSize: 1,
				buffer: [ 0 ],
				indices: [ 0 ],
				mappingType: 'AllSame',
				referenceType: referenceType
			};
Y
yamahigashi 已提交
1082

M
Mr.doob 已提交
1083
		}
Y
yamahigashi 已提交
1084

M
Mr.doob 已提交
1085
		var materialIndexBuffer = parseIntArray( MaterialNode.subNodes.Materials.properties.a );
Y
yamahigashi 已提交
1086

M
Mr.doob 已提交
1087 1088 1089 1090
		// Since materials are stored as indices, there's a bit of a mismatch between FBX and what
		// we expect.  So we create an intermediate buffer that points to the index in the buffer,
		// for conforming with the other functions we've written for other data.
		var materialIndices = [];
Y
yamahigashi 已提交
1091

M
Mr.doob 已提交
1092
		for ( var materialIndexBufferIndex = 0, materialIndexBufferLength = materialIndexBuffer.length; materialIndexBufferIndex < materialIndexBufferLength; ++ materialIndexBufferIndex ) {
Y
yamahigashi 已提交
1093

M
Mr.doob 已提交
1094
			materialIndices.push( materialIndexBufferIndex );
Y
yamahigashi 已提交
1095

M
Mr.doob 已提交
1096
		}
Y
yamahigashi 已提交
1097

M
Mr.doob 已提交
1098 1099 1100 1101 1102 1103 1104
		return {
			dataSize: 1,
			buffer: materialIndexBuffer,
			indices: materialIndices,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1105

M
Mr.doob 已提交
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
	}

	/**
	 * Function uses the infoObject and given indices to return value array of object.
	 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
	 * @param {number} polygonIndex - Index of polygon in geometry.
	 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
	 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
	 * @returns {number[]}
	 */

	var dataArray = [];

	var GetData = {

		ByPolygonVertex: {

			/**
			 * Function uses the infoObject and given indices to return value array of object.
			 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
			 * @param {number} polygonIndex - Index of polygon in geometry.
			 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
			 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
			 * @returns {number[]}
			 */
			Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var from = ( polygonVertexIndex * infoObject.dataSize );
				var to = ( polygonVertexIndex * infoObject.dataSize ) + infoObject.dataSize;

				// return infoObject.buffer.slice( from, to );
				return slice( dataArray, infoObject.buffer, from, to );

			},

			/**
			 * Function uses the infoObject and given indices to return value array of object.
			 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
			 * @param {number} polygonIndex - Index of polygon in geometry.
			 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
			 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
			 * @returns {number[]}
			 */
			IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var index = infoObject.indices[ polygonVertexIndex ];
				var from = ( index * infoObject.dataSize );
				var to = ( index * infoObject.dataSize ) + infoObject.dataSize;

				// return infoObject.buffer.slice( from, to );
				return slice( dataArray, infoObject.buffer, from, to );

			}
Y
yamahigashi 已提交
1159

Y
yamahigashi 已提交
1160
		},
Y
yamahigashi 已提交
1161

M
Mr.doob 已提交
1162
		ByPolygon: {
Y
yamahigashi 已提交
1163

M
Mr.doob 已提交
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
			/**
			 * Function uses the infoObject and given indices to return value array of object.
			 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
			 * @param {number} polygonIndex - Index of polygon in geometry.
			 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
			 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
			 * @returns {number[]}
			 */
			Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var from = polygonIndex * infoObject.dataSize;
				var to = polygonIndex * infoObject.dataSize + infoObject.dataSize;

				// return infoObject.buffer.slice( from, to );
				return slice( dataArray, infoObject.buffer, from, to );

			},

			/**
			 * Function uses the infoObject and given indices to return value array of object.
			 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
			 * @param {number} polygonIndex - Index of polygon in geometry.
			 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
			 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
			 * @returns {number[]}
			 */
			IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var index = infoObject.indices[ polygonIndex ];
				var from = index * infoObject.dataSize;
				var to = index * infoObject.dataSize + infoObject.dataSize;

				// return infoObject.buffer.slice( from, to );
				return slice( dataArray, infoObject.buffer, from, to );

			}
Y
yamahigashi 已提交
1200

Y
yamahigashi 已提交
1201
		},
Y
yamahigashi 已提交
1202

M
Mr.doob 已提交
1203
		ByVertice: {
Y
yamahigashi 已提交
1204

M
Mr.doob 已提交
1205 1206 1207 1208 1209 1210 1211 1212 1213
			Direct: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {

				var from = ( vertexIndex * infoObject.dataSize );
				var to = ( vertexIndex * infoObject.dataSize ) + infoObject.dataSize;

				// return infoObject.buffer.slice( from, to );
				return slice( dataArray, infoObject.buffer, from, to );

			}
Y
yamahigashi 已提交
1214

Y
yamahigashi 已提交
1215
		},
Y
yamahigashi 已提交
1216

M
Mr.doob 已提交
1217
		AllSame: {
Y
yamahigashi 已提交
1218

M
Mr.doob 已提交
1219 1220 1221 1222 1223 1224 1225 1226 1227
			/**
			 * Function uses the infoObject and given indices to return value array of object.
			 * @param {number} polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
			 * @param {number} polygonIndex - Index of polygon in geometry.
			 * @param {number} vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
			 * @param {{datasize: number, buffer: number[], indices: number[], mappingType: string, referenceType: string}} infoObject - Object containing data and how to access data.
			 * @returns {number[]}
			 */
			IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
Y
yamahigashi 已提交
1228

M
Mr.doob 已提交
1229 1230
				var from = infoObject.indices[ 0 ] * infoObject.dataSize;
				var to = infoObject.indices[ 0 ] * infoObject.dataSize + infoObject.dataSize;
Y
yamahigashi 已提交
1231

M
Mr.doob 已提交
1232 1233
				// return infoObject.buffer.slice( from, to );
				return slice( dataArray, infoObject.buffer, from, to );
Y
yamahigashi 已提交
1234

M
Mr.doob 已提交
1235
			}
Y
yamahigashi 已提交
1236

M
Mr.doob 已提交
1237
		}
Y
yamahigashi 已提交
1238

M
Mr.doob 已提交
1239
	};
Y
yamahigashi 已提交
1240

M
Mr.doob 已提交
1241
	function getData( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
Y
yamahigashi 已提交
1242

M
Mr.doob 已提交
1243
		return GetData[ infoObject.mappingType ][ infoObject.referenceType ]( polygonVertexIndex, polygonIndex, vertexIndex, infoObject );
Y
yamahigashi 已提交
1244

M
Mr.doob 已提交
1245
	}
Y
yamahigashi 已提交
1246

M
Mr.doob 已提交
1247 1248 1249 1250 1251 1252 1253
	/**
	 * Specialty function for parsing NurbsCurve based Geometry Nodes.
	 * @param {FBXGeometryNode} geometryNode
	 * @param {{parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}} relationships
	 * @returns {THREE.BufferGeometry}
	 */
	function parseNurbsGeometry( geometryNode ) {
Y
yamahigashi 已提交
1254

M
Mr.doob 已提交
1255
		if ( THREE.NURBSCurve === undefined ) {
Y
yamahigashi 已提交
1256

M
Mugen87 已提交
1257
			console.error( 'THREE.FBXLoader: The loader relies on THREE.NURBSCurve for any nurbs present in the model. Nurbs will show up as empty geometry.' );
M
Mr.doob 已提交
1258
			return new THREE.BufferGeometry();
Y
yamahigashi 已提交
1259

M
Mr.doob 已提交
1260
		}
Y
yamahigashi 已提交
1261

M
Mr.doob 已提交
1262
		var order = parseInt( geometryNode.properties.Order );
Y
yamahigashi 已提交
1263

M
Mr.doob 已提交
1264
		if ( isNaN( order ) ) {
Y
yamahigashi 已提交
1265

M
Mugen87 已提交
1266
			console.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geometryNode.properties.Order, geometryNode.id );
M
Mr.doob 已提交
1267
			return new THREE.BufferGeometry();
Y
yamahigashi 已提交
1268

M
Mr.doob 已提交
1269
		}
Y
yamahigashi 已提交
1270

M
Mr.doob 已提交
1271
		var degree = order - 1;
Y
yamahigashi 已提交
1272

M
Mr.doob 已提交
1273 1274 1275
		var knots = parseFloatArray( geometryNode.subNodes.KnotVector.properties.a );
		var controlPoints = [];
		var pointsValues = parseFloatArray( geometryNode.subNodes.Points.properties.a );
Y
yamahigashi 已提交
1276

M
Mr.doob 已提交
1277
		for ( var i = 0, l = pointsValues.length; i < l; i += 4 ) {
Y
yamahigashi 已提交
1278

M
Mr.doob 已提交
1279
			controlPoints.push( new THREE.Vector4().fromArray( pointsValues, i ) );
Y
yamahigashi 已提交
1280

M
Mr.doob 已提交
1281
		}
Y
yamahigashi 已提交
1282

M
Mr.doob 已提交
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
		var startKnot, endKnot;

		if ( geometryNode.properties.Form === 'Closed' ) {

			controlPoints.push( controlPoints[ 0 ] );

		} else if ( geometryNode.properties.Form === 'Periodic' ) {

			startKnot = degree;
			endKnot = knots.length - 1 - startKnot;

			for ( var i = 0; i < degree; ++ i ) {

				controlPoints.push( controlPoints[ i ] );

			}

		}

		var curve = new THREE.NURBSCurve( degree, knots, controlPoints, startKnot, endKnot );
		var vertices = curve.getPoints( controlPoints.length * 7 );

		var positions = new Float32Array( vertices.length * 3 );

		for ( var i = 0, l = vertices.length; i < l; ++ i ) {

			vertices[ i ].toArray( positions, i * 3 );

		}

		var geometry = new THREE.BufferGeometry();
		geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

		return geometry;

	}

	/**
	 * Finally generates Scene graph and Scene graph Objects.
	 * @param {{Objects: {subNodes: {Model: Object.<number, FBXModelNode>}}}} FBXTree
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @param {Map<number, {map: Map<number, {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}>, array: {FBX_ID: number, indices: number[], weights: number[], transform: number[], transformLink: number[], linkMode: string}[], skeleton: THREE.Skeleton|null}>} deformers
	 * @param {Map<number, THREE.BufferGeometry>} geometryMap
	 * @param {Map<number, THREE.Material>} materialMap
	 * @returns {THREE.Group}
	 */
	function parseScene( FBXTree, connections, deformers, geometryMap, materialMap ) {

		var sceneGraph = new THREE.Group();

		var ModelNode = FBXTree.Objects.subNodes.Model;

		/**
		 * @type {Array.<THREE.Object3D>}
		 */
		var modelArray = [];

		/**
		 * @type {Map.<number, THREE.Object3D>}
		 */
		var modelMap = new Map();

		for ( var nodeID in ModelNode ) {

			var id = parseInt( nodeID );
			var node = ModelNode[ nodeID ];
			var conns = connections.get( id );
			var model = null;

			for ( var i = 0; i < conns.parents.length; ++ i ) {

				for ( var FBX_ID in deformers ) {

					var deformer = deformers[ FBX_ID ];
					var subDeformers = deformer.map;
					var subDeformer = subDeformers[ conns.parents[ i ].ID ];

					if ( subDeformer ) {

						var model2 = model;
						model = new THREE.Bone();
						deformer.bones[ subDeformer.index ] = model;

						// seems like we need this not to make non-connected bone, maybe?
						// TODO: confirm
						if ( model2 !== null ) model.add( model2 );

					}
Y
yamahigashi 已提交
1371

Y
yamahigashi 已提交
1372
				}
Y
yamahigashi 已提交
1373

Y
yamahigashi 已提交
1374
			}
Y
yamahigashi 已提交
1375

M
Mr.doob 已提交
1376
			if ( ! model ) {
Y
yamahigashi 已提交
1377

M
Mr.doob 已提交
1378
				switch ( node.attrType ) {
Y
yamahigashi 已提交
1379

M
Mugen87 已提交
1380
					case 'Mesh':
M
Mr.doob 已提交
1381 1382 1383 1384
						/**
						 * @type {?THREE.BufferGeometry}
						 */
						var geometry = null;
Y
yamahigashi 已提交
1385

M
Mr.doob 已提交
1386 1387 1388 1389
						/**
						 * @type {THREE.MultiMaterial|THREE.Material}
						 */
						var material = null;
Y
yamahigashi 已提交
1390

M
Mr.doob 已提交
1391 1392 1393 1394
						/**
						 * @type {Array.<THREE.Material>}
						 */
						var materials = [];
Y
yamahigashi 已提交
1395

M
Mr.doob 已提交
1396
						for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {
Y
yamahigashi 已提交
1397

M
Mr.doob 已提交
1398
							var child = conns.children[ childrenIndex ];
Y
yamahigashi 已提交
1399

M
Mr.doob 已提交
1400
							if ( geometryMap.has( child.ID ) ) {
Y
yamahigashi 已提交
1401

M
Mr.doob 已提交
1402
								geometry = geometryMap.get( child.ID );
Y
yamahigashi 已提交
1403

M
Mr.doob 已提交
1404
							}
Y
yamahigashi 已提交
1405

M
Mr.doob 已提交
1406
							if ( materialMap.has( child.ID ) ) {
Y
yamahigashi 已提交
1407

M
Mr.doob 已提交
1408
								materials.push( materialMap.get( child.ID ) );
Y
yamahigashi 已提交
1409

M
Mr.doob 已提交
1410
							}
Y
yamahigashi 已提交
1411

M
Mr.doob 已提交
1412 1413 1414
						}
						if ( materials.length > 1 ) {

1415
							material = materials;
M
Mr.doob 已提交
1416 1417 1418 1419

						} else if ( materials.length > 0 ) {

							material = materials[ 0 ];
Y
yamahigashi 已提交
1420

Y
yamahigashi 已提交
1421
						} else {
Y
yamahigashi 已提交
1422

1423
							material = new THREE.MeshStandardMaterial( { color: 0x3300ff } );
M
Mr.doob 已提交
1424
							materials.push( material );
Y
yamahigashi 已提交
1425

Y
yamahigashi 已提交
1426
						}
M
Mr.doob 已提交
1427
						if ( 'color' in geometry.attributes ) {
Y
yamahigashi 已提交
1428

M
Mugen87 已提交
1429
							for ( var materialIndex = 0, numMaterials = materials.length; materialIndex < numMaterials; ++ materialIndex ) {
Y
yamahigashi 已提交
1430

M
Mr.doob 已提交
1431
								materials[ materialIndex ].vertexColors = THREE.VertexColors;
Y
yamahigashi 已提交
1432

M
Mr.doob 已提交
1433
							}
Y
yamahigashi 已提交
1434

M
Mr.doob 已提交
1435 1436
						}
						if ( geometry.FBX_Deformer ) {
Y
yamahigashi 已提交
1437

M
Mr.doob 已提交
1438
							for ( var materialsIndex = 0, materialsLength = materials.length; materialsIndex < materialsLength; ++ materialsIndex ) {
Y
yamahigashi 已提交
1439

M
Mr.doob 已提交
1440
								materials[ materialsIndex ].skinning = true;
Y
yamahigashi 已提交
1441

M
Mr.doob 已提交
1442 1443
							}
							model = new THREE.SkinnedMesh( geometry, material );
1444

M
Mr.doob 已提交
1445
						} else {
1446

M
Mr.doob 已提交
1447
							model = new THREE.Mesh( geometry, material );
Y
yamahigashi 已提交
1448

M
Mr.doob 已提交
1449 1450 1451
						}
						break;

L
Lewy Blue 已提交
1452
					case 'Camera':
L
Lewy Blue 已提交
1453 1454
						/* ***********
						* Supported light types:
L
Lewy Blue 已提交
1455 1456
						* PerspectiveCamera
						* OrthographicCamera
L
Lewy Blue 已提交
1457
						*
L
Lewy Blue 已提交
1458
						* TODO: Support targets via camera.lookAt
L
Lewy Blue 已提交
1459
						************** */
L
Lewy Blue 已提交
1460
						var cameraAttribute;
L
Lewy Blue 已提交
1461 1462 1463 1464 1465 1466 1467 1468 1469

						for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {

							var childID = conns.children[ childrenIndex ].ID;

							var attr = FBXTree.Objects.subNodes.NodeAttribute[ childID ];

							if ( attr !== undefined && attr.properties !== undefined ) {

L
Lewy Blue 已提交
1470
								cameraAttribute = attr.properties;
L
Lewy Blue 已提交
1471 1472 1473 1474 1475

							}

						}

L
Lewy Blue 已提交
1476
						if ( cameraAttribute === undefined ) {
L
Lewy Blue 已提交
1477 1478 1479 1480 1481

							model = new THREE.Object3D();

						} else {

L
Lewy Blue 已提交
1482 1483
							var type = 0;
							if ( cameraAttribute.CameraProjectionType !== undefined && ( cameraAttribute.CameraProjectionType.value === '1' || cameraAttribute.CameraProjectionType.value === 1 ) ) {
L
Lewy Blue 已提交
1484

L
Lewy Blue 已提交
1485
								type = 1;
L
Lewy Blue 已提交
1486 1487 1488

							}

L
Lewy Blue 已提交
1489 1490
							var nearClippingPlane = 1;
							if ( cameraAttribute.NearPlane !== undefined ) {
L
Lewy Blue 已提交
1491

L
Lewy Blue 已提交
1492
								nearClippingPlane = cameraAttribute.NearPlane.value / 1000;
L
Lewy Blue 已提交
1493

L
Lewy Blue 已提交
1494
							}
L
Lewy Blue 已提交
1495

L
Lewy Blue 已提交
1496 1497
							var farClippingPlane = 1000;
							if ( cameraAttribute.FarPlane !== undefined ) {
L
Lewy Blue 已提交
1498

L
Lewy Blue 已提交
1499
								farClippingPlane = cameraAttribute.FarPlane.value / 1000;
L
Lewy Blue 已提交
1500 1501 1502 1503

							}


L
Lewy Blue 已提交
1504 1505
							var width = window.innerWidth;
							var height = window.innerHeight;
L
Lewy Blue 已提交
1506

L
Lewy Blue 已提交
1507
							if ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) {
L
Lewy Blue 已提交
1508

L
Lewy Blue 已提交
1509 1510
								width = parseFloat( cameraAttribute.AspectWidth.value );
								height = parseFloat( cameraAttribute.AspectHeight.value );
L
Lewy Blue 已提交
1511

L
Lewy Blue 已提交
1512
							}
L
Lewy Blue 已提交
1513

L
Lewy Blue 已提交
1514
							var aspect = width / height;
L
Lewy Blue 已提交
1515

L
Lewy Blue 已提交
1516 1517
							var fov = 45;
							if ( cameraAttribute.FieldOfView !== undefined ) {
L
Lewy Blue 已提交
1518

L
Lewy Blue 已提交
1519
								fov = parseFloat( cameraAttribute.FieldOfView.value );
L
Lewy Blue 已提交
1520 1521 1522 1523 1524

							}

							switch ( type ) {

L
Lewy Blue 已提交
1525
								case '0': // Perspective
L
Lewy Blue 已提交
1526
								case 0:
L
Lewy Blue 已提交
1527
									model = new THREE.PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane );
L
Lewy Blue 已提交
1528 1529
									break;

L
Lewy Blue 已提交
1530
								case '1': // Orthographic
L
Lewy Blue 已提交
1531
								case 1:
L
Lewy Blue 已提交
1532
									model = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane );
L
Lewy Blue 已提交
1533 1534 1535
									break;

								default:
L
Lewy Blue 已提交
1536 1537
									console.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' );
									model = new THREE.Object3D();
L
Lewy Blue 已提交
1538 1539 1540 1541 1542 1543 1544 1545
									break;

							}

						}

						break;

M
Mugen87 已提交
1546
					case 'NurbsCurve':
M
Mr.doob 已提交
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568
						var geometry = null;

						for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {

							var child = conns.children[ childrenIndex ];

							if ( geometryMap.has( child.ID ) ) {

								geometry = geometryMap.get( child.ID );

							}

						}

						// FBX does not list materials for Nurbs lines, so we'll just put our own in here.
						material = new THREE.LineBasicMaterial( { color: 0x3300ff, linewidth: 5 } );
						model = new THREE.Line( geometry, material );
						break;

					default:
						model = new THREE.Object3D();
						break;
Y
yamahigashi 已提交
1569

Y
yamahigashi 已提交
1570
				}
Y
yamahigashi 已提交
1571

Y
yamahigashi 已提交
1572
			}
Y
yamahigashi 已提交
1573

M
Mr.doob 已提交
1574 1575
			model.name = node.attrName.replace( /:/, '' ).replace( /_/, '' ).replace( /-/, '' );
			model.FBX_ID = id;
Y
yamahigashi 已提交
1576

M
Mr.doob 已提交
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
			modelArray.push( model );
			modelMap.set( id, model );

		}

		for ( var modelArrayIndex = 0, modelArrayLength = modelArray.length; modelArrayIndex < modelArrayLength; ++ modelArrayIndex ) {

			var model = modelArray[ modelArrayIndex ];

			var node = ModelNode[ model.FBX_ID ];

			if ( 'Lcl_Translation' in node.properties ) {

				model.position.fromArray( parseFloatArray( node.properties.Lcl_Translation.value ) );
Y
yamahigashi 已提交
1591

Y
yamahigashi 已提交
1592
			}
Y
yamahigashi 已提交
1593

M
Mr.doob 已提交
1594
			if ( 'Lcl_Rotation' in node.properties ) {
Y
yamahigashi 已提交
1595

M
Mr.doob 已提交
1596 1597 1598
				var rotation = parseFloatArray( node.properties.Lcl_Rotation.value ).map( degreeToRadian );
				rotation.push( 'ZYX' );
				model.rotation.fromArray( rotation );
Y
yamahigashi 已提交
1599

M
Mr.doob 已提交
1600
			}
Y
yamahigashi 已提交
1601

M
Mr.doob 已提交
1602
			if ( 'Lcl_Scaling' in node.properties ) {
Y
yamahigashi 已提交
1603

M
Mr.doob 已提交
1604
				model.scale.fromArray( parseFloatArray( node.properties.Lcl_Scaling.value ) );
Y
yamahigashi 已提交
1605

M
Mr.doob 已提交
1606
			}
Y
yamahigashi 已提交
1607

M
Mr.doob 已提交
1608
			if ( 'PreRotation' in node.properties ) {
Y
yamahigashi 已提交
1609

M
Mr.doob 已提交
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
				var preRotations = new THREE.Euler().setFromVector3( parseVector3( node.properties.PreRotation ).multiplyScalar( DEG2RAD ), 'ZYX' );
				preRotations = new THREE.Quaternion().setFromEuler( preRotations );
				var currentRotation = new THREE.Quaternion().setFromEuler( model.rotation );
				preRotations.multiply( currentRotation );
				model.rotation.setFromQuaternion( preRotations, 'ZYX' );

			}

			var conns = connections.get( model.FBX_ID );
			for ( var parentIndex = 0; parentIndex < conns.parents.length; parentIndex ++ ) {

				var pIndex = findIndex( modelArray, function ( mod ) {

					return mod.FBX_ID === conns.parents[ parentIndex ].ID;

				} );
				if ( pIndex > - 1 ) {

					modelArray[ pIndex ].add( model );
					break;
Y
yamahigashi 已提交
1630

Y
yamahigashi 已提交
1631
				}
Y
yamahigashi 已提交
1632

Y
yamahigashi 已提交
1633
			}
M
Mr.doob 已提交
1634
			if ( model.parent === null ) {
Y
yamahigashi 已提交
1635

M
Mr.doob 已提交
1636
				sceneGraph.add( model );
Y
yamahigashi 已提交
1637

M
Mr.doob 已提交
1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
			}

		}


		// Now with the bones created, we can update the skeletons and bind them to the skinned meshes.
		sceneGraph.updateMatrixWorld( true );

		// Put skeleton into bind pose.
		var BindPoseNode = FBXTree.Objects.subNodes.Pose;
		for ( var nodeID in BindPoseNode ) {

			if ( BindPoseNode[ nodeID ].attrType === 'BindPose' ) {

				BindPoseNode = BindPoseNode[ nodeID ];
				break;
Y
yamahigashi 已提交
1654

Y
yamahigashi 已提交
1655
			}
Y
yamahigashi 已提交
1656

M
Mr.doob 已提交
1657 1658
		}
		if ( BindPoseNode ) {
Y
yamahigashi 已提交
1659

M
Mr.doob 已提交
1660 1661
			var PoseNode = BindPoseNode.subNodes.PoseNode;
			var worldMatrices = new Map();
Y
yamahigashi 已提交
1662

M
Mr.doob 已提交
1663
			for ( var PoseNodeIndex = 0, PoseNodeLength = PoseNode.length; PoseNodeIndex < PoseNodeLength; ++ PoseNodeIndex ) {
Y
yamahigashi 已提交
1664

M
Mr.doob 已提交
1665
				var node = PoseNode[ PoseNodeIndex ];
Y
yamahigashi 已提交
1666

M
Mr.doob 已提交
1667
				var rawMatWrd = parseMatrixArray( node.subNodes.Matrix.properties.a );
Y
yamahigashi 已提交
1668

M
Mr.doob 已提交
1669
				worldMatrices.set( parseInt( node.id ), rawMatWrd );
Y
yamahigashi 已提交
1670

M
Mr.doob 已提交
1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
			}

		}

		for ( var FBX_ID in deformers ) {

			var deformer = deformers[ FBX_ID ];
			var subDeformers = deformer.map;

			for ( var key in subDeformers ) {

				var subDeformer = subDeformers[ key ];
				var subDeformerIndex = subDeformer.index;

				/**
				 * @type {THREE.Bone}
				 */
				var bone = deformer.bones[ subDeformerIndex ];
				if ( ! worldMatrices.has( bone.FBX_ID ) ) {

					break;
Y
yamahigashi 已提交
1692

Y
yamahigashi 已提交
1693
				}
M
Mr.doob 已提交
1694 1695
				var mat = worldMatrices.get( bone.FBX_ID );
				bone.matrixWorld.copy( mat );
Y
yamahigashi 已提交
1696

Y
yamahigashi 已提交
1697
			}
Y
yamahigashi 已提交
1698

M
Mr.doob 已提交
1699 1700
			// Now that skeleton is in bind pose, bind to model.
			deformer.skeleton = new THREE.Skeleton( deformer.bones );
Y
yamahigashi 已提交
1701

M
Mr.doob 已提交
1702 1703
			var conns = connections.get( deformer.FBX_ID );
			var parents = conns.parents;
Y
yamahigashi 已提交
1704

M
Mr.doob 已提交
1705
			for ( var parentsIndex = 0, parentsLength = parents.length; parentsIndex < parentsLength; ++ parentsIndex ) {
Y
yamahigashi 已提交
1706

M
Mr.doob 已提交
1707
				var parent = parents[ parentsIndex ];
Y
yamahigashi 已提交
1708

M
Mr.doob 已提交
1709
				if ( geometryMap.has( parent.ID ) ) {
Y
yamahigashi 已提交
1710

M
Mr.doob 已提交
1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725
					var geoID = parent.ID;
					var geoConns = connections.get( geoID );

					for ( var i = 0; i < geoConns.parents.length; ++ i ) {

						if ( modelMap.has( geoConns.parents[ i ].ID ) ) {

							var model = modelMap.get( geoConns.parents[ i ].ID );
							//ASSERT model typeof SkinnedMesh
							model.bind( deformer.skeleton, model.matrixWorld );
							break;

						}

					}
Y
yamahigashi 已提交
1726

Y
yamahigashi 已提交
1727
				}
Y
yamahigashi 已提交
1728

Y
yamahigashi 已提交
1729
			}
Y
yamahigashi 已提交
1730

M
Mr.doob 已提交
1731
		}
Y
yamahigashi 已提交
1732

M
Mr.doob 已提交
1733 1734 1735
		//Skeleton is now bound, return objects to starting
		//world positions.
		sceneGraph.updateMatrixWorld( true );
Y
yamahigashi 已提交
1736

M
Mr.doob 已提交
1737 1738 1739 1740 1741 1742
		// Silly hack with the animation parsing.  We're gonna pretend the scene graph has a skeleton
		// to attach animations to, since FBXs treat animations as animations for the entire scene,
		// not just for individual objects.
		sceneGraph.skeleton = {
			bones: modelArray
		};
Y
yamahigashi 已提交
1743

M
Mr.doob 已提交
1744
		var animations = parseAnimations( FBXTree, connections, sceneGraph );
Y
yamahigashi 已提交
1745

M
Mr.doob 已提交
1746
		addAnimations( sceneGraph, animations );
Y
yamahigashi 已提交
1747

M
Mr.doob 已提交
1748
		return sceneGraph;
Y
yamahigashi 已提交
1749

M
Mr.doob 已提交
1750
	}
Y
yamahigashi 已提交
1751

M
Mr.doob 已提交
1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161
	/**
	 * Parses animation information from FBXTree and generates an AnimationInfoObject.
	 * @param {{Objects: {subNodes: {AnimationCurveNode: any, AnimationCurve: any, AnimationLayer: any, AnimationStack: any}}}} FBXTree
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 */
	function parseAnimations( FBXTree, connections, sceneGraph ) {

		var rawNodes = FBXTree.Objects.subNodes.AnimationCurveNode;
		var rawCurves = FBXTree.Objects.subNodes.AnimationCurve;
		var rawLayers = FBXTree.Objects.subNodes.AnimationLayer;
		var rawStacks = FBXTree.Objects.subNodes.AnimationStack;

		/**
		 * @type {{
				 curves: Map<number, {
				 T: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					};
				},
				 R: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					};
				},
				 S: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					};
				}
			 }>,
			 layers: Map<number, {
				T: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					},
				},
				R: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					},
				},
				S: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					},
				}
				}[]>,
			 stacks: Map<number, {
				 name: string,
				 layers: {
					T: {
						id: number;
						attr: string;
						internalID: number;
						attrX: boolean;
						attrY: boolean;
						attrZ: boolean;
						containerBoneID: number;
						containerID: number;
						curves: {
							x: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
							y: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
							z: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
						};
					};
					R: {
						id: number;
						attr: string;
						internalID: number;
						attrX: boolean;
						attrY: boolean;
						attrZ: boolean;
						containerBoneID: number;
						containerID: number;
						curves: {
							x: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
							y: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
							z: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
						};
					};
					S: {
						id: number;
						attr: string;
						internalID: number;
						attrX: boolean;
						attrY: boolean;
						attrZ: boolean;
						containerBoneID: number;
						containerID: number;
						curves: {
							x: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
							y: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
							z: {
								version: any;
								id: number;
								internalID: number;
								times: number[];
								values: number[];
								attrFlag: number[];
								attrData: number[];
							};
						};
					};
				}[][],
			 length: number,
			 frames: number }>,
			 length: number,
			 fps: number,
			 frames: number
		 }}
		 */
		var returnObject = {
			curves: new Map(),
			layers: {},
			stacks: {},
			length: 0,
			fps: 30,
			frames: 0
		};

		/**
		 * @type {Array.<{
				id: number;
				attr: string;
				internalID: number;
				attrX: boolean;
				attrY: boolean;
				attrZ: boolean;
				containerBoneID: number;
				containerID: number;
			}>}
		 */
		var animationCurveNodes = [];
		for ( var nodeID in rawNodes ) {

			if ( nodeID.match( /\d+/ ) ) {

				var animationNode = parseAnimationNode( FBXTree, rawNodes[ nodeID ], connections, sceneGraph );
				animationCurveNodes.push( animationNode );

			}
Y
yamahigashi 已提交
2162

M
Mr.doob 已提交
2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
		}

		/**
		 * @type {Map.<number, {
				id: number,
				attr: string,
				internalID: number,
				attrX: boolean,
				attrY: boolean,
				attrZ: boolean,
				containerBoneID: number,
				containerID: number,
				curves: {
					x: {
						version: any,
						id: number,
						internalID: number,
						times: number[],
						values: number[],
						attrFlag: number[],
						attrData: number[],
					},
					y: {
						version: any,
						id: number,
						internalID: number,
						times: number[],
						values: number[],
						attrFlag: number[],
						attrData: number[],
					},
					z: {
						version: any,
						id: number,
						internalID: number,
						times: number[],
						values: number[],
						attrFlag: number[],
						attrData: number[],
					}
Y
yamahigashi 已提交
2203
				}
M
Mr.doob 已提交
2204 2205 2206 2207
			}>}
		 */
		var tmpMap = new Map();
		for ( var animationCurveNodeIndex = 0; animationCurveNodeIndex < animationCurveNodes.length; ++ animationCurveNodeIndex ) {
Y
yamahigashi 已提交
2208

M
Mr.doob 已提交
2209
			if ( animationCurveNodes[ animationCurveNodeIndex ] === null ) {
Y
yamahigashi 已提交
2210

M
Mr.doob 已提交
2211
				continue;
Y
yamahigashi 已提交
2212

M
Mr.doob 已提交
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
			}
			tmpMap.set( animationCurveNodes[ animationCurveNodeIndex ].id, animationCurveNodes[ animationCurveNodeIndex ] );

		}


		/**
		 * @type {{
				version: any,
				id: number,
				internalID: number,
				times: number[],
				values: number[],
				attrFlag: number[],
				attrData: number[],
			}[]}
		 */
		var animationCurves = [];
		for ( nodeID in rawCurves ) {

			if ( nodeID.match( /\d+/ ) ) {

				var animationCurve = parseAnimationCurve( rawCurves[ nodeID ] );

				// seems like this check would be necessary?
				if ( ! connections.has( animationCurve.id ) ) continue;

				animationCurves.push( animationCurve );

				var firstParentConn = connections.get( animationCurve.id ).parents[ 0 ];
				var firstParentID = firstParentConn.ID;
				var firstParentRelationship = firstParentConn.relationship;
				var axis = '';

				if ( firstParentRelationship.match( /X/ ) ) {

					axis = 'x';

				} else if ( firstParentRelationship.match( /Y/ ) ) {

					axis = 'y';

				} else if ( firstParentRelationship.match( /Z/ ) ) {

					axis = 'z';
Y
yamahigashi 已提交
2258

Y
yamahigashi 已提交
2259
				} else {
Y
yamahigashi 已提交
2260

M
Mr.doob 已提交
2261
					continue;
Y
yamahigashi 已提交
2262

Y
yamahigashi 已提交
2263
				}
Y
yamahigashi 已提交
2264

M
Mr.doob 已提交
2265 2266
				tmpMap.get( firstParentID ).curves[ axis ] = animationCurve;

Y
yamahigashi 已提交
2267
			}
Y
yamahigashi 已提交
2268

M
Mr.doob 已提交
2269
		}
Y
yamahigashi 已提交
2270

M
Mr.doob 已提交
2271
		tmpMap.forEach( function ( curveNode ) {
Y
yamahigashi 已提交
2272

M
Mr.doob 已提交
2273 2274
			var id = curveNode.containerBoneID;
			if ( ! returnObject.curves.has( id ) ) {
Y
yamahigashi 已提交
2275

M
Mr.doob 已提交
2276
				returnObject.curves.set( id, { T: null, R: null, S: null } );
Y
yamahigashi 已提交
2277

M
Mr.doob 已提交
2278 2279 2280
			}
			returnObject.curves.get( id )[ curveNode.attr ] = curveNode;
			if ( curveNode.attr === 'R' ) {
Y
yamahigashi 已提交
2281

M
Mr.doob 已提交
2282
				var curves = curveNode.curves;
2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317

				// Seems like some FBX files have AnimationCurveNode
				// which doesn't have any connected AnimationCurve.
				// Setting animation parameter for them here.

				if ( curves.x === null ) {

					curves.x = {
						version: null,
						times: [ 0.0 ],
						values: [ 0.0 ]
					};

				}

				if ( curves.y === null ) {

					curves.y = {
						version: null,
						times: [ 0.0 ],
						values: [ 0.0 ]
					};

				}

				if ( curves.z === null ) {

					curves.z = {
						version: null,
						times: [ 0.0 ],
						values: [ 0.0 ]
					};

				}

M
Mr.doob 已提交
2318 2319 2320
				curves.x.values = curves.x.values.map( degreeToRadian );
				curves.y.values = curves.y.values.map( degreeToRadian );
				curves.z.values = curves.z.values.map( degreeToRadian );
Y
yamahigashi 已提交
2321

M
Mr.doob 已提交
2322
				if ( curveNode.preRotations !== null ) {
Y
yamahigashi 已提交
2323

M
Mr.doob 已提交
2324 2325 2326 2327 2328
					var preRotations = new THREE.Euler().setFromVector3( curveNode.preRotations, 'ZYX' );
					preRotations = new THREE.Quaternion().setFromEuler( preRotations );
					var frameRotation = new THREE.Euler();
					var frameRotationQuaternion = new THREE.Quaternion();
					for ( var frame = 0; frame < curves.x.times.length; ++ frame ) {
Y
yamahigashi 已提交
2329

M
Mr.doob 已提交
2330 2331 2332 2333 2334 2335
						frameRotation.set( curves.x.values[ frame ], curves.y.values[ frame ], curves.z.values[ frame ], 'ZYX' );
						frameRotationQuaternion.setFromEuler( frameRotation ).premultiply( preRotations );
						frameRotation.setFromQuaternion( frameRotationQuaternion, 'ZYX' );
						curves.x.values[ frame ] = frameRotation.x;
						curves.y.values[ frame ] = frameRotation.y;
						curves.z.values[ frame ] = frameRotation.z;
Y
yamahigashi 已提交
2336

M
Mr.doob 已提交
2337 2338 2339
					}

				}
Y
yamahigashi 已提交
2340

Y
yamahigashi 已提交
2341
			}
Y
yamahigashi 已提交
2342

M
Mr.doob 已提交
2343
		} );
Y
yamahigashi 已提交
2344

M
Mr.doob 已提交
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
		for ( var nodeID in rawLayers ) {

			/**
			 * @type {{
				T: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					},
				},
				R: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					},
				},
				S: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					},
				}
				}[]}
			 */
			var layer = [];
			var children = connections.get( parseInt( nodeID ) ).children;
Y
yamahigashi 已提交
2470

M
Mr.doob 已提交
2471
			for ( var childIndex = 0; childIndex < children.length; childIndex ++ ) {
Y
yamahigashi 已提交
2472

M
Mr.doob 已提交
2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490
				// Skip lockInfluenceWeights
				if ( tmpMap.has( children[ childIndex ].ID ) ) {

					var curveNode = tmpMap.get( children[ childIndex ].ID );
					var boneID = curveNode.containerBoneID;
					if ( layer[ boneID ] === undefined ) {

						layer[ boneID ] = {
							T: null,
							R: null,
							S: null
						};

					}

					layer[ boneID ][ curveNode.attr ] = curveNode;

				}
Y
yamahigashi 已提交
2491

Y
yamahigashi 已提交
2492
			}
Y
yamahigashi 已提交
2493

M
Mr.doob 已提交
2494
			returnObject.layers[ nodeID ] = layer;
Y
yamahigashi 已提交
2495

M
Mr.doob 已提交
2496
		}
Y
yamahigashi 已提交
2497

M
Mr.doob 已提交
2498
		for ( var nodeID in rawStacks ) {
Y
yamahigashi 已提交
2499

M
Mr.doob 已提交
2500 2501 2502
			var layers = [];
			var children = connections.get( parseInt( nodeID ) ).children;
			var timestamps = { max: 0, min: Number.MAX_VALUE };
Y
yamahigashi 已提交
2503

M
Mr.doob 已提交
2504
			for ( var childIndex = 0; childIndex < children.length; ++ childIndex ) {
Y
yamahigashi 已提交
2505

M
Mr.doob 已提交
2506
				var currentLayer = returnObject.layers[ children[ childIndex ].ID ];
Y
yamahigashi 已提交
2507

M
Mr.doob 已提交
2508
				if ( currentLayer !== undefined ) {
Y
yamahigashi 已提交
2509

M
Mr.doob 已提交
2510
					layers.push( currentLayer );
Y
yamahigashi 已提交
2511

M
Mr.doob 已提交
2512
					for ( var currentLayerIndex = 0, currentLayerLength = currentLayer.length; currentLayerIndex < currentLayerLength; ++ currentLayerIndex ) {
Y
yamahigashi 已提交
2513

M
Mr.doob 已提交
2514
						var layer = currentLayer[ currentLayerIndex ];
Y
yamahigashi 已提交
2515

M
Mr.doob 已提交
2516
						if ( layer ) {
Y
yamahigashi 已提交
2517

M
Mr.doob 已提交
2518 2519 2520 2521 2522 2523 2524
							getCurveNodeMaxMinTimeStamps( layer, timestamps );

						}

					}

				}
Y
yamahigashi 已提交
2525

M
Mr.doob 已提交
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
			}

			// Do we have an animation clip with actual length?
			if ( timestamps.max > timestamps.min ) {

				returnObject.stacks[ nodeID ] = {
					name: rawStacks[ nodeID ].attrName,
					layers: layers,
					length: timestamps.max - timestamps.min,
					frames: ( timestamps.max - timestamps.min ) * 30
				};
Y
yamahigashi 已提交
2537

M
Mr.doob 已提交
2538
			}
Y
yamahigashi 已提交
2539

M
Mr.doob 已提交
2540
		}
Y
yamahigashi 已提交
2541

M
Mr.doob 已提交
2542
		return returnObject;
Y
yamahigashi 已提交
2543

Y
yamahigashi 已提交
2544
	}
Y
yamahigashi 已提交
2545

M
Mr.doob 已提交
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620
	/**
	 * @param {Object} FBXTree
	 * @param {{id: number, attrName: string, properties: Object<string, any>}} animationCurveNode
	 * @param {Map<number, {parents: {ID: number, relationship: string}[], children: {ID: number, relationship: string}[]}>} connections
	 * @param {{skeleton: {bones: {FBX_ID: number}[]}}} sceneGraph
	 */
	function parseAnimationNode( FBXTree, animationCurveNode, connections, sceneGraph ) {

		var rawModels = FBXTree.Objects.subNodes.Model;

		var returnObject = {
			/**
			 * @type {number}
			 */
			id: animationCurveNode.id,

			/**
			 * @type {string}
			 */
			attr: animationCurveNode.attrName,

			/**
			 * @type {number}
			 */
			internalID: animationCurveNode.id,

			/**
			 * @type {boolean}
			 */
			attrX: false,

			/**
			 * @type {boolean}
			 */
			attrY: false,

			/**
			 * @type {boolean}
			 */
			attrZ: false,

			/**
			 * @type {number}
			 */
			containerBoneID: - 1,

			/**
			 * @type {number}
			 */
			containerID: - 1,

			curves: {
				x: null,
				y: null,
				z: null
			},

			/**
			 * @type {number[]}
			 */
			preRotations: null
		};

		if ( returnObject.attr.match( /S|R|T/ ) ) {

			for ( var attributeKey in animationCurveNode.properties ) {

				if ( attributeKey.match( /X/ ) ) {

					returnObject.attrX = true;

				}
				if ( attributeKey.match( /Y/ ) ) {

					returnObject.attrY = true;
Y
yamahigashi 已提交
2621

M
Mr.doob 已提交
2622 2623
				}
				if ( attributeKey.match( /Z/ ) ) {
Y
yamahigashi 已提交
2624

M
Mr.doob 已提交
2625
					returnObject.attrZ = true;
Y
yamahigashi 已提交
2626

M
Mr.doob 已提交
2627
				}
Y
yamahigashi 已提交
2628

M
Mr.doob 已提交
2629
			}
Y
yamahigashi 已提交
2630

M
Mr.doob 已提交
2631
		} else {
Y
yamahigashi 已提交
2632

M
Mr.doob 已提交
2633
			return null;
Y
yamahigashi 已提交
2634

M
Mr.doob 已提交
2635
		}
Y
yamahigashi 已提交
2636

M
Mr.doob 已提交
2637 2638
		var conns = connections.get( returnObject.id );
		var containerIndices = conns.parents;
Y
yamahigashi 已提交
2639

M
Mr.doob 已提交
2640
		for ( var containerIndicesIndex = containerIndices.length - 1; containerIndicesIndex >= 0; -- containerIndicesIndex ) {
Y
yamahigashi 已提交
2641

M
Mr.doob 已提交
2642
			var boneID = findIndex( sceneGraph.skeleton.bones, function ( bone ) {
Y
yamahigashi 已提交
2643

M
Mr.doob 已提交
2644
				return bone.FBX_ID === containerIndices[ containerIndicesIndex ].ID;
Y
yamahigashi 已提交
2645

M
Mr.doob 已提交
2646 2647
			} );
			if ( boneID > - 1 ) {
Y
yamahigashi 已提交
2648

M
Mr.doob 已提交
2649 2650 2651 2652
				returnObject.containerBoneID = boneID;
				returnObject.containerID = containerIndices[ containerIndicesIndex ].ID;
				var model = rawModels[ returnObject.containerID.toString() ];
				if ( 'PreRotation' in model.properties ) {
Y
yamahigashi 已提交
2653

M
Mr.doob 已提交
2654
					returnObject.preRotations = parseVector3( model.properties.PreRotation ).multiplyScalar( Math.PI / 180 );
Y
yamahigashi 已提交
2655

Y
yamahigashi 已提交
2656
				}
M
Mr.doob 已提交
2657
				break;
Y
yamahigashi 已提交
2658

Y
yamahigashi 已提交
2659
			}
Y
yamahigashi 已提交
2660

Y
yamahigashi 已提交
2661
		}
Y
yamahigashi 已提交
2662

M
Mr.doob 已提交
2663
		return returnObject;
Y
yamahigashi 已提交
2664

M
Mr.doob 已提交
2665
	}
Y
yamahigashi 已提交
2666

M
Mr.doob 已提交
2667 2668 2669 2670
	/**
	 * @param {{id: number, subNodes: {KeyTime: {properties: {a: string}}, KeyValueFloat: {properties: {a: string}}, KeyAttrFlags: {properties: {a: string}}, KeyAttrDataFloat: {properties: {a: string}}}}} animationCurve
	 */
	function parseAnimationCurve( animationCurve ) {
Y
yamahigashi 已提交
2671

M
Mr.doob 已提交
2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
		return {
			version: null,
			id: animationCurve.id,
			internalID: animationCurve.id,
			times: parseFloatArray( animationCurve.subNodes.KeyTime.properties.a ).map( convertFBXTimeToSeconds ),
			values: parseFloatArray( animationCurve.subNodes.KeyValueFloat.properties.a ),

			attrFlag: parseIntArray( animationCurve.subNodes.KeyAttrFlags.properties.a ),
			attrData: parseFloatArray( animationCurve.subNodes.KeyAttrDataFloat.properties.a )
		};
Y
yamahigashi 已提交
2682

M
Mr.doob 已提交
2683
	}
Y
yamahigashi 已提交
2684

M
Mr.doob 已提交
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812
	/**
	 * Sets the maxTimeStamp and minTimeStamp variables if it has timeStamps that are either larger or smaller
	 * than the max or min respectively.
	 * @param {{
				T: {
						id: number,
						attr: string,
						internalID: number,
						attrX: boolean,
						attrY: boolean,
						attrZ: boolean,
						containerBoneID: number,
						containerID: number,
						curves: {
								x: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
								y: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
								z: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
						},
				},
				R: {
						id: number,
						attr: string,
						internalID: number,
						attrX: boolean,
						attrY: boolean,
						attrZ: boolean,
						containerBoneID: number,
						containerID: number,
						curves: {
								x: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
								y: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
								z: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
						},
				},
				S: {
						id: number,
						attr: string,
						internalID: number,
						attrX: boolean,
						attrY: boolean,
						attrZ: boolean,
						containerBoneID: number,
						containerID: number,
						curves: {
								x: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
								y: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
								z: {
										version: any,
										id: number,
										internalID: number,
										times: number[],
										values: number[],
										attrFlag: number[],
										attrData: number[],
								},
						},
				},
		}} layer
	 */
	function getCurveNodeMaxMinTimeStamps( layer, timestamps ) {

		if ( layer.R ) {

			getCurveMaxMinTimeStamp( layer.R.curves, timestamps );
Y
yamahigashi 已提交
2813

M
Mr.doob 已提交
2814 2815
		}
		if ( layer.S ) {
Y
yamahigashi 已提交
2816

M
Mr.doob 已提交
2817
			getCurveMaxMinTimeStamp( layer.S.curves, timestamps );
Y
yamahigashi 已提交
2818

M
Mr.doob 已提交
2819 2820
		}
		if ( layer.T ) {
Y
yamahigashi 已提交
2821

M
Mr.doob 已提交
2822
			getCurveMaxMinTimeStamp( layer.T.curves, timestamps );
Y
yamahigashi 已提交
2823

M
Mr.doob 已提交
2824
		}
Y
yamahigashi 已提交
2825

M
Mr.doob 已提交
2826
	}
Y
yamahigashi 已提交
2827

M
Mr.doob 已提交
2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857
	/**
	 * Sets the maxTimeStamp and minTimeStamp if one of the curve's time stamps
	 * exceeds the maximum or minimum.
	 * @param {{
				x: {
						version: any,
						id: number,
						internalID: number,
						times: number[],
						values: number[],
						attrFlag: number[],
						attrData: number[],
				},
				y: {
						version: any,
						id: number,
						internalID: number,
						times: number[],
						values: number[],
						attrFlag: number[],
						attrData: number[],
				},
				z: {
						version: any,
						id: number,
						internalID: number,
						times: number[],
						values: number[],
						attrFlag: number[],
						attrData: number[],
Y
yamahigashi 已提交
2858
				}
M
Mr.doob 已提交
2859 2860 2861
		}} curve
	 */
	function getCurveMaxMinTimeStamp( curve, timestamps ) {
Y
yamahigashi 已提交
2862

M
Mr.doob 已提交
2863
		if ( curve.x ) {
Y
yamahigashi 已提交
2864

M
Mr.doob 已提交
2865
			getCurveAxisMaxMinTimeStamps( curve.x, timestamps );
Y
yamahigashi 已提交
2866

Y
yamahigashi 已提交
2867
		}
M
Mr.doob 已提交
2868
		if ( curve.y ) {
Y
yamahigashi 已提交
2869

M
Mr.doob 已提交
2870
			getCurveAxisMaxMinTimeStamps( curve.y, timestamps );
Y
yamahigashi 已提交
2871

M
Mr.doob 已提交
2872 2873
		}
		if ( curve.z ) {
2874

M
Mr.doob 已提交
2875
			getCurveAxisMaxMinTimeStamps( curve.z, timestamps );
2876

M
Mr.doob 已提交
2877
		}
2878

M
Mr.doob 已提交
2879
	}
Y
yamahigashi 已提交
2880

M
Mr.doob 已提交
2881 2882 2883 2884 2885
	/**
	 * Sets the maxTimeStamp and minTimeStamp if one of its timestamps exceeds the maximum or minimum.
	 * @param {{times: number[]}} axis
	 */
	function getCurveAxisMaxMinTimeStamps( axis, timestamps ) {
Y
yamahigashi 已提交
2886

M
Mr.doob 已提交
2887 2888
		timestamps.max = axis.times[ axis.times.length - 1 ] > timestamps.max ? axis.times[ axis.times.length - 1 ] : timestamps.max;
		timestamps.min = axis.times[ 0 ] < timestamps.min ? axis.times[ 0 ] : timestamps.min;
Y
yamahigashi 已提交
2889

M
Mr.doob 已提交
2890
	}
Y
yamahigashi 已提交
2891

M
Mr.doob 已提交
2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266
	/**
	 * @param {{
		curves: Map<number, {
			T: {
				id: number;
				attr: string;
				internalID: number;
				attrX: boolean;
				attrY: boolean;
				attrZ: boolean;
				containerBoneID: number;
				containerID: number;
				curves: {
					x: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					y: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					z: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
				};
			};
			R: {
				id: number;
				attr: string;
				internalID: number;
				attrX: boolean;
				attrY: boolean;
				attrZ: boolean;
				containerBoneID: number;
				containerID: number;
				curves: {
					x: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					y: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					z: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
				};
			};
			S: {
				id: number;
				attr: string;
				internalID: number;
				attrX: boolean;
				attrY: boolean;
				attrZ: boolean;
				containerBoneID: number;
				containerID: number;
				curves: {
					x: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					y: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					z: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
				};
			};
		}>;
		layers: Map<number, {
			T: {
				id: number;
				attr: string;
				internalID: number;
				attrX: boolean;
				attrY: boolean;
				attrZ: boolean;
				containerBoneID: number;
				containerID: number;
				curves: {
					x: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					y: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					z: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
				};
			};
			R: {
				id: number;
				attr: string;
				internalID: number;
				attrX: boolean;
				attrY: boolean;
				attrZ: boolean;
				containerBoneID: number;
				containerID: number;
				curves: {
					x: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					y: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					z: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
				};
			};
			S: {
				id: number;
				attr: string;
				internalID: number;
				attrX: boolean;
				attrY: boolean;
				attrZ: boolean;
				containerBoneID: number;
				containerID: number;
				curves: {
					x: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					y: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
					z: {
						version: any;
						id: number;
						internalID: number;
						times: number[];
						values: number[];
						attrFlag: number[];
						attrData: number[];
					};
				};
			};
		}[]>;
		stacks: Map<number, {
			name: string;
			layers: {
				T: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					};
				};
				R: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					};
				};
				S: {
					id: number;
					attr: string;
					internalID: number;
					attrX: boolean;
					attrY: boolean;
					attrZ: boolean;
					containerBoneID: number;
					containerID: number;
					curves: {
						x: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						y: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
						z: {
							version: any;
							id: number;
							internalID: number;
							times: number[];
							values: number[];
							attrFlag: number[];
							attrData: number[];
						};
					};
				};
			}[][];
			length: number;
			frames: number;
		}>;
		length: number;
		fps: number;
		frames: number;
	}} animations,
	 * @param {{skeleton: { bones: THREE.Bone[]}}} group
	 */
	function addAnimations( group, animations ) {

		if ( group.animations === undefined ) {

			group.animations = [];
Y
yamahigashi 已提交
3267

M
Mr.doob 已提交
3268
		}
Y
yamahigashi 已提交
3269

M
Mr.doob 已提交
3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298
		var stacks = animations.stacks;

		for ( var key in stacks ) {

			var stack = stacks[ key ];

			/**
			 * @type {{
			 * name: string,
			 * fps: number,
			 * length: number,
			 * hierarchy: Array.<{
			 * 	parent: number,
			 * 	name: string,
			 * 	keys: Array.<{
			 * 		time: number,
			 * 		pos: Array.<number>,
			 * 		rot: Array.<number>,
			 * 		scl: Array.<number>
			 * 	}>
			 * }>
			 * }}
			 */
			var animationData = {
				name: stack.name,
				fps: 30,
				length: stack.length,
				hierarchy: []
			};
Y
yamahigashi 已提交
3299

M
Mr.doob 已提交
3300
			var bones = group.skeleton.bones;
Y
yamahigashi 已提交
3301

M
Mr.doob 已提交
3302
			for ( var bonesIndex = 0, bonesLength = bones.length; bonesIndex < bonesLength; ++ bonesIndex ) {
Y
yamahigashi 已提交
3303

M
Mr.doob 已提交
3304
				var bone = bones[ bonesIndex ];
Y
yamahigashi 已提交
3305

M
Mr.doob 已提交
3306 3307
				var name = bone.name.replace( /.*:/, '' );
				var parentIndex = findIndex( bones, function ( parentBone ) {
Y
yamahigashi 已提交
3308

M
Mr.doob 已提交
3309
					return bone.parent === parentBone;
Y
yamahigashi 已提交
3310

M
Mr.doob 已提交
3311 3312
				} );
				animationData.hierarchy.push( { parent: parentIndex, name: name, keys: [] } );
Y
yamahigashi 已提交
3313

Y
yamahigashi 已提交
3314
			}
Y
yamahigashi 已提交
3315

M
Mr.doob 已提交
3316
			for ( var frame = 0; frame <= stack.frames; frame ++ ) {
Y
yamahigashi 已提交
3317

M
Mr.doob 已提交
3318
				for ( var bonesIndex = 0, bonesLength = bones.length; bonesIndex < bonesLength; ++ bonesIndex ) {
Y
yamahigashi 已提交
3319

M
Mr.doob 已提交
3320 3321
					var bone = bones[ bonesIndex ];
					var boneIndex = bonesIndex;
Y
yamahigashi 已提交
3322

M
Mr.doob 已提交
3323
					var animationNode = stack.layers[ 0 ][ boneIndex ];
Y
yamahigashi 已提交
3324

M
Mr.doob 已提交
3325
					for ( var hierarchyIndex = 0, hierarchyLength = animationData.hierarchy.length; hierarchyIndex < hierarchyLength; ++ hierarchyIndex ) {
Y
yamahigashi 已提交
3326

M
Mr.doob 已提交
3327
						var node = animationData.hierarchy[ hierarchyIndex ];
Y
yamahigashi 已提交
3328

M
Mr.doob 已提交
3329
						if ( node.name === bone.name ) {
Y
yamahigashi 已提交
3330

M
Mr.doob 已提交
3331
							node.keys.push( generateKey( animations, animationNode, bone, frame ) );
Y
yamahigashi 已提交
3332

M
Mr.doob 已提交
3333
						}
Y
yamahigashi 已提交
3334

M
Mr.doob 已提交
3335
					}
Y
yamahigashi 已提交
3336

M
Mr.doob 已提交
3337
				}
Y
yamahigashi 已提交
3338

Y
yamahigashi 已提交
3339
			}
Y
yamahigashi 已提交
3340

M
Mr.doob 已提交
3341
			group.animations.push( THREE.AnimationClip.parseAnimation( animationData, bones ) );
Y
yamahigashi 已提交
3342

Y
yamahigashi 已提交
3343
		}
Y
yamahigashi 已提交
3344

M
Mr.doob 已提交
3345
	}
Y
yamahigashi 已提交
3346

M
Mr.doob 已提交
3347 3348
	var euler = new THREE.Euler();
	var quaternion = new THREE.Quaternion();
Y
yamahigashi 已提交
3349

M
Mr.doob 已提交
3350 3351 3352 3353
	/**
	 * @param {THREE.Bone} bone
	 */
	function generateKey( animations, animationNode, bone, frame ) {
Y
yamahigashi 已提交
3354

M
Mr.doob 已提交
3355 3356 3357 3358 3359 3360 3361 3362
		var key = {
			time: frame / animations.fps,
			pos: bone.position.toArray(),
			rot: bone.quaternion.toArray(),
			scl: bone.scale.toArray()
		};

		if ( animationNode === undefined ) return key;
Y
yamahigashi 已提交
3363

M
Mr.doob 已提交
3364
		try {
Y
yamahigashi 已提交
3365

M
Mr.doob 已提交
3366
			if ( hasCurve( animationNode, 'T' ) && hasKeyOnFrame( animationNode.T, frame ) ) {
Y
yamahigashi 已提交
3367

M
Mr.doob 已提交
3368
				key.pos = [ animationNode.T.curves.x.values[ frame ], animationNode.T.curves.y.values[ frame ], animationNode.T.curves.z.values[ frame ] ];
Y
yamahigashi 已提交
3369

M
Mr.doob 已提交
3370
			}
Y
yamahigashi 已提交
3371

M
Mr.doob 已提交
3372
			if ( hasCurve( animationNode, 'R' ) && hasKeyOnFrame( animationNode.R, frame ) ) {
Y
yamahigashi 已提交
3373

M
Mr.doob 已提交
3374 3375 3376 3377 3378 3379
				var rotationX = animationNode.R.curves.x.values[ frame ];
				var rotationY = animationNode.R.curves.y.values[ frame ];
				var rotationZ = animationNode.R.curves.z.values[ frame ];

				quaternion.setFromEuler( euler.set( rotationX, rotationY, rotationZ, 'ZYX' ) );
				key.rot = quaternion.toArray();
Y
yamahigashi 已提交
3380

Y
yamahigashi 已提交
3381
			}
Y
yamahigashi 已提交
3382

M
Mr.doob 已提交
3383
			if ( hasCurve( animationNode, 'S' ) && hasKeyOnFrame( animationNode.S, frame ) ) {
Y
yamahigashi 已提交
3384

M
Mr.doob 已提交
3385
				key.scl = [ animationNode.S.curves.x.values[ frame ], animationNode.S.curves.y.values[ frame ], animationNode.S.curves.z.values[ frame ] ];
Y
yamahigashi 已提交
3386

M
Mr.doob 已提交
3387
			}
Y
yamahigashi 已提交
3388

M
Mr.doob 已提交
3389
		} catch ( error ) {
Y
yamahigashi 已提交
3390

M
Mr.doob 已提交
3391
			// Curve is not fully plotted.
M
Mugen87 已提交
3392 3393
			console.log( 'THREE.FBXLoader: ', bone );
			console.log( 'THREE.FBXLoader: ', error );
Y
yamahigashi 已提交
3394

Y
yamahigashi 已提交
3395
		}
Y
yamahigashi 已提交
3396

M
Mr.doob 已提交
3397
		return key;
3398

M
Mr.doob 已提交
3399
	}
3400

M
Mr.doob 已提交
3401
	var AXES = [ 'x', 'y', 'z' ];
3402

M
Mr.doob 已提交
3403
	function hasCurve( animationNode, attribute ) {
3404

M
Mr.doob 已提交
3405
		if ( animationNode === undefined ) {
3406

M
Mr.doob 已提交
3407 3408 3409
			return false;

		}
Y
yamahigashi 已提交
3410

M
Mr.doob 已提交
3411
		var attributeNode = animationNode[ attribute ];
Y
yamahigashi 已提交
3412

M
Mr.doob 已提交
3413
		if ( ! attributeNode ) {
Y
yamahigashi 已提交
3414

M
Mr.doob 已提交
3415
			return false;
Y
yamahigashi 已提交
3416

Y
yamahigashi 已提交
3417
		}
Y
yamahigashi 已提交
3418

M
Mr.doob 已提交
3419
		return AXES.every( function ( key ) {
Y
yamahigashi 已提交
3420

M
Mr.doob 已提交
3421
			return attributeNode.curves[ key ] !== null;
Y
yamahigashi 已提交
3422

M
Mr.doob 已提交
3423
		} );
Y
yamahigashi 已提交
3424

M
Mr.doob 已提交
3425
	}
Y
yamahigashi 已提交
3426

M
Mr.doob 已提交
3427
	function hasKeyOnFrame( attributeNode, frame ) {
Y
yamahigashi 已提交
3428

M
Mr.doob 已提交
3429
		return AXES.every( function ( key ) {
Y
yamahigashi 已提交
3430

M
Mr.doob 已提交
3431
			return isKeyExistOnFrame( attributeNode.curves[ key ], frame );
Y
yamahigashi 已提交
3432

M
Mr.doob 已提交
3433
		} );
Y
yamahigashi 已提交
3434

M
Mr.doob 已提交
3435
	}
Y
yamahigashi 已提交
3436

M
Mr.doob 已提交
3437
	function isKeyExistOnFrame( curve, frame ) {
Y
yamahigashi 已提交
3438

M
Mr.doob 已提交
3439
		return curve.values[ frame ] !== undefined;
Y
yamahigashi 已提交
3440

M
Mr.doob 已提交
3441
	}
Y
yamahigashi 已提交
3442

M
Mr.doob 已提交
3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483
	/**
	 * An instance of a Vertex with data for drawing vertices to the screen.
	 * @constructor
	 */
	function Vertex() {

		/**
		 * Position of the vertex.
		 * @type {THREE.Vector3}
		 */
		this.position = new THREE.Vector3();

		/**
		 * Normal of the vertex
		 * @type {THREE.Vector3}
		 */
		this.normal = new THREE.Vector3();

		/**
		 * UV coordinates of the vertex.
		 * @type {THREE.Vector2}
		 */
		this.uv = new THREE.Vector2();

		/**
		 * Color of the vertex
		 * @type {THREE.Vector3}
		 */
		this.color = new THREE.Vector3();

		/**
		 * Indices of the bones vertex is influenced by.
		 * @type {THREE.Vector4}
		 */
		this.skinIndices = new THREE.Vector4( 0, 0, 0, 0 );

		/**
		 * Weights that each bone influences the vertex.
		 * @type {THREE.Vector4}
		 */
		this.skinWeights = new THREE.Vector4( 0, 0, 0, 0 );
Y
yamahigashi 已提交
3484

M
Mr.doob 已提交
3485
	}
Y
yamahigashi 已提交
3486

M
Mr.doob 已提交
3487
	Object.assign( Vertex.prototype, {
Y
yamahigashi 已提交
3488

M
Mr.doob 已提交
3489
		copy: function ( target ) {
Y
yamahigashi 已提交
3490

M
Mr.doob 已提交
3491
			var returnVar = target || new Vertex();
Y
yamahigashi 已提交
3492

M
Mr.doob 已提交
3493 3494 3495 3496 3497
			returnVar.position.copy( this.position );
			returnVar.normal.copy( this.normal );
			returnVar.uv.copy( this.uv );
			returnVar.skinIndices.copy( this.skinIndices );
			returnVar.skinWeights.copy( this.skinWeights );
Y
yamahigashi 已提交
3498

M
Mr.doob 已提交
3499
			return returnVar;
Y
yamahigashi 已提交
3500

M
Mr.doob 已提交
3501
		},
Y
yamahigashi 已提交
3502

M
Mr.doob 已提交
3503
		flattenToBuffers: function ( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer ) {
Y
yamahigashi 已提交
3504

M
Mr.doob 已提交
3505 3506 3507 3508 3509 3510
			this.position.toArray( vertexBuffer, vertexBuffer.length );
			this.normal.toArray( normalBuffer, normalBuffer.length );
			this.uv.toArray( uvBuffer, uvBuffer.length );
			this.color.toArray( colorBuffer, colorBuffer.length );
			this.skinIndices.toArray( skinIndexBuffer, skinIndexBuffer.length );
			this.skinWeights.toArray( skinWeightBuffer, skinWeightBuffer.length );
Y
yamahigashi 已提交
3511

Y
yamahigashi 已提交
3512
		}
Y
yamahigashi 已提交
3513

M
Mr.doob 已提交
3514
	} );
Y
yamahigashi 已提交
3515

M
Mr.doob 已提交
3516 3517 3518 3519
	/**
	 * @constructor
	 */
	function Triangle() {
Y
yamahigashi 已提交
3520

M
Mr.doob 已提交
3521 3522 3523 3524
		/**
		 * @type {{position: THREE.Vector3, normal: THREE.Vector3, uv: THREE.Vector2, skinIndices: THREE.Vector4, skinWeights: THREE.Vector4}[]}
		 */
		this.vertices = [];
Y
yamahigashi 已提交
3525

M
Mr.doob 已提交
3526
	}
Y
yamahigashi 已提交
3527

M
Mr.doob 已提交
3528
	Object.assign( Triangle.prototype, {
Y
yamahigashi 已提交
3529

M
Mr.doob 已提交
3530
		copy: function ( target ) {
Y
yamahigashi 已提交
3531

M
Mr.doob 已提交
3532
			var returnVar = target || new Triangle();
Y
yamahigashi 已提交
3533

M
Mr.doob 已提交
3534
			for ( var i = 0; i < this.vertices.length; ++ i ) {
Y
yamahigashi 已提交
3535

M
Mr.doob 已提交
3536
				 this.vertices[ i ].copy( returnVar.vertices[ i ] );
Y
yamahigashi 已提交
3537

M
Mr.doob 已提交
3538 3539 3540 3541 3542
			}

			return returnVar;

		},
Y
yamahigashi 已提交
3543

M
Mr.doob 已提交
3544
		flattenToBuffers: function ( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer ) {
Y
yamahigashi 已提交
3545

M
Mr.doob 已提交
3546
			var vertices = this.vertices;
Y
yamahigashi 已提交
3547

M
Mr.doob 已提交
3548
			for ( var i = 0, l = vertices.length; i < l; ++ i ) {
Y
yamahigashi 已提交
3549

M
Mr.doob 已提交
3550
				vertices[ i ].flattenToBuffers( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer );
Y
yamahigashi 已提交
3551

Y
yamahigashi 已提交
3552
			}
Y
yamahigashi 已提交
3553

Y
yamahigashi 已提交
3554
		}
Y
yamahigashi 已提交
3555

M
Mr.doob 已提交
3556
	} );
Y
yamahigashi 已提交
3557

M
Mr.doob 已提交
3558 3559 3560 3561
	/**
	 * @constructor
	 */
	function Face() {
Y
yamahigashi 已提交
3562

M
Mr.doob 已提交
3563 3564 3565 3566 3567
		/**
		 * @type {{vertices: {position: THREE.Vector3, normal: THREE.Vector3, uv: THREE.Vector2, skinIndices: THREE.Vector4, skinWeights: THREE.Vector4}[]}[]}
		 */
		this.triangles = [];
		this.materialIndex = 0;
Y
yamahigashi 已提交
3568

M
Mr.doob 已提交
3569
	}
Y
yamahigashi 已提交
3570

M
Mr.doob 已提交
3571
	Object.assign( Face.prototype, {
Y
yamahigashi 已提交
3572

M
Mr.doob 已提交
3573
		copy: function ( target ) {
Y
yamahigashi 已提交
3574

M
Mr.doob 已提交
3575
			var returnVar = target || new Face();
Y
yamahigashi 已提交
3576

M
Mr.doob 已提交
3577
			for ( var i = 0; i < this.triangles.length; ++ i ) {
Y
yamahigashi 已提交
3578

M
Mr.doob 已提交
3579
				this.triangles[ i ].copy( returnVar.triangles[ i ] );
Y
yamahigashi 已提交
3580

M
Mr.doob 已提交
3581
			}
Y
yamahigashi 已提交
3582

M
Mr.doob 已提交
3583
			returnVar.materialIndex = this.materialIndex;
Y
yamahigashi 已提交
3584

M
Mr.doob 已提交
3585
			return returnVar;
Y
yamahigashi 已提交
3586

M
Mr.doob 已提交
3587
		},
Y
yamahigashi 已提交
3588

M
Mr.doob 已提交
3589
		genTrianglesFromVertices: function ( vertexArray ) {
Y
yamahigashi 已提交
3590

M
Mr.doob 已提交
3591
			for ( var i = 2; i < vertexArray.length; ++ i ) {
Y
yamahigashi 已提交
3592

M
Mr.doob 已提交
3593 3594 3595 3596 3597
				var triangle = new Triangle();
				triangle.vertices[ 0 ] = vertexArray[ 0 ];
				triangle.vertices[ 1 ] = vertexArray[ i - 1 ];
				triangle.vertices[ 2 ] = vertexArray[ i ];
				this.triangles.push( triangle );
K
Kyle Larson 已提交
3598

M
Mr.doob 已提交
3599
			}
K
Kyle Larson 已提交
3600

M
Mr.doob 已提交
3601
		},
K
Kyle Larson 已提交
3602

M
Mr.doob 已提交
3603
		flattenToBuffers: function ( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer, materialIndexBuffer ) {
K
Kyle Larson 已提交
3604

M
Mr.doob 已提交
3605 3606
			var triangles = this.triangles;
			var materialIndex = this.materialIndex;
K
Kyle Larson 已提交
3607

M
Mr.doob 已提交
3608
			for ( var i = 0, l = triangles.length; i < l; ++ i ) {
K
Kyle Larson 已提交
3609

M
Mr.doob 已提交
3610 3611
				triangles[ i ].flattenToBuffers( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer );
				append( materialIndexBuffer, [ materialIndex, materialIndex, materialIndex ] );
K
Kyle Larson 已提交
3612 3613 3614

			}

M
Mr.doob 已提交
3615
		}
K
Kyle Larson 已提交
3616

M
Mr.doob 已提交
3617
	} );
K
Kyle Larson 已提交
3618

M
Mr.doob 已提交
3619 3620 3621 3622
	/**
	 * @constructor
	 */
	function Geometry() {
K
Kyle Larson 已提交
3623

M
Mr.doob 已提交
3624 3625 3626 3627
		/**
		 * @type {{triangles: {vertices: {position: THREE.Vector3, normal: THREE.Vector3, uv: THREE.Vector2, skinIndices: THREE.Vector4, skinWeights: THREE.Vector4}[]}[], materialIndex: number}[]}
		 */
		this.faces = [];
K
Kyle Larson 已提交
3628

M
Mr.doob 已提交
3629 3630 3631 3632
		/**
		 * @type {{}|THREE.Skeleton}
		 */
		this.skeleton = null;
K
Kyle Larson 已提交
3633

M
Mr.doob 已提交
3634
	}
K
Kyle Larson 已提交
3635

M
Mr.doob 已提交
3636
	Object.assign( Geometry.prototype, {
K
Kyle Larson 已提交
3637

M
Mr.doob 已提交
3638 3639 3640 3641
		/**
		 * @returns	{{vertexBuffer: number[], normalBuffer: number[], uvBuffer: number[], skinIndexBuffer: number[], skinWeightBuffer: number[], materialIndexBuffer: number[]}}
		 */
		flattenToBuffers: function () {
K
Kyle Larson 已提交
3642

M
Mr.doob 已提交
3643 3644 3645 3646 3647 3648
			var vertexBuffer = [];
			var normalBuffer = [];
			var uvBuffer = [];
			var colorBuffer = [];
			var skinIndexBuffer = [];
			var skinWeightBuffer = [];
Y
yamahigashi 已提交
3649

M
Mr.doob 已提交
3650
			var materialIndexBuffer = [];
Y
yamahigashi 已提交
3651

M
Mr.doob 已提交
3652
			var faces = this.faces;
Y
yamahigashi 已提交
3653

M
Mr.doob 已提交
3654
			for ( var i = 0, l = faces.length; i < l; ++ i ) {
Y
yamahigashi 已提交
3655

M
Mr.doob 已提交
3656
				faces[ i ].flattenToBuffers( vertexBuffer, normalBuffer, uvBuffer, colorBuffer, skinIndexBuffer, skinWeightBuffer, materialIndexBuffer );
Y
yamahigashi 已提交
3657

M
Mr.doob 已提交
3658
			}
Y
yamahigashi 已提交
3659

M
Mr.doob 已提交
3660 3661 3662 3663 3664 3665 3666 3667 3668
			return {
				vertexBuffer: vertexBuffer,
				normalBuffer: normalBuffer,
				uvBuffer: uvBuffer,
				colorBuffer: colorBuffer,
				skinIndexBuffer: skinIndexBuffer,
				skinWeightBuffer: skinWeightBuffer,
				materialIndexBuffer: materialIndexBuffer
			};
Y
yamahigashi 已提交
3669

M
Mr.doob 已提交
3670
		}
Y
yamahigashi 已提交
3671

M
Mr.doob 已提交
3672
	} );
Y
yamahigashi 已提交
3673

M
Mr.doob 已提交
3674
	function TextParser() {}
Y
yamahigashi 已提交
3675

M
Mr.doob 已提交
3676
	Object.assign( TextParser.prototype, {
Y
yamahigashi 已提交
3677

M
Mr.doob 已提交
3678
		getPrevNode: function () {
Y
yamahigashi 已提交
3679

M
Mr.doob 已提交
3680
			return this.nodeStack[ this.currentIndent - 2 ];
Y
yamahigashi 已提交
3681

M
Mr.doob 已提交
3682
		},
Y
yamahigashi 已提交
3683

M
Mr.doob 已提交
3684
		getCurrentNode: function () {
Y
yamahigashi 已提交
3685

M
Mr.doob 已提交
3686
			return this.nodeStack[ this.currentIndent - 1 ];
Y
yamahigashi 已提交
3687

M
Mr.doob 已提交
3688
		},
Y
yamahigashi 已提交
3689

M
Mr.doob 已提交
3690
		getCurrentProp: function () {
Y
yamahigashi 已提交
3691

M
Mr.doob 已提交
3692
			return this.currentProp;
Y
yamahigashi 已提交
3693

M
Mr.doob 已提交
3694
		},
Y
yamahigashi 已提交
3695

M
Mr.doob 已提交
3696
		pushStack: function ( node ) {
Y
yamahigashi 已提交
3697

M
Mr.doob 已提交
3698 3699
			this.nodeStack.push( node );
			this.currentIndent += 1;
Y
yamahigashi 已提交
3700

M
Mr.doob 已提交
3701
		},
Y
yamahigashi 已提交
3702

M
Mr.doob 已提交
3703
		popStack: function () {
Y
yamahigashi 已提交
3704

M
Mr.doob 已提交
3705 3706
			this.nodeStack.pop();
			this.currentIndent -= 1;
Y
yamahigashi 已提交
3707

M
Mr.doob 已提交
3708
		},
Y
yamahigashi 已提交
3709

M
Mr.doob 已提交
3710
		setCurrentProp: function ( val, name ) {
Y
yamahigashi 已提交
3711

M
Mr.doob 已提交
3712 3713
			this.currentProp = val;
			this.currentPropName = name;
Y
yamahigashi 已提交
3714

M
Mr.doob 已提交
3715
		},
Y
yamahigashi 已提交
3716

M
Mr.doob 已提交
3717 3718
		// ----------parse ---------------------------------------------------
		parse: function ( text ) {
Y
yamahigashi 已提交
3719

M
Mr.doob 已提交
3720 3721 3722 3723 3724
			this.currentIndent = 0;
			this.allNodes = new FBXTree();
			this.nodeStack = [];
			this.currentProp = [];
			this.currentPropName = '';
Y
yamahigashi 已提交
3725

M
Mugen87 已提交
3726
			var split = text.split( '\n' );
Y
yamahigashi 已提交
3727

3728
			for ( var lineNum = 0, lineLength = split.length; lineNum < lineLength; lineNum ++ ) {
Y
yamahigashi 已提交
3729

3730
				var l = split[ lineNum ];
Y
yamahigashi 已提交
3731

3732
				// skip comment line
M
Mr.doob 已提交
3733 3734 3735
				if ( l.match( /^[\s\t]*;/ ) ) {

					continue;
Y
yamahigashi 已提交
3736

3737 3738 3739
				}

				// skip empty line
M
Mr.doob 已提交
3740
				if ( l.match( /^[\s\t]*$/ ) ) {
Y
yamahigashi 已提交
3741

M
Mr.doob 已提交
3742
					continue;
Y
yamahigashi 已提交
3743

3744
				}
Y
yamahigashi 已提交
3745

M
Mr.doob 已提交
3746
				// beginning of node
M
Mugen87 已提交
3747
				var beginningOfNodeExp = new RegExp( '^\\t{' + this.currentIndent + '}(\\w+):(.*){', '' );
M
Mr.doob 已提交
3748
				var match = l.match( beginningOfNodeExp );
3749

M
Mr.doob 已提交
3750
				if ( match ) {
Y
yamahigashi 已提交
3751

M
Mugen87 已提交
3752
					var nodeName = match[ 1 ].trim().replace( /^"/, '' ).replace( /"$/, '' );
M
Mr.doob 已提交
3753
					var nodeAttrs = match[ 2 ].split( ',' );
Y
yamahigashi 已提交
3754

M
Mr.doob 已提交
3755
					for ( var i = 0, l = nodeAttrs.length; i < l; i ++ ) {
M
Mugen87 已提交
3756

M
Mr.doob 已提交
3757
						nodeAttrs[ i ] = nodeAttrs[ i ].trim().replace( /^"/, '' ).replace( /"$/, '' );
M
Mugen87 已提交
3758

M
Mr.doob 已提交
3759 3760 3761 3762 3763 3764
					}

					this.parseNodeBegin( l, nodeName, nodeAttrs || null );
					continue;

				}
Y
yamahigashi 已提交
3765

M
Mr.doob 已提交
3766
				// node's property
M
Mugen87 已提交
3767
				var propExp = new RegExp( '^\\t{' + ( this.currentIndent ) + '}(\\w+):[\\s\\t\\r\\n](.*)' );
M
Mr.doob 已提交
3768
				var match = l.match( propExp );
3769

M
Mr.doob 已提交
3770
				if ( match ) {
Y
yamahigashi 已提交
3771

M
Mugen87 已提交
3772 3773
					var propName = match[ 1 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
					var propValue = match[ 2 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
Y
yamahigashi 已提交
3774

3775 3776 3777 3778 3779 3780 3781 3782 3783
					// for special case: base64 image data follows "Content: ," line
					//	Content: ,
					//	 "iVB..."
					if ( propName === 'Content' && propValue === ',' ) {

						propValue = split[ ++ lineNum ].replace( /"/g, '' ).trim();

					}

M
Mr.doob 已提交
3784 3785
					this.parseNodeProperty( l, propName, propValue );
					continue;
Y
yamahigashi 已提交
3786

M
Mr.doob 已提交
3787
				}
Y
yamahigashi 已提交
3788

M
Mr.doob 已提交
3789
				// end of node
M
Mugen87 已提交
3790
				var endOfNodeExp = new RegExp( '^\\t{' + ( this.currentIndent - 1 ) + '}}' );
3791

M
Mr.doob 已提交
3792
				if ( l.match( endOfNodeExp ) ) {
Y
yamahigashi 已提交
3793

M
Mr.doob 已提交
3794 3795
					this.nodeEnd();
					continue;
Y
yamahigashi 已提交
3796

Y
yamahigashi 已提交
3797
				}
Y
yamahigashi 已提交
3798

M
Mr.doob 已提交
3799 3800 3801 3802 3803 3804 3805 3806 3807 3808
				// for special case,
				//
				//	  Vertices: *8670 {
				//		  a: 0.0356229953467846,13.9599733352661,-0.399196773.....(snip)
				// -0.0612030513584614,13.960485458374,-0.409748703241348,-0.10.....
				// 0.12490539252758,13.7450733184814,-0.454119384288788,0.09272.....
				// 0.0836158767342567,13.5432004928589,-0.435397416353226,0.028.....
				//
				// these case the lines must contiue with previous line
				if ( l.match( /^[^\s\t}]/ ) ) {
Y
yamahigashi 已提交
3809

M
Mr.doob 已提交
3810
					this.parseNodePropertyContinued( l );
Y
yamahigashi 已提交
3811

M
Mr.doob 已提交
3812
				}
Y
yamahigashi 已提交
3813

Y
yamahigashi 已提交
3814
			}
Y
yamahigashi 已提交
3815

M
Mr.doob 已提交
3816
			return this.allNodes;
Y
yamahigashi 已提交
3817

M
Mr.doob 已提交
3818
		},
Y
yamahigashi 已提交
3819

M
Mr.doob 已提交
3820
		parseNodeBegin: function ( line, nodeName, nodeAttrs ) {
Y
yamahigashi 已提交
3821

M
Mr.doob 已提交
3822 3823 3824 3825
			// var nodeName = match[1];
			var node = { 'name': nodeName, properties: {}, 'subNodes': {} };
			var attrs = this.parseNodeAttr( nodeAttrs );
			var currentNode = this.getCurrentNode();
Y
yamahigashi 已提交
3826

M
Mr.doob 已提交
3827 3828
			// a top node
			if ( this.currentIndent === 0 ) {
Y
yamahigashi 已提交
3829

M
Mr.doob 已提交
3830
				this.allNodes.add( nodeName, node );
Y
yamahigashi 已提交
3831

M
Mr.doob 已提交
3832
			} else {
Y
yamahigashi 已提交
3833

M
Mr.doob 已提交
3834
				// a subnode
Y
yamahigashi 已提交
3835

M
Mr.doob 已提交
3836 3837
				// already exists subnode, then append it
				if ( nodeName in currentNode.subNodes ) {
Y
yamahigashi 已提交
3838

M
Mr.doob 已提交
3839
					var tmp = currentNode.subNodes[ nodeName ];
Y
yamahigashi 已提交
3840

M
Mr.doob 已提交
3841 3842
					// console.log( "duped entry found\nkey: " + nodeName + "\nvalue: " + propValue );
					if ( this.isFlattenNode( currentNode.subNodes[ nodeName ] ) ) {
Y
yamahigashi 已提交
3843 3844


M
Mr.doob 已提交
3845
						if ( attrs.id === '' ) {
Y
yamahigashi 已提交
3846

M
Mr.doob 已提交
3847 3848
							currentNode.subNodes[ nodeName ] = [];
							currentNode.subNodes[ nodeName ].push( tmp );
Y
yamahigashi 已提交
3849

M
Mr.doob 已提交
3850
						} else {
Y
yamahigashi 已提交
3851

M
Mr.doob 已提交
3852 3853
							currentNode.subNodes[ nodeName ] = {};
							currentNode.subNodes[ nodeName ][ tmp.id ] = tmp;
Y
yamahigashi 已提交
3854

M
Mr.doob 已提交
3855
						}
Y
yamahigashi 已提交
3856

M
Mr.doob 已提交
3857
					}
Y
yamahigashi 已提交
3858

M
Mr.doob 已提交
3859
					if ( attrs.id === '' ) {
Y
yamahigashi 已提交
3860

M
Mr.doob 已提交
3861
						currentNode.subNodes[ nodeName ].push( node );
3862

M
Mr.doob 已提交
3863
					} else {
Y
yamahigashi 已提交
3864

M
Mr.doob 已提交
3865
						currentNode.subNodes[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
3866

M
Mr.doob 已提交
3867
					}
Y
yamahigashi 已提交
3868

M
Mr.doob 已提交
3869
				} else if ( typeof attrs.id === 'number' || attrs.id.match( /^\d+$/ ) ) {
Y
yamahigashi 已提交
3870

M
Mr.doob 已提交
3871 3872
					currentNode.subNodes[ nodeName ] = {};
					currentNode.subNodes[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
3873

M
Mr.doob 已提交
3874
				} else {
Y
yamahigashi 已提交
3875

M
Mr.doob 已提交
3876
					currentNode.subNodes[ nodeName ] = node;
Y
yamahigashi 已提交
3877

M
Mr.doob 已提交
3878
				}
K
Kyle Larson 已提交
3879

Y
yamahigashi 已提交
3880
			}
Y
yamahigashi 已提交
3881

M
Mr.doob 已提交
3882 3883 3884
			// for this		  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
			// NodeAttribute: 1001463072, "NodeAttribute::", "LimbNode" {
			if ( nodeAttrs ) {
Y
yamahigashi 已提交
3885

M
Mr.doob 已提交
3886 3887 3888
				node.id = attrs.id;
				node.attrName = attrs.name;
				node.attrType = attrs.type;
K
Kyle Larson 已提交
3889

M
Mr.doob 已提交
3890
			}
K
Kyle Larson 已提交
3891

M
Mr.doob 已提交
3892
			this.pushStack( node );
K
Kyle Larson 已提交
3893

M
Mr.doob 已提交
3894
		},
K
Kyle Larson 已提交
3895

M
Mr.doob 已提交
3896
		parseNodeAttr: function ( attrs ) {
K
Kyle Larson 已提交
3897

M
Mr.doob 已提交
3898
			var id = attrs[ 0 ];
K
Kyle Larson 已提交
3899

M
Mugen87 已提交
3900
			if ( attrs[ 0 ] !== '' ) {
Y
yamahigashi 已提交
3901

M
Mr.doob 已提交
3902
				id = parseInt( attrs[ 0 ] );
Y
yamahigashi 已提交
3903

M
Mr.doob 已提交
3904
				if ( isNaN( id ) ) {
Y
yamahigashi 已提交
3905

M
Mr.doob 已提交
3906 3907
					// PolygonVertexIndex: *16380 {
					id = attrs[ 0 ];
Y
yamahigashi 已提交
3908

M
Mr.doob 已提交
3909
				}
Y
yamahigashi 已提交
3910

M
Mr.doob 已提交
3911
			}
Y
yamahigashi 已提交
3912

M
Mr.doob 已提交
3913
			var name = '', type = '';
Y
yamahigashi 已提交
3914

M
Mr.doob 已提交
3915
			if ( attrs.length > 1 ) {
Y
yamahigashi 已提交
3916

M
Mr.doob 已提交
3917 3918
				name = attrs[ 1 ].replace( /^(\w+)::/, '' );
				type = attrs[ 2 ];
Y
yamahigashi 已提交
3919

M
Mr.doob 已提交
3920
			}
Y
yamahigashi 已提交
3921

M
Mr.doob 已提交
3922
			return { id: id, name: name, type: type };
Y
yamahigashi 已提交
3923

M
Mr.doob 已提交
3924
		},
Y
yamahigashi 已提交
3925

M
Mr.doob 已提交
3926
		parseNodeProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
3927

M
Mr.doob 已提交
3928 3929
			var currentNode = this.getCurrentNode();
			var parentName = currentNode.name;
Y
yamahigashi 已提交
3930

M
Mr.doob 已提交
3931
			// special case parent node's is like "Properties70"
M
Mugen87 已提交
3932
			// these children nodes must treat with careful
M
Mr.doob 已提交
3933
			if ( parentName !== undefined ) {
Y
yamahigashi 已提交
3934

M
Mr.doob 已提交
3935 3936
				var propMatch = parentName.match( /Properties(\d)+/ );
				if ( propMatch ) {
Y
yamahigashi 已提交
3937

M
Mr.doob 已提交
3938 3939
					this.parseNodeSpecialProperty( line, propName, propValue );
					return;
Y
yamahigashi 已提交
3940

M
Mr.doob 已提交
3941
				}
Y
yamahigashi 已提交
3942

M
Mr.doob 已提交
3943
			}
Y
yamahigashi 已提交
3944

M
Mr.doob 已提交
3945
			// special case Connections
M
Mugen87 已提交
3946
			if ( propName === 'C' ) {
Y
yamahigashi 已提交
3947

M
Mr.doob 已提交
3948 3949 3950
				var connProps = propValue.split( ',' ).slice( 1 );
				var from = parseInt( connProps[ 0 ] );
				var to = parseInt( connProps[ 1 ] );
Y
yamahigashi 已提交
3951

M
Mr.doob 已提交
3952
				var rest = propValue.split( ',' ).slice( 3 );
Y
yamahigashi 已提交
3953

M
Mr.doob 已提交
3954 3955 3956
				propName = 'connections';
				propValue = [ from, to ];
				append( propValue, rest );
Y
yamahigashi 已提交
3957

M
Mr.doob 已提交
3958
				if ( currentNode.properties[ propName ] === undefined ) {
Y
yamahigashi 已提交
3959

M
Mr.doob 已提交
3960
					currentNode.properties[ propName ] = [];
Y
yamahigashi 已提交
3961

M
Mr.doob 已提交
3962
				}
Y
yamahigashi 已提交
3963

M
Mr.doob 已提交
3964
			}
Y
yamahigashi 已提交
3965

M
Mr.doob 已提交
3966
			// special case Connections
M
Mugen87 已提交
3967
			if ( propName === 'Node' ) {
Y
yamahigashi 已提交
3968

M
Mr.doob 已提交
3969 3970 3971
				var id = parseInt( propValue );
				currentNode.properties.id = id;
				currentNode.id = id;
Y
yamahigashi 已提交
3972

M
Mr.doob 已提交
3973
			}
Y
yamahigashi 已提交
3974

M
Mr.doob 已提交
3975 3976
			// already exists in properties, then append this
			if ( propName in currentNode.properties ) {
Y
yamahigashi 已提交
3977

M
Mr.doob 已提交
3978 3979
				// console.log( "duped entry found\nkey: " + propName + "\nvalue: " + propValue );
				if ( Array.isArray( currentNode.properties[ propName ] ) ) {
Y
yamahigashi 已提交
3980

M
Mr.doob 已提交
3981
					currentNode.properties[ propName ].push( propValue );
Y
yamahigashi 已提交
3982

M
Mr.doob 已提交
3983
				} else {
Y
yamahigashi 已提交
3984

M
Mr.doob 已提交
3985
					currentNode.properties[ propName ] += propValue;
Y
yamahigashi 已提交
3986

M
Mr.doob 已提交
3987
				}
Y
yamahigashi 已提交
3988

M
Mr.doob 已提交
3989
			} else {
Y
yamahigashi 已提交
3990

M
Mr.doob 已提交
3991 3992
				// console.log( propName + ":  " + propValue );
				if ( Array.isArray( currentNode.properties[ propName ] ) ) {
Y
yamahigashi 已提交
3993

M
Mr.doob 已提交
3994
					currentNode.properties[ propName ].push( propValue );
Y
yamahigashi 已提交
3995

M
Mr.doob 已提交
3996
				} else {
Y
yamahigashi 已提交
3997

M
Mr.doob 已提交
3998
					currentNode.properties[ propName ] = propValue;
Y
yamahigashi 已提交
3999

M
Mr.doob 已提交
4000
				}
Y
yamahigashi 已提交
4001

M
Mr.doob 已提交
4002
			}
Y
yamahigashi 已提交
4003

M
Mr.doob 已提交
4004
			this.setCurrentProp( currentNode.properties, propName );
Y
yamahigashi 已提交
4005

M
Mr.doob 已提交
4006
		},
Y
yamahigashi 已提交
4007

M
Mr.doob 已提交
4008 4009
		// TODO:
		parseNodePropertyContinued: function ( line ) {
Y
yamahigashi 已提交
4010

M
Mr.doob 已提交
4011
			this.currentProp[ this.currentPropName ] += line;
Y
yamahigashi 已提交
4012

M
Mr.doob 已提交
4013
		},
Y
yamahigashi 已提交
4014

M
Mr.doob 已提交
4015
		parseNodeSpecialProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
4016

M
Mr.doob 已提交
4017 4018 4019 4020 4021
			// split this
			// P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1
			// into array like below
			// ["Lcl Scaling", "Lcl Scaling", "", "A", "1,1,1" ]
			var props = propValue.split( '",' );
Y
yamahigashi 已提交
4022

M
Mr.doob 已提交
4023
			for ( var i = 0, l = props.length; i < l; i ++ ) {
M
Mugen87 已提交
4024

M
Mr.doob 已提交
4025
				props[ i ] = props[ i ].trim().replace( /^\"/, '' ).replace( /\s/, '_' );
M
Mugen87 已提交
4026

Y
yamahigashi 已提交
4027 4028
			}

M
Mr.doob 已提交
4029 4030 4031 4032 4033
			var innerPropName = props[ 0 ];
			var innerPropType1 = props[ 1 ];
			var innerPropType2 = props[ 2 ];
			var innerPropFlag = props[ 3 ];
			var innerPropValue = props[ 4 ];
Y
yamahigashi 已提交
4034

M
Mr.doob 已提交
4035 4036 4037 4038 4039
			/*
			if ( innerPropValue === undefined ) {
				innerPropValue = props[3];
			}
			*/
Y
yamahigashi 已提交
4040

M
Mr.doob 已提交
4041 4042
			// cast value in its type
			switch ( innerPropType1 ) {
Y
yamahigashi 已提交
4043

M
Mugen87 已提交
4044
				case 'int':
M
Mr.doob 已提交
4045 4046
					innerPropValue = parseInt( innerPropValue );
					break;
Y
yamahigashi 已提交
4047

M
Mugen87 已提交
4048
				case 'double':
M
Mr.doob 已提交
4049 4050
					innerPropValue = parseFloat( innerPropValue );
					break;
Y
yamahigashi 已提交
4051

M
Mugen87 已提交
4052 4053
				case 'ColorRGB':
				case 'Vector3D':
M
Mr.doob 已提交
4054 4055
					innerPropValue = parseFloatArray( innerPropValue );
					break;
Y
yamahigashi 已提交
4056

M
Mr.doob 已提交
4057
			}
Y
yamahigashi 已提交
4058

M
Mr.doob 已提交
4059 4060
			// CAUTION: these props must append to parent's parent
			this.getPrevNode().properties[ innerPropName ] = {
Y
yamahigashi 已提交
4061

M
Mr.doob 已提交
4062 4063 4064 4065
				'type': innerPropType1,
				'type2': innerPropType2,
				'flag': innerPropFlag,
				'value': innerPropValue
Y
yamahigashi 已提交
4066

M
Mr.doob 已提交
4067
			};
Y
yamahigashi 已提交
4068

M
Mr.doob 已提交
4069
			this.setCurrentProp( this.getPrevNode().properties, innerPropName );
Y
yamahigashi 已提交
4070

M
Mr.doob 已提交
4071
		},
4072

M
Mr.doob 已提交
4073
		nodeEnd: function () {
4074

M
Mr.doob 已提交
4075
			this.popStack();
4076

M
Mr.doob 已提交
4077
		},
Y
yamahigashi 已提交
4078

M
Mr.doob 已提交
4079 4080 4081
		/* ---------------------------------------------------------------- */
		/*		util													  */
		isFlattenNode: function ( node ) {
Y
yamahigashi 已提交
4082

M
Mr.doob 已提交
4083
			return ( 'subNodes' in node && 'properties' in node ) ? true : false;
Y
yamahigashi 已提交
4084

M
Mr.doob 已提交
4085
		}
Y
yamahigashi 已提交
4086

M
Mr.doob 已提交
4087
	} );
Y
yamahigashi 已提交
4088

M
Mr.doob 已提交
4089 4090 4091 4092
	// Binary format specification:
	//   https://code.blender.org/2013/08/fbx-binary-file-format-specification/
	//   https://wiki.rogiken.org/specifications/file-format/fbx/ (more detail but Japanese)
	function BinaryParser() {}
Y
yamahigashi 已提交
4093

M
Mr.doob 已提交
4094
	Object.assign( BinaryParser.prototype, {
Y
yamahigashi 已提交
4095

M
Mr.doob 已提交
4096 4097 4098 4099 4100 4101
		/**
		 * Parses binary data and builds FBXTree as much compatible as possible with the one built by TextParser.
		 * @param {ArrayBuffer} buffer
		 * @returns {THREE.FBXTree}
		 */
		parse: function ( buffer ) {
Y
yamahigashi 已提交
4102

M
Mr.doob 已提交
4103 4104
			var reader = new BinaryReader( buffer );
			reader.skip( 23 ); // skip magic 23 bytes
Y
yamahigashi 已提交
4105

M
Mr.doob 已提交
4106
			var version = reader.getUint32();
Y
yamahigashi 已提交
4107

M
Mugen87 已提交
4108
			console.log( 'THREE.FBXLoader: FBX binary version: ' + version );
Y
yamahigashi 已提交
4109

M
Mr.doob 已提交
4110
			var allNodes = new FBXTree();
Y
yamahigashi 已提交
4111

M
Mr.doob 已提交
4112
			while ( ! this.endOfContent( reader ) ) {
Y
yamahigashi 已提交
4113

M
Mr.doob 已提交
4114 4115
				var node = this.parseNode( reader, version );
				if ( node !== null ) allNodes.add( node.name, node );
Y
yamahigashi 已提交
4116

M
Mr.doob 已提交
4117
			}
4118

M
Mr.doob 已提交
4119
			return allNodes;
Y
yamahigashi 已提交
4120

M
Mr.doob 已提交
4121
		},
Y
yamahigashi 已提交
4122

M
Mr.doob 已提交
4123 4124 4125 4126 4127
		/**
		 * Checks if reader has reached the end of content.
		 * @param {BinaryReader} reader
		 * @returns {boolean}
		 */
M
Mugen87 已提交
4128
		endOfContent: function ( reader ) {
M
Mr.doob 已提交
4129 4130 4131

			// footer size: 160bytes + 16-byte alignment padding
			// - 16bytes: magic
4132
			// - padding til 16-byte alignment (at least 1byte?)
4133
			//   (seems like some exporters embed fixed 15 or 16bytes?)
M
Mr.doob 已提交
4134 4135 4136 4137 4138 4139
			// - 4bytes: magic
			// - 4bytes: version
			// - 120bytes: zero
			// - 16bytes: magic
			if ( reader.size() % 16 === 0 ) {

M
Mugen87 已提交
4140
				return ( ( reader.getOffset() + 160 + 16 ) & ~ 0xf ) >= reader.size();
Y
yamahigashi 已提交
4141

M
Mr.doob 已提交
4142
			} else {
Y
yamahigashi 已提交
4143

4144
				return reader.getOffset() + 160 + 16 >= reader.size();
Y
yamahigashi 已提交
4145

M
Mr.doob 已提交
4146
			}
Y
yamahigashi 已提交
4147

M
Mr.doob 已提交
4148
		},
Y
yamahigashi 已提交
4149

M
Mr.doob 已提交
4150 4151 4152 4153 4154 4155 4156 4157
		/**
		 * Parses Node as much compatible as possible with the one parsed by TextParser
		 * TODO: could be optimized more?
		 * @param {BinaryReader} reader
		 * @param {number} version
		 * @returns {Object} - Returns an Object as node, or null if NULL-record.
		 */
		parseNode: function ( reader, version ) {
Y
yamahigashi 已提交
4158

M
Mr.doob 已提交
4159 4160 4161
			// The first three data sizes depends on version.
			var endOffset = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
			var numProperties = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
M
Mr.doob 已提交
4162
			var propertyListLen = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
M
Mr.doob 已提交
4163 4164
			var nameLen = reader.getUint8();
			var name = reader.getString( nameLen );
Y
yamahigashi 已提交
4165

M
Mr.doob 已提交
4166 4167
			// Regards this node as NULL-record if endOffset is zero
			if ( endOffset === 0 ) return null;
Y
yamahigashi 已提交
4168

M
Mr.doob 已提交
4169
			var propertyList = [];
Y
yamahigashi 已提交
4170

M
Mr.doob 已提交
4171
			for ( var i = 0; i < numProperties; i ++ ) {
Y
yamahigashi 已提交
4172

M
Mr.doob 已提交
4173
				propertyList.push( this.parseProperty( reader ) );
Y
yamahigashi 已提交
4174

M
Mr.doob 已提交
4175
			}
Y
yamahigashi 已提交
4176

M
Mr.doob 已提交
4177 4178 4179 4180
			// Regards the first three elements in propertyList as id, attrName, and attrType
			var id = propertyList.length > 0 ? propertyList[ 0 ] : '';
			var attrName = propertyList.length > 1 ? propertyList[ 1 ] : '';
			var attrType = propertyList.length > 2 ? propertyList[ 2 ] : '';
Y
yamahigashi 已提交
4181

M
Mr.doob 已提交
4182 4183
			var subNodes = {};
			var properties = {};
Y
yamahigashi 已提交
4184

M
Mr.doob 已提交
4185
			var isSingleProperty = false;
Y
yamahigashi 已提交
4186

M
Mr.doob 已提交
4187 4188 4189
			// if this node represents just a single property
			// like (name, 0) set or (name2, [0, 1, 2]) set of {name: 0, name2: [0, 1, 2]}
			if ( numProperties === 1 && reader.getOffset() === endOffset ) {
Y
yamahigashi 已提交
4190

M
Mr.doob 已提交
4191
				isSingleProperty = true;
Y
yamahigashi 已提交
4192

M
Mr.doob 已提交
4193
			}
Y
yamahigashi 已提交
4194

M
Mr.doob 已提交
4195
			while ( endOffset > reader.getOffset() ) {
Y
yamahigashi 已提交
4196

M
Mr.doob 已提交
4197
				var node = this.parseNode( reader, version );
Y
yamahigashi 已提交
4198

M
Mr.doob 已提交
4199
				if ( node === null ) continue;
Y
yamahigashi 已提交
4200

M
Mr.doob 已提交
4201 4202
				// special case: child node is single property
				if ( node.singleProperty === true ) {
Y
yamahigashi 已提交
4203

M
Mr.doob 已提交
4204
					var value = node.propertyList[ 0 ];
Y
yamahigashi 已提交
4205

M
Mr.doob 已提交
4206
					if ( Array.isArray( value ) ) {
Y
yamahigashi 已提交
4207

M
Mr.doob 已提交
4208 4209 4210 4211 4212
						// node represents
						//	Vertices: *3 {
						//		a: 0.01, 0.02, 0.03
						//	}
						// of text format here.
Y
yamahigashi 已提交
4213

M
Mr.doob 已提交
4214 4215
						node.properties[ node.name ] = node.propertyList[ 0 ];
						subNodes[ node.name ] = node;
Y
yamahigashi 已提交
4216

M
Mr.doob 已提交
4217 4218 4219
						// Later phase expects single property array is in node.properties.a as String.
						// TODO: optimize
						node.properties.a = value.toString();
Y
yamahigashi 已提交
4220

M
Mr.doob 已提交
4221
					} else {
Y
yamahigashi 已提交
4222

M
Mr.doob 已提交
4223 4224 4225
						// node represents
						// 	Version: 100
						// of text format here.
Y
yamahigashi 已提交
4226

M
Mr.doob 已提交
4227
						properties[ node.name ] = value;
Y
yamahigashi 已提交
4228

M
Mr.doob 已提交
4229
					}
Y
yamahigashi 已提交
4230

M
Mr.doob 已提交
4231
					continue;
Y
yamahigashi 已提交
4232

M
Mr.doob 已提交
4233
				}
Y
yamahigashi 已提交
4234

M
Mr.doob 已提交
4235 4236
				// special case: connections
				if ( name === 'Connections' && node.name === 'C' ) {
Y
yamahigashi 已提交
4237

M
Mr.doob 已提交
4238
					var array = [];
Y
yamahigashi 已提交
4239

M
Mr.doob 已提交
4240 4241 4242
					// node.propertyList would be like
					// ["OO", 111264976, 144038752, "d|x"] (?, from, to, additional values)
					for ( var i = 1, il = node.propertyList.length; i < il; i ++ ) {
Y
yamahigashi 已提交
4243

M
Mr.doob 已提交
4244
						array[ i - 1 ] = node.propertyList[ i ];
Y
yamahigashi 已提交
4245

M
Mr.doob 已提交
4246
					}
Y
yamahigashi 已提交
4247

M
Mr.doob 已提交
4248
					if ( properties.connections === undefined ) {
Y
yamahigashi 已提交
4249

M
Mr.doob 已提交
4250
						properties.connections = [];
Y
yamahigashi 已提交
4251

M
Mr.doob 已提交
4252
					}
Y
yamahigashi 已提交
4253

M
Mr.doob 已提交
4254
					properties.connections.push( array );
Y
yamahigashi 已提交
4255

M
Mr.doob 已提交
4256
					continue;
Y
yamahigashi 已提交
4257

M
Mr.doob 已提交
4258
				}
Y
yamahigashi 已提交
4259

M
Mr.doob 已提交
4260 4261
				// special case: child node is Properties\d+
				if ( node.name.match( /^Properties\d+$/ ) ) {
Y
yamahigashi 已提交
4262

M
Mr.doob 已提交
4263
					// move child node's properties to this node.
Y
yamahigashi 已提交
4264

M
Mr.doob 已提交
4265
					var keys = Object.keys( node.properties );
Y
yamahigashi 已提交
4266

M
Mr.doob 已提交
4267
					for ( var i = 0, il = keys.length; i < il; i ++ ) {
Y
yamahigashi 已提交
4268

M
Mr.doob 已提交
4269 4270
						var key = keys[ i ];
						properties[ key ] = node.properties[ key ];
Y
yamahigashi 已提交
4271

M
Mr.doob 已提交
4272
					}
Y
yamahigashi 已提交
4273

M
Mr.doob 已提交
4274
					continue;
Y
yamahigashi 已提交
4275

M
Mr.doob 已提交
4276
				}
Y
yamahigashi 已提交
4277

M
Mr.doob 已提交
4278 4279
				// special case: properties
				if ( name.match( /^Properties\d+$/ ) && node.name === 'P' ) {
Y
yamahigashi 已提交
4280

M
Mr.doob 已提交
4281 4282 4283 4284 4285
					var innerPropName = node.propertyList[ 0 ];
					var innerPropType1 = node.propertyList[ 1 ];
					var innerPropType2 = node.propertyList[ 2 ];
					var innerPropFlag = node.propertyList[ 3 ];
					var innerPropValue;
Y
yamahigashi 已提交
4286

M
Mr.doob 已提交
4287 4288
					if ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );
					if ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );
Y
yamahigashi 已提交
4289

M
Mr.doob 已提交
4290 4291
					if ( innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' ||
						 innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
Y
yamahigashi 已提交
4292

M
Mr.doob 已提交
4293 4294 4295 4296 4297
						innerPropValue = [
							node.propertyList[ 4 ],
							node.propertyList[ 5 ],
							node.propertyList[ 6 ]
						];
Y
yamahigashi 已提交
4298

M
Mr.doob 已提交
4299
					} else {
Y
yamahigashi 已提交
4300

M
Mr.doob 已提交
4301
						innerPropValue = node.propertyList[ 4 ];
Y
yamahigashi 已提交
4302

M
Mr.doob 已提交
4303
					}
Y
yamahigashi 已提交
4304

M
Mr.doob 已提交
4305
					if ( innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
Y
yamahigashi 已提交
4306

M
Mr.doob 已提交
4307
						innerPropValue = innerPropValue.toString();
Y
yamahigashi 已提交
4308

M
Mr.doob 已提交
4309
					}
Y
yamahigashi 已提交
4310

M
Mr.doob 已提交
4311 4312
					// this will be copied to parent. see above.
					properties[ innerPropName ] = {
Y
yamahigashi 已提交
4313

M
Mr.doob 已提交
4314 4315 4316 4317
						'type': innerPropType1,
						'type2': innerPropType2,
						'flag': innerPropFlag,
						'value': innerPropValue
Y
yamahigashi 已提交
4318

M
Mr.doob 已提交
4319
					};
Y
yamahigashi 已提交
4320

M
Mr.doob 已提交
4321
					continue;
Y
yamahigashi 已提交
4322

M
Mr.doob 已提交
4323
				}
Y
yamahigashi 已提交
4324

M
Mr.doob 已提交
4325 4326 4327
				// standard case
				// follows TextParser's manner.
				if ( subNodes[ node.name ] === undefined ) {
Y
yamahigashi 已提交
4328

M
Mr.doob 已提交
4329
					if ( typeof node.id === 'number' ) {
K
Kyle Larson 已提交
4330

M
Mr.doob 已提交
4331 4332
						subNodes[ node.name ] = {};
						subNodes[ node.name ][ node.id ] = node;
Y
yamahigashi 已提交
4333

M
Mr.doob 已提交
4334
					} else {
Y
yamahigashi 已提交
4335

M
Mr.doob 已提交
4336
						subNodes[ node.name ] = node;
Y
yamahigashi 已提交
4337

M
Mr.doob 已提交
4338
					}
Y
yamahigashi 已提交
4339

M
Mr.doob 已提交
4340
				} else {
Y
yamahigashi 已提交
4341

M
Mr.doob 已提交
4342
					if ( node.id === '' ) {
Y
yamahigashi 已提交
4343

M
Mr.doob 已提交
4344
						if ( ! Array.isArray( subNodes[ node.name ] ) ) {
Y
yamahigashi 已提交
4345

M
Mr.doob 已提交
4346
							subNodes[ node.name ] = [ subNodes[ node.name ] ];
Y
yamahigashi 已提交
4347

M
Mr.doob 已提交
4348
						}
Y
yamahigashi 已提交
4349

M
Mr.doob 已提交
4350
						subNodes[ node.name ].push( node );
Y
yamahigashi 已提交
4351

M
Mr.doob 已提交
4352
					} else {
Y
yamahigashi 已提交
4353

M
Mr.doob 已提交
4354
						if ( subNodes[ node.name ][ node.id ] === undefined ) {
Y
yamahigashi 已提交
4355

M
Mr.doob 已提交
4356
							subNodes[ node.name ][ node.id ] = node;
Y
yamahigashi 已提交
4357

M
Mr.doob 已提交
4358
						} else {
Y
yamahigashi 已提交
4359

M
Mr.doob 已提交
4360
							// conflict id. irregular?
Y
yamahigashi 已提交
4361

M
Mr.doob 已提交
4362
							if ( ! Array.isArray( subNodes[ node.name ][ node.id ] ) ) {
Y
yamahigashi 已提交
4363

M
Mr.doob 已提交
4364
								subNodes[ node.name ][ node.id ] = [ subNodes[ node.name ][ node.id ] ];
Y
yamahigashi 已提交
4365

M
Mr.doob 已提交
4366
							}
Y
yamahigashi 已提交
4367

M
Mr.doob 已提交
4368
							subNodes[ node.name ][ node.id ].push( node );
K
Kyle Larson 已提交
4369

M
Mr.doob 已提交
4370
						}
K
Kyle Larson 已提交
4371

M
Mr.doob 已提交
4372
					}
K
Kyle Larson 已提交
4373

M
Mr.doob 已提交
4374
				}
K
Kyle Larson 已提交
4375

M
Mr.doob 已提交
4376
			}
K
Kyle Larson 已提交
4377

M
Mr.doob 已提交
4378
			return {
K
Kyle Larson 已提交
4379

M
Mr.doob 已提交
4380 4381 4382 4383 4384 4385 4386 4387
				singleProperty: isSingleProperty,
				id: id,
				attrName: attrName,
				attrType: attrType,
				name: name,
				properties: properties,
				propertyList: propertyList, // raw property list, would be used by parent
				subNodes: subNodes
K
Kyle Larson 已提交
4388

M
Mr.doob 已提交
4389
			};
K
Kyle Larson 已提交
4390

M
Mr.doob 已提交
4391
		},
K
Kyle Larson 已提交
4392

M
Mr.doob 已提交
4393
		parseProperty: function ( reader ) {
K
Kyle Larson 已提交
4394

M
Mr.doob 已提交
4395
			var type = reader.getChar();
K
Kyle Larson 已提交
4396

M
Mr.doob 已提交
4397
			switch ( type ) {
K
Kyle Larson 已提交
4398

M
Mr.doob 已提交
4399 4400
				case 'F':
					return reader.getFloat32();
K
Kyle Larson 已提交
4401

M
Mr.doob 已提交
4402 4403
				case 'D':
					return reader.getFloat64();
K
Kyle Larson 已提交
4404

M
Mr.doob 已提交
4405 4406
				case 'L':
					return reader.getInt64();
K
Kyle Larson 已提交
4407

M
Mr.doob 已提交
4408 4409
				case 'I':
					return reader.getInt32();
K
Kyle Larson 已提交
4410

M
Mr.doob 已提交
4411 4412
				case 'Y':
					return reader.getInt16();
K
Kyle Larson 已提交
4413

M
Mr.doob 已提交
4414 4415
				case 'C':
					return reader.getBoolean();
K
Kyle Larson 已提交
4416

M
Mr.doob 已提交
4417 4418 4419 4420 4421
				case 'f':
				case 'd':
				case 'l':
				case 'i':
				case 'b':
K
Kyle Larson 已提交
4422

M
Mr.doob 已提交
4423 4424 4425
					var arrayLength = reader.getUint32();
					var encoding = reader.getUint32(); // 0: non-compressed, 1: compressed
					var compressedLength = reader.getUint32();
K
Kyle Larson 已提交
4426

M
Mr.doob 已提交
4427
					if ( encoding === 0 ) {
K
Kyle Larson 已提交
4428

M
Mr.doob 已提交
4429
						switch ( type ) {
K
Kyle Larson 已提交
4430

M
Mr.doob 已提交
4431 4432
							case 'f':
								return reader.getFloat32Array( arrayLength );
K
Kyle Larson 已提交
4433

M
Mr.doob 已提交
4434 4435
							case 'd':
								return reader.getFloat64Array( arrayLength );
K
Kyle Larson 已提交
4436

M
Mr.doob 已提交
4437 4438
							case 'l':
								return reader.getInt64Array( arrayLength );
K
Kyle Larson 已提交
4439

M
Mr.doob 已提交
4440 4441
							case 'i':
								return reader.getInt32Array( arrayLength );
Y
yamahigashi 已提交
4442

M
Mr.doob 已提交
4443 4444
							case 'b':
								return reader.getBooleanArray( arrayLength );
Y
yamahigashi 已提交
4445

M
Mr.doob 已提交
4446
						}
Y
yamahigashi 已提交
4447

M
Mr.doob 已提交
4448
					}
Y
yamahigashi 已提交
4449

M
Mr.doob 已提交
4450
					if ( window.Zlib === undefined ) {
Y
yamahigashi 已提交
4451

M
Mugen87 已提交
4452
						throw new Error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
Y
yamahigashi 已提交
4453

M
Mr.doob 已提交
4454
					}
Y
yamahigashi 已提交
4455

M
Mugen87 已提交
4456
					var inflate = new Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) ); // eslint-disable-line no-undef
M
Mr.doob 已提交
4457
					var reader2 = new BinaryReader( inflate.decompress().buffer );
Y
yamahigashi 已提交
4458

M
Mr.doob 已提交
4459
					switch ( type ) {
Y
yamahigashi 已提交
4460

M
Mr.doob 已提交
4461 4462
						case 'f':
							return reader2.getFloat32Array( arrayLength );
Y
yamahigashi 已提交
4463

M
Mr.doob 已提交
4464 4465
						case 'd':
							return reader2.getFloat64Array( arrayLength );
Y
yamahigashi 已提交
4466

M
Mr.doob 已提交
4467 4468
						case 'l':
							return reader2.getInt64Array( arrayLength );
Y
yamahigashi 已提交
4469

M
Mr.doob 已提交
4470 4471
						case 'i':
							return reader2.getInt32Array( arrayLength );
Y
yamahigashi 已提交
4472

M
Mr.doob 已提交
4473 4474
						case 'b':
							return reader2.getBooleanArray( arrayLength );
Y
yamahigashi 已提交
4475

M
Mr.doob 已提交
4476
					}
Y
yamahigashi 已提交
4477

M
Mr.doob 已提交
4478 4479 4480
				case 'S':
					var length = reader.getUint32();
					return reader.getString( length );
Y
yamahigashi 已提交
4481

M
Mr.doob 已提交
4482 4483 4484
				case 'R':
					var length = reader.getUint32();
					return reader.getArrayBuffer( length );
Y
yamahigashi 已提交
4485

M
Mr.doob 已提交
4486
				default:
M
Mugen87 已提交
4487
					throw new Error( 'THREE.FBXLoader: Unknown property type ' + type );
Y
yamahigashi 已提交
4488

M
Mr.doob 已提交
4489
			}
Y
yamahigashi 已提交
4490

M
Mr.doob 已提交
4491
		}
Y
yamahigashi 已提交
4492

M
Mr.doob 已提交
4493
	} );
Y
yamahigashi 已提交
4494 4495


M
Mr.doob 已提交
4496
	function BinaryReader( buffer, littleEndian ) {
Y
yamahigashi 已提交
4497

M
Mr.doob 已提交
4498 4499 4500
		this.dv = new DataView( buffer );
		this.offset = 0;
		this.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;
Y
yamahigashi 已提交
4501

M
Mr.doob 已提交
4502
	}
Y
yamahigashi 已提交
4503

M
Mr.doob 已提交
4504
	Object.assign( BinaryReader.prototype, {
Y
yamahigashi 已提交
4505

M
Mr.doob 已提交
4506
		getOffset: function () {
Y
yamahigashi 已提交
4507

M
Mr.doob 已提交
4508
			return this.offset;
Y
yamahigashi 已提交
4509

M
Mr.doob 已提交
4510
		},
Y
yamahigashi 已提交
4511

M
Mr.doob 已提交
4512
		size: function () {
Y
yamahigashi 已提交
4513

M
Mr.doob 已提交
4514
			return this.dv.buffer.byteLength;
Y
yamahigashi 已提交
4515

M
Mr.doob 已提交
4516
		},
Y
yamahigashi 已提交
4517

M
Mr.doob 已提交
4518
		skip: function ( length ) {
Y
yamahigashi 已提交
4519

M
Mr.doob 已提交
4520
			this.offset += length;
Y
yamahigashi 已提交
4521

M
Mr.doob 已提交
4522
		},
Y
yamahigashi 已提交
4523

M
Mr.doob 已提交
4524 4525 4526 4527
		// seems like true/false representation depends on exporter.
		//   true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)
		// then sees LSB.
		getBoolean: function () {
Y
yamahigashi 已提交
4528

M
Mr.doob 已提交
4529
			return ( this.getUint8() & 1 ) === 1;
Y
yamahigashi 已提交
4530

M
Mr.doob 已提交
4531
		},
Y
yamahigashi 已提交
4532

M
Mr.doob 已提交
4533
		getBooleanArray: function ( size ) {
Y
yamahigashi 已提交
4534

M
Mr.doob 已提交
4535
			var a = [];
Y
yamahigashi 已提交
4536

M
Mr.doob 已提交
4537
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4538

M
Mr.doob 已提交
4539
				a.push( this.getBoolean() );
Y
yamahigashi 已提交
4540 4541 4542

			}

M
Mr.doob 已提交
4543
			return a;
Y
yamahigashi 已提交
4544

M
Mr.doob 已提交
4545
		},
Y
yamahigashi 已提交
4546

M
Mr.doob 已提交
4547
		getInt8: function () {
Y
yamahigashi 已提交
4548

M
Mr.doob 已提交
4549 4550 4551
			var value = this.dv.getInt8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
4552

M
Mr.doob 已提交
4553
		},
Y
yamahigashi 已提交
4554

M
Mr.doob 已提交
4555
		getInt8Array: function ( size ) {
Y
yamahigashi 已提交
4556

M
Mr.doob 已提交
4557
			var a = [];
Y
yamahigashi 已提交
4558

M
Mr.doob 已提交
4559
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4560

M
Mr.doob 已提交
4561
				a.push( this.getInt8() );
Y
yamahigashi 已提交
4562

M
Mr.doob 已提交
4563
			}
Y
yamahigashi 已提交
4564

M
Mr.doob 已提交
4565
			return a;
Y
yamahigashi 已提交
4566

M
Mr.doob 已提交
4567
		},
Y
yamahigashi 已提交
4568

M
Mr.doob 已提交
4569
		getUint8: function () {
Y
yamahigashi 已提交
4570

M
Mr.doob 已提交
4571 4572 4573
			var value = this.dv.getUint8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
4574

M
Mr.doob 已提交
4575
		},
Y
yamahigashi 已提交
4576

M
Mr.doob 已提交
4577
		getUint8Array: function ( size ) {
Y
yamahigashi 已提交
4578

M
Mr.doob 已提交
4579
			var a = [];
Y
yamahigashi 已提交
4580

M
Mr.doob 已提交
4581
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4582

M
Mr.doob 已提交
4583
				a.push( this.getUint8() );
Y
yamahigashi 已提交
4584 4585 4586

			}

M
Mr.doob 已提交
4587
			return a;
Y
yamahigashi 已提交
4588

M
Mr.doob 已提交
4589
		},
Y
yamahigashi 已提交
4590

M
Mr.doob 已提交
4591
		getInt16: function () {
Y
yamahigashi 已提交
4592

M
Mr.doob 已提交
4593 4594 4595
			var value = this.dv.getInt16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
4596

M
Mr.doob 已提交
4597
		},
Y
yamahigashi 已提交
4598

M
Mr.doob 已提交
4599
		getInt16Array: function ( size ) {
Y
yamahigashi 已提交
4600

M
Mr.doob 已提交
4601
			var a = [];
Y
yamahigashi 已提交
4602

M
Mr.doob 已提交
4603
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4604

M
Mr.doob 已提交
4605
				a.push( this.getInt16() );
Y
yamahigashi 已提交
4606

M
Mr.doob 已提交
4607
			}
Y
yamahigashi 已提交
4608

M
Mr.doob 已提交
4609
			return a;
4610

M
Mr.doob 已提交
4611
		},
4612

M
Mr.doob 已提交
4613
		getUint16: function () {
Y
yamahigashi 已提交
4614

M
Mr.doob 已提交
4615 4616 4617
			var value = this.dv.getUint16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
4618

M
Mr.doob 已提交
4619
		},
Y
yamahigashi 已提交
4620

M
Mr.doob 已提交
4621
		getUint16Array: function ( size ) {
Y
yamahigashi 已提交
4622

M
Mr.doob 已提交
4623
			var a = [];
Y
yamahigashi 已提交
4624

M
Mr.doob 已提交
4625
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4626

M
Mr.doob 已提交
4627
				a.push( this.getUint16() );
Y
yamahigashi 已提交
4628 4629 4630

			}

M
Mr.doob 已提交
4631
			return a;
Y
yamahigashi 已提交
4632

M
Mr.doob 已提交
4633
		},
4634

M
Mr.doob 已提交
4635
		getInt32: function () {
4636

M
Mr.doob 已提交
4637 4638 4639
			var value = this.dv.getInt32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
4640

M
Mr.doob 已提交
4641
		},
4642

M
Mr.doob 已提交
4643
		getInt32Array: function ( size ) {
4644

M
Mr.doob 已提交
4645
			var a = [];
4646

M
Mr.doob 已提交
4647
			for ( var i = 0; i < size; i ++ ) {
4648

M
Mr.doob 已提交
4649
				a.push( this.getInt32() );
4650 4651 4652

			}

M
Mr.doob 已提交
4653
			return a;
4654

M
Mr.doob 已提交
4655
		},
4656

M
Mr.doob 已提交
4657
		getUint32: function () {
4658

M
Mr.doob 已提交
4659 4660 4661 4662 4663
			var value = this.dv.getUint32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;

		},
4664

M
Mr.doob 已提交
4665
		getUint32Array: function ( size ) {
4666

M
Mr.doob 已提交
4667
			var a = [];
4668

M
Mr.doob 已提交
4669
			for ( var i = 0; i < size; i ++ ) {
4670

M
Mr.doob 已提交
4671
				a.push( this.getUint32() );
4672

M
Mr.doob 已提交
4673
			}
4674

M
Mr.doob 已提交
4675
			return a;
4676

M
Mr.doob 已提交
4677
		},
4678

M
Mr.doob 已提交
4679 4680 4681 4682 4683 4684
		// JavaScript doesn't support 64-bit integer so attempting to calculate by ourselves.
		// 1 << 32 will return 1 so using multiply operation instead here.
		// There'd be a possibility that this method returns wrong value if the value
		// is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.
		// TODO: safely handle 64-bit integer
		getInt64: function () {
4685

M
Mr.doob 已提交
4686
			var low, high;
4687

M
Mr.doob 已提交
4688
			if ( this.littleEndian ) {
4689

M
Mr.doob 已提交
4690 4691
				low = this.getUint32();
				high = this.getUint32();
4692

M
Mr.doob 已提交
4693
			} else {
4694

M
Mr.doob 已提交
4695 4696
				high = this.getUint32();
				low = this.getUint32();
4697

M
Mr.doob 已提交
4698
			}
4699

M
Mr.doob 已提交
4700 4701
			// calculate negative value
			if ( high & 0x80000000 ) {
4702

M
Mugen87 已提交
4703 4704
				high = ~ high & 0xFFFFFFFF;
				low = ~ low & 0xFFFFFFFF;
4705

M
Mr.doob 已提交
4706
				if ( low === 0xFFFFFFFF ) high = ( high + 1 ) & 0xFFFFFFFF;
4707

M
Mr.doob 已提交
4708
				low = ( low + 1 ) & 0xFFFFFFFF;
4709

M
Mr.doob 已提交
4710
				return - ( high * 0x100000000 + low );
4711

M
Mr.doob 已提交
4712
			}
4713

M
Mr.doob 已提交
4714
			return high * 0x100000000 + low;
4715

M
Mr.doob 已提交
4716
		},
4717

M
Mr.doob 已提交
4718
		getInt64Array: function ( size ) {
4719

M
Mr.doob 已提交
4720
			var a = [];
4721

M
Mr.doob 已提交
4722
			for ( var i = 0; i < size; i ++ ) {
4723

M
Mr.doob 已提交
4724
				a.push( this.getInt64() );
4725 4726 4727

			}

M
Mr.doob 已提交
4728 4729 4730
			return a;

		},
4731

M
Mr.doob 已提交
4732 4733
		// Note: see getInt64() comment
		getUint64: function () {
4734

M
Mr.doob 已提交
4735
			var low, high;
4736

M
Mr.doob 已提交
4737 4738 4739 4740 4741 4742 4743 4744 4745
			if ( this.littleEndian ) {

				low = this.getUint32();
				high = this.getUint32();

			} else {

				high = this.getUint32();
				low = this.getUint32();
4746 4747

			}
4748

M
Mr.doob 已提交
4749
			return high * 0x100000000 + low;
4750

M
Mr.doob 已提交
4751
		},
Y
yamahigashi 已提交
4752

M
Mr.doob 已提交
4753
		getUint64Array: function ( size ) {
Y
yamahigashi 已提交
4754

M
Mr.doob 已提交
4755
			var a = [];
Y
yamahigashi 已提交
4756

M
Mr.doob 已提交
4757
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4758

M
Mr.doob 已提交
4759
				a.push( this.getUint64() );
Y
yamahigashi 已提交
4760

M
Mr.doob 已提交
4761
			}
Y
yamahigashi 已提交
4762

M
Mr.doob 已提交
4763
			return a;
Y
yamahigashi 已提交
4764

M
Mr.doob 已提交
4765
		},
K
Kyle Larson 已提交
4766

M
Mr.doob 已提交
4767
		getFloat32: function () {
Y
yamahigashi 已提交
4768

M
Mr.doob 已提交
4769 4770 4771
			var value = this.dv.getFloat32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
Y
yamahigashi 已提交
4772

M
Mr.doob 已提交
4773
		},
Y
yamahigashi 已提交
4774

M
Mr.doob 已提交
4775
		getFloat32Array: function ( size ) {
Y
yamahigashi 已提交
4776

M
Mr.doob 已提交
4777
			var a = [];
Y
yamahigashi 已提交
4778

M
Mr.doob 已提交
4779
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4780

M
Mr.doob 已提交
4781
				a.push( this.getFloat32() );
Y
yamahigashi 已提交
4782 4783 4784

			}

M
Mr.doob 已提交
4785
			return a;
Y
yamahigashi 已提交
4786

M
Mr.doob 已提交
4787
		},
Y
yamahigashi 已提交
4788

M
Mr.doob 已提交
4789
		getFloat64: function () {
Y
yamahigashi 已提交
4790

M
Mr.doob 已提交
4791 4792 4793
			var value = this.dv.getFloat64( this.offset, this.littleEndian );
			this.offset += 8;
			return value;
Y
yamahigashi 已提交
4794

M
Mr.doob 已提交
4795
		},
Y
yamahigashi 已提交
4796

M
Mr.doob 已提交
4797
		getFloat64Array: function ( size ) {
Y
yamahigashi 已提交
4798

M
Mr.doob 已提交
4799
			var a = [];
Y
yamahigashi 已提交
4800

M
Mr.doob 已提交
4801
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4802

M
Mr.doob 已提交
4803
				a.push( this.getFloat64() );
Y
yamahigashi 已提交
4804

M
Mr.doob 已提交
4805
			}
Y
yamahigashi 已提交
4806

M
Mr.doob 已提交
4807
			return a;
Y
yamahigashi 已提交
4808

M
Mr.doob 已提交
4809
		},
Y
yamahigashi 已提交
4810

M
Mr.doob 已提交
4811
		getArrayBuffer: function ( size ) {
Y
yamahigashi 已提交
4812

M
Mr.doob 已提交
4813 4814 4815
			var value = this.dv.buffer.slice( this.offset, this.offset + size );
			this.offset += size;
			return value;
Y
yamahigashi 已提交
4816

M
Mr.doob 已提交
4817
		},
Y
yamahigashi 已提交
4818

M
Mr.doob 已提交
4819
		getChar: function () {
Y
yamahigashi 已提交
4820

M
Mr.doob 已提交
4821
			return String.fromCharCode( this.getUint8() );
Y
yamahigashi 已提交
4822

M
Mr.doob 已提交
4823
		},
Y
yamahigashi 已提交
4824

M
Mr.doob 已提交
4825
		getString: function ( size ) {
Y
yamahigashi 已提交
4826

M
Mr.doob 已提交
4827
			var s = '';
Y
yamahigashi 已提交
4828

M
Mr.doob 已提交
4829
			while ( size > 0 ) {
Y
yamahigashi 已提交
4830

M
Mr.doob 已提交
4831
				var value = this.getUint8();
M
Mugen87 已提交
4832
				size --;
Y
yamahigashi 已提交
4833

M
Mr.doob 已提交
4834
				if ( value === 0 ) break;
Y
yamahigashi 已提交
4835

M
Mr.doob 已提交
4836
				s += String.fromCharCode( value );
Y
yamahigashi 已提交
4837

M
Mr.doob 已提交
4838
			}
Y
yamahigashi 已提交
4839

M
Mr.doob 已提交
4840
			this.skip( size );
Y
yamahigashi 已提交
4841

M
Mr.doob 已提交
4842
			return s;
Y
yamahigashi 已提交
4843

M
Mr.doob 已提交
4844
		}
Y
yamahigashi 已提交
4845

M
Mr.doob 已提交
4846
	} );
Y
yamahigashi 已提交
4847 4848


M
Mr.doob 已提交
4849
	function FBXTree() {}
Y
yamahigashi 已提交
4850

M
Mr.doob 已提交
4851
	Object.assign( FBXTree.prototype, {
Y
yamahigashi 已提交
4852

M
Mr.doob 已提交
4853
		add: function ( key, val ) {
Y
yamahigashi 已提交
4854

M
Mr.doob 已提交
4855
			this[ key ] = val;
Y
yamahigashi 已提交
4856

M
Mr.doob 已提交
4857
		},
Y
yamahigashi 已提交
4858

M
Mr.doob 已提交
4859
		searchConnectionParent: function ( id ) {
K
Kyle Larson 已提交
4860

M
Mr.doob 已提交
4861
			if ( this.__cache_search_connection_parent === undefined ) {
K
Kyle Larson 已提交
4862

M
Mr.doob 已提交
4863
				this.__cache_search_connection_parent = [];
4864

M
Mr.doob 已提交
4865
			}
4866

M
Mr.doob 已提交
4867
			if ( this.__cache_search_connection_parent[ id ] !== undefined ) {
4868

M
Mr.doob 已提交
4869
				return this.__cache_search_connection_parent[ id ];
4870

M
Mr.doob 已提交
4871
			} else {
4872

M
Mr.doob 已提交
4873
				this.__cache_search_connection_parent[ id ] = [];
4874 4875 4876

			}

M
Mr.doob 已提交
4877
			var conns = this.Connections.properties.connections;
4878

M
Mr.doob 已提交
4879 4880
			var results = [];
			for ( var i = 0; i < conns.length; ++ i ) {
4881

M
Mr.doob 已提交
4882
				if ( conns[ i ][ 0 ] == id ) {
4883

M
Mr.doob 已提交
4884 4885 4886
					// 0 means scene root
					var res = conns[ i ][ 1 ] === 0 ? - 1 : conns[ i ][ 1 ];
					results.push( res );
4887

M
Mr.doob 已提交
4888
				}
4889

M
Mr.doob 已提交
4890
			}
4891

M
Mr.doob 已提交
4892
			if ( results.length > 0 ) {
4893

M
Mr.doob 已提交
4894 4895
				append( this.__cache_search_connection_parent[ id ], results );
				return results;
4896

M
Mr.doob 已提交
4897
			} else {
4898

M
Mr.doob 已提交
4899 4900
				this.__cache_search_connection_parent[ id ] = [ - 1 ];
				return [ - 1 ];
4901

M
Mr.doob 已提交
4902
			}
4903

K
Kyle Larson 已提交
4904
		},
K
Kyle Larson 已提交
4905

M
Mr.doob 已提交
4906
		searchConnectionChildren: function ( id ) {
4907

M
Mr.doob 已提交
4908
			if ( this.__cache_search_connection_children === undefined ) {
4909

M
Mr.doob 已提交
4910
				this.__cache_search_connection_children = [];
4911

K
Kyle Larson 已提交
4912
			}
4913

M
Mr.doob 已提交
4914
			if ( this.__cache_search_connection_children[ id ] !== undefined ) {
4915

M
Mr.doob 已提交
4916 4917 4918
				return this.__cache_search_connection_children[ id ];

			} else {
4919

M
Mr.doob 已提交
4920
				this.__cache_search_connection_children[ id ] = [];
4921

K
Kyle Larson 已提交
4922
			}
4923

M
Mr.doob 已提交
4924
			var conns = this.Connections.properties.connections;
4925

M
Mr.doob 已提交
4926 4927
			var res = [];
			for ( var i = 0; i < conns.length; ++ i ) {
4928

M
Mr.doob 已提交
4929
				if ( conns[ i ][ 1 ] == id ) {
4930

M
Mr.doob 已提交
4931 4932 4933
					// 0 means scene root
					res.push( conns[ i ][ 0 ] === 0 ? - 1 : conns[ i ][ 0 ] );
					// there may more than one kid, then search to the end
4934

M
Mr.doob 已提交
4935
				}
4936

K
Kyle Larson 已提交
4937
			}
4938

M
Mr.doob 已提交
4939
			if ( res.length > 0 ) {
K
Kyle Larson 已提交
4940

M
Mr.doob 已提交
4941 4942 4943 4944
				append( this.__cache_search_connection_children[ id ], res );
				return res;

			} else {
K
Kyle Larson 已提交
4945

M
Mr.doob 已提交
4946 4947
				this.__cache_search_connection_children[ id ] = [ ];
				return [ ];
4948

K
Kyle Larson 已提交
4949
			}
K
Kyle Larson 已提交
4950

M
Mr.doob 已提交
4951
		},
4952

M
Mr.doob 已提交
4953
		searchConnectionType: function ( id, to ) {
4954

M
Mr.doob 已提交
4955 4956
			var key = id + ',' + to; // TODO: to hash
			if ( this.__cache_search_connection_type === undefined ) {
4957

M
Mr.doob 已提交
4958
				this.__cache_search_connection_type = {};
4959

M
Mr.doob 已提交
4960
			}
K
Kyle Larson 已提交
4961

M
Mr.doob 已提交
4962
			if ( this.__cache_search_connection_type[ key ] !== undefined ) {
K
Kyle Larson 已提交
4963

M
Mr.doob 已提交
4964
				return this.__cache_search_connection_type[ key ];
K
Kyle Larson 已提交
4965

M
Mr.doob 已提交
4966
			} else {
4967

M
Mr.doob 已提交
4968
				this.__cache_search_connection_type[ key ] = '';
Y
yamahigashi 已提交
4969

M
Mr.doob 已提交
4970
			}
Y
yamahigashi 已提交
4971

M
Mr.doob 已提交
4972
			var conns = this.Connections.properties.connections;
Y
yamahigashi 已提交
4973

M
Mr.doob 已提交
4974
			for ( var i = 0; i < conns.length; ++ i ) {
Y
yamahigashi 已提交
4975

M
Mr.doob 已提交
4976
				if ( conns[ i ][ 0 ] == id && conns[ i ][ 1 ] == to ) {
Y
yamahigashi 已提交
4977

M
Mr.doob 已提交
4978 4979 4980
					// 0 means scene root
					this.__cache_search_connection_type[ key ] = conns[ i ][ 2 ];
					return conns[ i ][ 2 ];
Y
yamahigashi 已提交
4981

M
Mr.doob 已提交
4982
				}
Y
yamahigashi 已提交
4983 4984 4985

			}

M
Mr.doob 已提交
4986 4987
			this.__cache_search_connection_type[ id ] = null;
			return null;
Y
yamahigashi 已提交
4988

M
Mr.doob 已提交
4989
		}
Y
yamahigashi 已提交
4990

M
Mr.doob 已提交
4991
	} );
Y
yamahigashi 已提交
4992 4993


M
Mr.doob 已提交
4994 4995 4996 4997 4998
	/**
	 * @param {ArrayBuffer} buffer
	 * @returns {boolean}
	 */
	function isFbxFormatBinary( buffer ) {
Y
yamahigashi 已提交
4999

M
Mr.doob 已提交
5000
		var CORRECT = 'Kaydara FBX Binary  \0';
Y
yamahigashi 已提交
5001

M
Mr.doob 已提交
5002
		return buffer.byteLength >= CORRECT.length && CORRECT === convertArrayBufferToString( buffer, 0, CORRECT.length );
Y
yamahigashi 已提交
5003

M
Mr.doob 已提交
5004
	}
Y
yamahigashi 已提交
5005

M
Mr.doob 已提交
5006 5007 5008 5009
	/**
	 * @returns {boolean}
	 */
	function isFbxFormatASCII( text ) {
Y
yamahigashi 已提交
5010

M
Mr.doob 已提交
5011
		var CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
Y
yamahigashi 已提交
5012

M
Mr.doob 已提交
5013
		var cursor = 0;
Y
yamahigashi 已提交
5014

M
Mr.doob 已提交
5015
		function read( offset ) {
Y
yamahigashi 已提交
5016

M
Mr.doob 已提交
5017 5018 5019 5020
			var result = text[ offset - 1 ];
			text = text.slice( cursor + offset );
			cursor ++;
			return result;
Y
yamahigashi 已提交
5021 5022 5023

		}

M
Mr.doob 已提交
5024
		for ( var i = 0; i < CORRECT.length; ++ i ) {
Y
yamahigashi 已提交
5025

M
Mr.doob 已提交
5026
			var num = read( 1 );
M
Mugen87 已提交
5027
			if ( num === CORRECT[ i ] ) {
Y
yamahigashi 已提交
5028

M
Mr.doob 已提交
5029
				return false;
Y
yamahigashi 已提交
5030 5031 5032

			}

M
Mr.doob 已提交
5033
		}
Y
yamahigashi 已提交
5034

M
Mr.doob 已提交
5035
		return true;
Y
yamahigashi 已提交
5036

M
Mr.doob 已提交
5037
	}
Y
yamahigashi 已提交
5038

M
Mr.doob 已提交
5039 5040 5041 5042
	/**
	 * @returns {number}
	 */
	function getFbxVersion( text ) {
Y
yamahigashi 已提交
5043

M
Mr.doob 已提交
5044 5045 5046 5047 5048 5049
		var versionRegExp = /FBXVersion: (\d+)/;
		var match = text.match( versionRegExp );
		if ( match ) {

			var version = parseInt( match[ 1 ] );
			return version;
Y
yamahigashi 已提交
5050 5051

		}
M
Mugen87 已提交
5052
		throw new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );
Y
yamahigashi 已提交
5053

M
Mr.doob 已提交
5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064
	}

	/**
	 * Converts FBX ticks into real time seconds.
	 * @param {number} time - FBX tick timestamp to convert.
	 * @returns {number} - FBX tick in real world time.
	 */
	function convertFBXTimeToSeconds( time ) {

		// Constant is FBX ticks per second.
		return time / 46186158000;
Y
yamahigashi 已提交
5065

K
Kyle Larson 已提交
5066
	}
Y
yamahigashi 已提交
5067

M
Mr.doob 已提交
5068 5069 5070 5071 5072 5073 5074 5075
	/**
	 * Parses comma separated list of float numbers and returns them in an array.
	 * @example
	 * // Returns [ 5.6, 9.4, 2.5, 1.4 ]
	 * parseFloatArray( "5.6,9.4,2.5,1.4" )
	 * @returns {number[]}
	 */
	function parseFloatArray( string ) {
Y
yamahigashi 已提交
5076

M
Mr.doob 已提交
5077
		var array = string.split( ',' );
Y
yamahigashi 已提交
5078

M
Mr.doob 已提交
5079
		for ( var i = 0, l = array.length; i < l; i ++ ) {
Y
yamahigashi 已提交
5080

M
Mr.doob 已提交
5081
			array[ i ] = parseFloat( array[ i ] );
Y
yamahigashi 已提交
5082

M
Mr.doob 已提交
5083
		}
Y
yamahigashi 已提交
5084

M
Mr.doob 已提交
5085
		return array;
Y
yamahigashi 已提交
5086

M
Mr.doob 已提交
5087
	}
Y
yamahigashi 已提交
5088

M
Mr.doob 已提交
5089 5090 5091 5092 5093 5094 5095 5096
	/**
	 * Parses comma separated list of int numbers and returns them in an array.
	 * @example
	 * // Returns [ 5, 8, 2, 3 ]
	 * parseFloatArray( "5,8,2,3" )
	 * @returns {number[]}
	 */
	function parseIntArray( string ) {
Y
yamahigashi 已提交
5097

M
Mr.doob 已提交
5098
		var array = string.split( ',' );
Y
yamahigashi 已提交
5099

M
Mr.doob 已提交
5100
		for ( var i = 0, l = array.length; i < l; i ++ ) {
Y
yamahigashi 已提交
5101

M
Mr.doob 已提交
5102
			array[ i ] = parseInt( array[ i ] );
Y
yamahigashi 已提交
5103 5104 5105

		}

M
Mr.doob 已提交
5106
		return array;
Y
yamahigashi 已提交
5107

M
Mr.doob 已提交
5108
	}
Y
yamahigashi 已提交
5109

M
Mr.doob 已提交
5110 5111 5112 5113 5114 5115
	/**
	 * Parses Vector3 property from FBXTree.  Property is given as .value.x, .value.y, etc.
	 * @param {FBXVector3} property - Property to parse as Vector3.
	 * @returns {THREE.Vector3}
	 */
	function parseVector3( property ) {
Y
yamahigashi 已提交
5116

M
Mr.doob 已提交
5117
		return new THREE.Vector3().fromArray( property.value );
Y
yamahigashi 已提交
5118

M
Mr.doob 已提交
5119
	}
Y
yamahigashi 已提交
5120

M
Mr.doob 已提交
5121 5122 5123 5124 5125 5126
	/**
	 * Parses Color property from FBXTree.  Property is given as .value.x, .value.y, etc.
	 * @param {FBXVector3} property - Property to parse as Color.
	 * @returns {THREE.Color}
	 */
	function parseColor( property ) {
Y
yamahigashi 已提交
5127

M
Mr.doob 已提交
5128
		return new THREE.Color().fromArray( property.value );
Y
yamahigashi 已提交
5129 5130 5131

	}

M
Mr.doob 已提交
5132
	function parseMatrixArray( floatString ) {
Y
yamahigashi 已提交
5133

M
Mr.doob 已提交
5134
		return new THREE.Matrix4().fromArray( parseFloatArray( floatString ) );
Y
yamahigashi 已提交
5135

5136
	}
Y
yamahigashi 已提交
5137

M
Mr.doob 已提交
5138 5139 5140 5141 5142 5143 5144 5145
	/**
	 * Converts ArrayBuffer to String.
	 * @param {ArrayBuffer} buffer
	 * @param {number} from
	 * @param {number} to
	 * @returns {String}
	 */
	function convertArrayBufferToString( buffer, from, to ) {
Y
yamahigashi 已提交
5146

M
Mr.doob 已提交
5147 5148
		if ( from === undefined ) from = 0;
		if ( to === undefined ) to = buffer.byteLength;
Y
yamahigashi 已提交
5149

M
Mr.doob 已提交
5150
		var array = new Uint8Array( buffer, from, to );
Y
yamahigashi 已提交
5151

5152 5153 5154 5155 5156 5157
		if ( window.TextDecoder !== undefined ) {

			return new TextDecoder().decode( array );

		}

M
Mr.doob 已提交
5158
		var s = '';
Y
yamahigashi 已提交
5159

M
Mr.doob 已提交
5160
		for ( var i = 0, il = array.length; i < il; i ++ ) {
Y
yamahigashi 已提交
5161

M
Mr.doob 已提交
5162
			s += String.fromCharCode( array[ i ] );
Y
yamahigashi 已提交
5163

M
Mr.doob 已提交
5164
		}
Y
yamahigashi 已提交
5165

M
Mr.doob 已提交
5166
		return s;
Y
yamahigashi 已提交
5167

M
Mr.doob 已提交
5168
	}
Y
yamahigashi 已提交
5169

M
Mr.doob 已提交
5170 5171 5172 5173 5174 5175
	/**
	 * Converts number from degrees into radians.
	 * @param {number} value
	 * @returns {number}
	 */
	function degreeToRadian( value ) {
Y
yamahigashi 已提交
5176

M
Mr.doob 已提交
5177
		return value * DEG2RAD;
Y
yamahigashi 已提交
5178

5179
	}
Y
yamahigashi 已提交
5180

M
Mr.doob 已提交
5181
	var DEG2RAD = Math.PI / 180;
Y
yamahigashi 已提交
5182

M
Mr.doob 已提交
5183
	//
Y
yamahigashi 已提交
5184

M
Mr.doob 已提交
5185
	function findIndex( array, func ) {
Y
yamahigashi 已提交
5186

M
Mr.doob 已提交
5187 5188 5189 5190 5191 5192
		for ( var i = 0, l = array.length; i < l; i ++ ) {

			if ( func( array[ i ] ) ) return i;

		}

M
Mugen87 已提交
5193
		return - 1;
Y
yamahigashi 已提交
5194

5195
	}
Y
yamahigashi 已提交
5196

M
Mr.doob 已提交
5197
	function append( a, b ) {
Y
yamahigashi 已提交
5198

M
Mr.doob 已提交
5199
		for ( var i = 0, j = a.length, l = b.length; i < l; i ++, j ++ ) {
Y
yamahigashi 已提交
5200

M
Mr.doob 已提交
5201
			a[ j ] = b[ i ];
Y
yamahigashi 已提交
5202

M
Mr.doob 已提交
5203
		}
Y
yamahigashi 已提交
5204

5205
	}
Y
yamahigashi 已提交
5206

M
Mr.doob 已提交
5207 5208 5209 5210 5211 5212 5213
	function slice( a, b, from, to ) {

		for ( var i = from, j = 0; i < to; i ++, j ++ ) {

			a[ j ] = b[ i ];

		}
Y
yamahigashi 已提交
5214

M
Mr.doob 已提交
5215
		return a;
Y
yamahigashi 已提交
5216

5217
	}
Y
yamahigashi 已提交
5218 5219

} )();