FBXLoader.js 96.1 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
 * Supports:
 * 	Mesh Generation (Positional Data)
 * 	Normal Data (Per Vertex Drawing Instance)
L
Lewy Blue 已提交
11 12 13
 *	UV Data (Per Vertex Drawing Instance)
 *	Skinning
 *	Animation
M
Mr.doob 已提交
14 15
 * 	- Separated Animations based on stacks.
 * 	- Skeletal & Non-Skeletal Animations
L
Lewy Blue 已提交
16
 *	NURBS (Open, Closed and Periodic forms)
Y
yamahigashi 已提交
17
 *
M
Mr.doob 已提交
18 19 20
 * Needs Support:
 * 	Indexed Buffers
 * 	PreRotation support.
L
Lewy Blue 已提交
21
 *	Euler rotation order
L
Lewy Blue 已提交
22 23 24 25 26 27 28
 *
 * FBX format references:
 * 	https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure
 *
 * 	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)
Y
yamahigashi 已提交
29 30
 */

31
( function () {
Y
yamahigashi 已提交
32

M
Mr.doob 已提交
33
	THREE.FBXLoader = function ( manager ) {
Y
yamahigashi 已提交
34

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

Y
yamahigashi 已提交
37
	};
Y
yamahigashi 已提交
38

39
	Object.assign( THREE.FBXLoader.prototype, {
Y
yamahigashi 已提交
40

41
		load: function ( url, onLoad, onProgress, onError ) {
Y
yamahigashi 已提交
42

M
Mr.doob 已提交
43
			var self = this;
Y
yamahigashi 已提交
44

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

M
Mr.doob 已提交
47 48 49
			var loader = new THREE.FileLoader( this.manager );
			loader.setResponseType( 'arraybuffer' );
			loader.load( url, function ( buffer ) {
Y
yamahigashi 已提交
50

M
Mr.doob 已提交
51
				try {
Y
yamahigashi 已提交
52

M
Mr.doob 已提交
53 54
					var scene = self.parse( buffer, resourceDirectory );
					onLoad( scene );
Y
yamahigashi 已提交
55

M
Mr.doob 已提交
56
				} catch ( error ) {
Y
yamahigashi 已提交
57

M
Mr.doob 已提交
58
					window.setTimeout( function () {
Y
yamahigashi 已提交
59

M
Mr.doob 已提交
60
						if ( onError ) onError( error );
Y
yamahigashi 已提交
61

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

M
Mr.doob 已提交
64
					}, 0 );
Y
yamahigashi 已提交
65

M
Mr.doob 已提交
66
				}
Y
yamahigashi 已提交
67

M
Mr.doob 已提交
68
			}, onProgress, onError );
Y
yamahigashi 已提交
69

70
		},
Y
yamahigashi 已提交
71

M
Mr.doob 已提交
72
		parse: function ( FBXBuffer, resourceDirectory ) {
Y
yamahigashi 已提交
73

M
Mr.doob 已提交
74
			var FBXTree;
Y
yamahigashi 已提交
75

M
Mr.doob 已提交
76
			if ( isFbxFormatBinary( FBXBuffer ) ) {
Y
yamahigashi 已提交
77

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

M
Mr.doob 已提交
80
			} else {
Y
yamahigashi 已提交
81

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

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

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

88
				}
Y
yamahigashi 已提交
89

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

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

M
Mr.doob 已提交
94
				}
Y
yamahigashi 已提交
95

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

98
			}
M
Mr.doob 已提交
99

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

M
Mr.doob 已提交
102 103 104 105 106 107 108
			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 已提交
109

M
Mr.doob 已提交
110
			return sceneGraph;
Y
yamahigashi 已提交
111

M
Mr.doob 已提交
112
		}
M
Mr.doob 已提交
113

M
Mr.doob 已提交
114
	} );
Y
yamahigashi 已提交
115

L
Lewy Blue 已提交
116 117
	// Parses FBXTree.Connections which holds parent-child connections between objects (e.g. material -> texture, model->geometry )
	// and details the connection type
M
Mr.doob 已提交
118
	function parseConnections( FBXTree ) {
Y
yamahigashi 已提交
119

M
Mr.doob 已提交
120
		var connectionMap = new Map();
K
Kyle Larson 已提交
121

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

M
Mr.doob 已提交
124 125
			var connectionArray = FBXTree.Connections.properties.connections;
			for ( var connectionArrayIndex = 0, connectionArrayLength = connectionArray.length; connectionArrayIndex < connectionArrayLength; ++ connectionArrayIndex ) {
Y
yamahigashi 已提交
126

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

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

M
Mr.doob 已提交
131 132 133 134
					connectionMap.set( connection[ 0 ], {
						parents: [],
						children: []
					} );
Y
yamahigashi 已提交
135

136
				}
Y
yamahigashi 已提交
137

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

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

M
Mr.doob 已提交
143 144 145 146
					connectionMap.set( connection[ 1 ], {
						parents: [],
						children: []
					} );
Y
yamahigashi 已提交
147

M
Mr.doob 已提交
148
				}
Y
yamahigashi 已提交
149

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

153
			}
Y
yamahigashi 已提交
154

M
Mr.doob 已提交
155
		}
Y
yamahigashi 已提交
156

M
Mr.doob 已提交
157
		return connectionMap;
K
Kyle Larson 已提交
158

M
Mr.doob 已提交
159
	}
K
Kyle Larson 已提交
160

L
Lewy Blue 已提交
161 162 163 164 165 166

	// Parses map of images referenced in FBXTree.Objects.subNodes.Video
	// Images can either be referenced externally or embedded in the file
	// These images are connected to textures in FBXTree.Objects.subNodes.Textures
	// via FBXTree.Connections. Note that images can be duplicated here, in which case only one
	// will will have a .Content field
M
Mr.doob 已提交
167
	function parseImages( FBXTree ) {
K
Kyle Larson 已提交
168

M
Mr.doob 已提交
169
		var imageMap = new Map();
K
Kyle Larson 已提交
170

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

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

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

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

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

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

M
Mr.doob 已提交
185
				}
K
Kyle Larson 已提交
186

M
Mr.doob 已提交
187
			}
K
Kyle Larson 已提交
188

M
Mr.doob 已提交
189
		}
K
Kyle Larson 已提交
190

M
Mr.doob 已提交
191
		return imageMap;
K
Kyle Larson 已提交
192

M
Mr.doob 已提交
193
	}
K
Kyle Larson 已提交
194

L
Lewy Blue 已提交
195
	// Parse embedded image data in FBXTree.Video.properties.Content
M
Mr.doob 已提交
196
	function parseImage( videoNode ) {
K
Kyle Larson 已提交
197

198
		var content = videoNode.properties.Content;
M
Mr.doob 已提交
199 200
		var fileName = videoNode.properties.RelativeFilename || videoNode.properties.Filename;
		var extension = fileName.slice( fileName.lastIndexOf( '.' ) + 1 ).toLowerCase();
K
Kyle Larson 已提交
201

M
Mr.doob 已提交
202
		var type;
K
Kyle Larson 已提交
203

M
Mr.doob 已提交
204
		switch ( extension ) {
K
Kyle Larson 已提交
205

M
Mr.doob 已提交
206
			case 'bmp':
K
Kyle Larson 已提交
207

M
Mr.doob 已提交
208 209
				type = 'image/bmp';
				break;
K
Kyle Larson 已提交
210

M
Mr.doob 已提交
211
			case 'jpg':
212
			case 'jpeg':
K
Kyle Larson 已提交
213

M
Mr.doob 已提交
214 215
				type = 'image/jpeg';
				break;
K
Kyle Larson 已提交
216

M
Mr.doob 已提交
217
			case 'png':
K
Kyle Larson 已提交
218

M
Mr.doob 已提交
219 220
				type = 'image/png';
				break;
K
Kyle Larson 已提交
221

M
Mr.doob 已提交
222
			case 'tif':
K
Kyle Larson 已提交
223

M
Mr.doob 已提交
224 225
				type = 'image/tiff';
				break;
K
Kyle Larson 已提交
226

M
Mr.doob 已提交
227
			default:
K
Kyle Larson 已提交
228

229
				console.warn( 'FBXLoader: Image type "' + extension + '" is not supported.' );
M
Mr.doob 已提交
230
				return;
K
Kyle Larson 已提交
231

M
Mr.doob 已提交
232
		}
K
Kyle Larson 已提交
233

234 235 236 237 238 239 240 241 242 243
		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 已提交
244

M
Mr.doob 已提交
245
	}
K
Kyle Larson 已提交
246

L
Lewy Blue 已提交
247 248 249
	// Parse nodes in FBXTree.Objects.subNodes.Texture
	// These contain details such as UV scaling, cropping, rotation etc and are connected
	// to images in FBXTree.Objects.subNodes.Video
M
Mr.doob 已提交
250
	function parseTextures( FBXTree, loader, imageMap, connections ) {
K
Kyle Larson 已提交
251

M
Mr.doob 已提交
252
		var textureMap = new Map();
K
Kyle Larson 已提交
253

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

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

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

M
Mr.doob 已提交
262
			}
K
Kyle Larson 已提交
263

M
Mr.doob 已提交
264
		}
K
Kyle Larson 已提交
265

M
Mr.doob 已提交
266
		return textureMap;
K
Kyle Larson 已提交
267

M
Mr.doob 已提交
268
	}
K
Kyle Larson 已提交
269

L
Lewy Blue 已提交
270
	// Parse individual node in FBXTree.Objects.subNodes.Texture
M
Mr.doob 已提交
271
	function parseTexture( textureNode, loader, imageMap, connections ) {
K
Kyle Larson 已提交
272

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

L
Lewy Blue 已提交
275
		var name = textureNode.attrName;
K
Kyle Larson 已提交
276

M
Mr.doob 已提交
277
		var fileName;
K
Kyle Larson 已提交
278

M
Mr.doob 已提交
279 280
		var filePath = textureNode.properties.FileName;
		var relativeFilePath = textureNode.properties.RelativeFilename;
K
Kyle Larson 已提交
281

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

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

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

L
Lewy Blue 已提交
288
		} else if ( relativeFilePath !== undefined && relativeFilePath[ 0 ] !== '/' && relativeFilePath.match( /^[a-zA-Z]:/ ) === null ) {
K
Kyle Larson 已提交
289

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

M
Mr.doob 已提交
293
			fileName = relativeFilePath;
K
Kyle Larson 已提交
294

M
Mr.doob 已提交
295
		} else {
K
Kyle Larson 已提交
296

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

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

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

M
Mr.doob 已提交
303
			} else {
K
Kyle Larson 已提交
304

M
Mr.doob 已提交
305
				fileName = filePath;
306

M
Mr.doob 已提交
307
			}
308

M
Mr.doob 已提交
309
		}
K
Kyle Larson 已提交
310

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

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

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

M
Mr.doob 已提交
317
		}
318

M
Mr.doob 已提交
319 320 321
		var texture = loader.load( fileName );
		texture.name = name;
		texture.FBX_ID = FBX_ID;
322

323 324 325 326 327 328 329 330 331 332 333 334
		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;

J
Juha-Pekka Arimaa 已提交
335
		if ( 'Scaling' in textureNode.properties ) {
J
Juha-Pekka Arimaa 已提交
336

J
Juha-Pekka Arimaa 已提交
337
			var values = textureNode.properties.Scaling.value;
J
Juha-Pekka Arimaa 已提交
338 339 340 341 342

			texture.repeat.x = values[ 0 ];
			texture.repeat.y = values[ 1 ];

		}
343

M
Mr.doob 已提交
344
		loader.setPath( currentPath );
345

M
Mr.doob 已提交
346
		return texture;
347

M
Mr.doob 已提交
348
	}
349

L
Lewy Blue 已提交
350 351

	// Parse nodes in FBXTree.Objects.subNodes.Material
M
Mr.doob 已提交
352
	function parseMaterials( FBXTree, textureMap, connections ) {
353

M
Mr.doob 已提交
354
		var materialMap = new Map();
355

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

M
Mr.doob 已提交
358 359
			var materialNodes = FBXTree.Objects.subNodes.Material;
			for ( var nodeID in materialNodes ) {
360

M
Mr.doob 已提交
361
				var material = parseMaterial( materialNodes[ nodeID ], textureMap, connections );
L
Lewy Blue 已提交
362
				if ( material !== null ) materialMap.set( parseInt( nodeID ), material );
363

M
Mr.doob 已提交
364
			}
365

M
Mr.doob 已提交
366
		}
367

M
Mr.doob 已提交
368
		return materialMap;
369

M
Mr.doob 已提交
370
	}
371

L
Lewy Blue 已提交
372 373 374
	// Parse single node in FBXTree.Objects.subNodes.Material
	// Materials are connected to texture maps in FBXTree.Objects.subNodes.Textures
	// FBX format currently only supports Lambert and Phong shading models
M
Mr.doob 已提交
375
	function parseMaterial( materialNode, textureMap, connections ) {
376

M
Mr.doob 已提交
377 378 379
		var FBX_ID = materialNode.id;
		var name = materialNode.attrName;
		var type = materialNode.properties.ShadingModel;
380

L
Lewy Blue 已提交
381
		//Case where FBX wraps shading model in property object.
M
Mr.doob 已提交
382
		if ( typeof type === 'object' ) {
383

M
Mr.doob 已提交
384
			type = type.value;
385

M
Mr.doob 已提交
386
		}
387

L
Lewy Blue 已提交
388
		// Ignore unused materials which don't have any connections.
L
Lewy Blue 已提交
389 390
		if ( ! connections.has( FBX_ID ) ) return null;

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

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

M
Mr.doob 已提交
395
		var material;
396

M
Mugen87 已提交
397
		switch ( type.toLowerCase() ) {
398

M
Mr.doob 已提交
399 400 401 402 403 404 405
			case 'phong':
				material = new THREE.MeshPhongMaterial();
				break;
			case 'lambert':
				material = new THREE.MeshLambertMaterial();
				break;
			default:
406 407
				console.warn( 'THREE.FBXLoader: unknown material type "%s". Defaulting to MeshPhongMaterial.', type );
				material = new THREE.MeshPhongMaterial( { color: 0x3300ff } );
M
Mr.doob 已提交
408
				break;
409

M
Mr.doob 已提交
410
		}
411

M
Mr.doob 已提交
412 413
		material.setValues( parameters );
		material.name = name;
414

M
Mr.doob 已提交
415
		return material;
416

M
Mr.doob 已提交
417
	}
418

L
Lewy Blue 已提交
419 420
	// Parse FBX material and return parameters suitable for a three.js material
	// Also parse the texture map and return any textures associated with the material
M
Mr.doob 已提交
421
	function parseParameters( properties, textureMap, childrenRelationships ) {
422

M
Mr.doob 已提交
423
		var parameters = {};
424

L
Lewy Blue 已提交
425 426
		if ( properties.BumpFactor ) {

427
			parameters.bumpScale = properties.BumpFactor.value;
L
Lewy Blue 已提交
428 429

		}
M
Mr.doob 已提交
430
		if ( properties.Diffuse ) {
431

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

L
Lewy Blue 已提交
434 435 436
		}
		if ( properties.DisplacementFactor ) {

437
			parameters.displacementScale = properties.DisplacementFactor.value;
L
Lewy Blue 已提交
438 439 440 441

		}
		if ( properties.ReflectionFactor ) {

442
			parameters.reflectivity = properties.ReflectionFactor.value;
L
Lewy Blue 已提交
443

M
Mr.doob 已提交
444 445
		}
		if ( properties.Specular ) {
446

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

M
Mr.doob 已提交
449 450
		}
		if ( properties.Shininess ) {
451

452
			parameters.shininess = properties.Shininess.value;
453

M
Mr.doob 已提交
454 455
		}
		if ( properties.Emissive ) {
456

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

M
Mr.doob 已提交
459 460
		}
		if ( properties.EmissiveFactor ) {
461

L
Lewy Blue 已提交
462
			parameters.emissiveIntensity = parseFloat( properties.EmissiveFactor.value );
463

M
Mr.doob 已提交
464 465
		}
		if ( properties.Opacity ) {
466

L
Lewy Blue 已提交
467
			parameters.opacity = parseFloat( properties.Opacity.value );
468

M
Mr.doob 已提交
469 470
		}
		if ( parameters.opacity < 1.0 ) {
K
Kyle Larson 已提交
471

M
Mr.doob 已提交
472
			parameters.transparent = true;
K
Kyle Larson 已提交
473

M
Mr.doob 已提交
474
		}
K
Kyle Larson 已提交
475

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

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

M
Mr.doob 已提交
480
			var type = relationship.relationship;
K
Kyle Larson 已提交
481

M
Mr.doob 已提交
482
			switch ( type ) {
K
Kyle Larson 已提交
483

L
Lewy Blue 已提交
484 485 486 487
				case 'Bump':
					parameters.bumpMap = textureMap.get( relationship.ID );
					break;

M
Mugen87 已提交
488
				case 'DiffuseColor':
M
Mr.doob 已提交
489 490
					parameters.map = textureMap.get( relationship.ID );
					break;
K
Kyle Larson 已提交
491

L
Lewy Blue 已提交
492 493 494 495 496 497 498
				case 'DisplacementColor':
					parameters.displacementMap = textureMap.get( relationship.ID );
					break;


				case 'EmissiveColor':
					parameters.emissiveMap = textureMap.get( relationship.ID );
499 500
					break;

M
Mugen87 已提交
501
				case 'NormalMap':
502 503 504
					parameters.normalMap = textureMap.get( relationship.ID );
					break;

L
Lewy Blue 已提交
505 506 507 508 509
				case 'ReflectionColor':
					parameters.envMap = textureMap.get( relationship.ID );
					parameters.envMap.mapping = THREE.EquirectangularReflectionMapping;
					break;

L
Lewy Blue 已提交
510 511 512 513 514 515 516 517 518
				case 'SpecularColor':
					parameters.specularMap = textureMap.get( relationship.ID );
					break;

				case 'TransparentColor':
					parameters.alphaMap = textureMap.get( relationship.ID );
					parameters.transparent = true;
					break;

M
Mugen87 已提交
519
				case 'AmbientColor':
L
Lewy Blue 已提交
520 521 522
				case 'ShininessExponent': // AKA glossiness map
				case 'SpecularFactor': // AKA specularLevel
				case 'VectorDisplacementColor': // NOTE: Seems to be a copy of DisplacementColor
M
Mr.doob 已提交
523
				default:
L
Lewy Blue 已提交
524
					console.warn( 'THREE.FBXLoader: %s map is not supported in three.js, skipping texture.', type );
M
Mr.doob 已提交
525
					break;
K
Kyle Larson 已提交
526 527 528

			}

M
Mr.doob 已提交
529
		}
K
Kyle Larson 已提交
530

M
Mr.doob 已提交
531
		return parameters;
K
Kyle Larson 已提交
532

M
Mr.doob 已提交
533
	}
K
Kyle Larson 已提交
534

L
Lewy Blue 已提交
535 536 537
	// Parse nodes in FBXTree.Objects.subNodes.Deformer
	// Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here
	// Generates map of Skeleton-like objects for use later when generating and binding skeletons.
M
Mr.doob 已提交
538
	function parseDeformers( FBXTree, connections ) {
K
Kyle Larson 已提交
539

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

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

M
Mr.doob 已提交
544
			var DeformerNodes = FBXTree.Objects.subNodes.Deformer;
545

M
Mr.doob 已提交
546
			for ( var nodeID in DeformerNodes ) {
547

M
Mr.doob 已提交
548
				var deformerNode = DeformerNodes[ nodeID ];
549

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

M
Mr.doob 已提交
552 553 554
					var conns = connections.get( parseInt( nodeID ) );
					var skeleton = parseSkeleton( conns, DeformerNodes );
					skeleton.FBX_ID = parseInt( nodeID );
555

M
Mr.doob 已提交
556
					deformers[ nodeID ] = skeleton;
557 558 559

				}

K
Kyle Larson 已提交
560 561
			}

M
Mr.doob 已提交
562
		}
K
Kyle Larson 已提交
563

M
Mr.doob 已提交
564
		return deformers;
K
Kyle Larson 已提交
565

M
Mr.doob 已提交
566
	}
K
Kyle Larson 已提交
567

L
Lewy Blue 已提交
568 569 570
	// Parse single nodes in FBXTree.Objects.subNodes.Deformer
	// Generates a "Skeleton Representation" of FBX nodes based on an FBX Skin Deformer's connections
	// and an object containing SubDeformer nodes.
M
Mr.doob 已提交
571
	function parseSkeleton( connections, DeformerNodes ) {
K
Kyle Larson 已提交
572

M
Mr.doob 已提交
573 574
		var subDeformers = {};
		var children = connections.children;
K
Kyle Larson 已提交
575

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

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

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

M
Mr.doob 已提交
582 583 584 585 586
			var subDeformer = {
				FBX_ID: child.ID,
				index: i,
				indices: [],
				weights: [],
587 588
				transform: new THREE.Matrix4().fromArray( subDeformerNode.subNodes.Transform.properties.a ),
				transformLink: new THREE.Matrix4().fromArray( subDeformerNode.subNodes.TransformLink.properties.a ),
M
Mr.doob 已提交
589 590
				linkMode: subDeformerNode.properties.Mode
			};
Y
yamahigashi 已提交
591

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

594 595
				subDeformer.indices = subDeformerNode.subNodes.Indexes.properties.a;
				subDeformer.weights = subDeformerNode.subNodes.Weights.properties.a;
Y
yamahigashi 已提交
596

M
Mr.doob 已提交
597
			}
Y
yamahigashi 已提交
598

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

M
Mr.doob 已提交
601
		}
Y
yamahigashi 已提交
602

M
Mr.doob 已提交
603 604 605 606
		return {
			map: subDeformers,
			bones: []
		};
Y
yamahigashi 已提交
607

M
Mr.doob 已提交
608
	}
Y
yamahigashi 已提交
609

L
Lewy Blue 已提交
610
	// Parse nodes in FBXTree.Objects.subNodes.Geometry
M
Mr.doob 已提交
611
	function parseGeometries( FBXTree, connections, deformers ) {
Y
yamahigashi 已提交
612

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

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

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

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

M
Mr.doob 已提交
621 622 623
				var relationships = connections.get( parseInt( nodeID ) );
				var geo = parseGeometry( geometryNodes[ nodeID ], relationships, deformers );
				geometryMap.set( parseInt( nodeID ), geo );
Y
yamahigashi 已提交
624

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

M
Mr.doob 已提交
627
		}
Y
yamahigashi 已提交
628

M
Mr.doob 已提交
629
		return geometryMap;
Y
yamahigashi 已提交
630

M
Mr.doob 已提交
631
	}
Y
yamahigashi 已提交
632

L
Lewy Blue 已提交
633
	// Parse single node in FBXTree.Objects.subNodes.Geometry
M
Mr.doob 已提交
634
	function parseGeometry( geometryNode, relationships, deformers ) {
Y
yamahigashi 已提交
635

M
Mr.doob 已提交
636
		switch ( geometryNode.attrType ) {
Y
yamahigashi 已提交
637

M
Mr.doob 已提交
638 639 640
			case 'Mesh':
				return parseMeshGeometry( geometryNode, relationships, deformers );
				break;
Y
yamahigashi 已提交
641

L
Lewy Blue 已提交
642
			case 'NurbsCurve':
M
Mr.doob 已提交
643 644
				return parseNurbsGeometry( geometryNode );
				break;
Y
yamahigashi 已提交
645

M
Mr.doob 已提交
646
		}
Y
yamahigashi 已提交
647

M
Mr.doob 已提交
648
	}
Y
yamahigashi 已提交
649

L
Lewy Blue 已提交
650
	// Parse single node mesh geometry in FBXTree.Objects.subNodes.Geometry
M
Mr.doob 已提交
651
	function parseMeshGeometry( geometryNode, relationships, deformers ) {
Y
yamahigashi 已提交
652

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

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

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

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

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

L
Lewy Blue 已提交
664
	// Generate a THREE.BufferGeometry from a node in FBXTree.Objects.subNodes.Geometry
M
Mr.doob 已提交
665
	function genGeometry( geometryNode, deformer ) {
Y
yamahigashi 已提交
666

M
Mr.doob 已提交
667
		var subNodes = geometryNode.subNodes;
Y
yamahigashi 已提交
668

L
tidying  
Lewy Blue 已提交
669 670
		var vertexPositions = subNodes.Vertices.properties.a;
		var vertexIndices = subNodes.PolygonVertexIndex.properties.a;
Y
yamahigashi 已提交
671

L
tidying  
Lewy Blue 已提交
672
		// create arrays to hold the final data used to build the buffergeometry
L
Lewy Blue 已提交
673 674 675 676 677 678 679
		var vertexBuffer = [];
		var normalBuffer = [];
		var colorsBuffer = [];
		var uvsBuffer = [];
		var materialIndexBuffer = [];
		var vertexWeightsBuffer = [];
		var weightsIndicesBuffer = [];
680

L
tidying  
Lewy Blue 已提交
681 682 683 684 685 686 687 688 689 690 691
		if ( subNodes.LayerElementColor ) {

			var colorInfo = getColors( subNodes.LayerElementColor[ 0 ] );

		}

		if ( subNodes.LayerElementMaterial ) {

			var materialInfo = getMaterials( subNodes.LayerElementMaterial[ 0 ] );

		}
Y
yamahigashi 已提交
692

M
Mr.doob 已提交
693 694 695
		if ( subNodes.LayerElementNormal ) {

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

M
Mr.doob 已提交
697
		}
Y
yamahigashi 已提交
698

M
Mr.doob 已提交
699
		if ( subNodes.LayerElementUV ) {
Y
yamahigashi 已提交
700

L
Lewy Blue 已提交
701 702
			var uvInfo = [];
			var i = 0;
L
Lewy Blue 已提交
703
			while ( subNodes.LayerElementUV[ i ] ) {
L
Lewy Blue 已提交
704

L
Lewy Blue 已提交
705 706
				uvInfo.push( getUVs( subNodes.LayerElementUV[ i ] ) );
				i ++;
L
Lewy Blue 已提交
707 708

			}
Y
yamahigashi 已提交
709

M
Mr.doob 已提交
710
		}
Y
yamahigashi 已提交
711 712


T
Takahiro 已提交
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
		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 已提交
742
		var polygonIndex = 0;
743
		var faceLength = 0;
T
Takahiro 已提交
744
		var displayedWeightsWarning = false;
Y
yamahigashi 已提交
745

L
tidying  
Lewy Blue 已提交
746
		// these will hold data for a single face
747 748
		var vertexPositionIndexes = [];
		var faceNormals = [];
749 750
		var faceColors = [];
		var faceUVs = [];
L
tidying  
Lewy Blue 已提交
751 752
		var faceWeights = [];
		var faceWeightIndices = [];
753

L
tidying  
Lewy Blue 已提交
754
		for ( var polygonVertexIndex = 0; polygonVertexIndex < vertexIndices.length; polygonVertexIndex ++ ) {
Y
yamahigashi 已提交
755

L
tidying  
Lewy Blue 已提交
756
			var vertexIndex = vertexIndices[ polygonVertexIndex ];
Y
yamahigashi 已提交
757

M
Mr.doob 已提交
758
			var endOfFace = false;
Y
yamahigashi 已提交
759

L
Lewy Blue 已提交
760 761 762 763 764 765 766
			// Face index and vertex index arrays are combined in a single array
			// A cube with quad faces looks like this:
			// PolygonVertexIndex: *24 {
			//  a: 0, 1, 3, -3, 2, 3, 5, -5, 4, 5, 7, -7, 6, 7, 1, -1, 1, 7, 5, -4, 6, 0, 2, -5
			//  }
			// Negative numbers mark the end of a face - first face here is 0, 1, 3, -3
			// to find index of last vertex multiply by -1 and subtract 1: -3 * - 1 - 1 = 2
M
Mr.doob 已提交
767
			if ( vertexIndex < 0 ) {
Y
yamahigashi 已提交
768

769
				vertexIndex = vertexIndex ^ - 1; // equivalent to ( x * -1 ) - 1
L
tidying  
Lewy Blue 已提交
770
				vertexIndices[ polygonVertexIndex ] = vertexIndex;
M
Mr.doob 已提交
771
				endOfFace = true;
Y
yamahigashi 已提交
772

M
Mr.doob 已提交
773
			}
Y
yamahigashi 已提交
774

M
Mr.doob 已提交
775 776
			var weightIndices = [];
			var weights = [];
Y
yamahigashi 已提交
777

778
			vertexPositionIndexes.push( vertexIndex * 3, vertexIndex * 3 + 1, vertexIndex * 3 + 2 );
Y
yamahigashi 已提交
779

L
tidying  
Lewy Blue 已提交
780 781 782 783 784 785 786
			if ( colorInfo ) {

				var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, colorInfo );

				faceColors.push( data[ 0 ], data[ 1 ], data[ 2 ] );

			}
Y
yamahigashi 已提交
787

M
Mr.doob 已提交
788
			if ( deformer ) {
Y
yamahigashi 已提交
789

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

T
Takahiro 已提交
792
					var array = weightTable[ vertexIndex ];
Y
yamahigashi 已提交
793

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

T
Takahiro 已提交
796 797
						weights.push( array[ j ].weight );
						weightIndices.push( array[ j ].id );
Y
yamahigashi 已提交
798

799
					}
Y
yamahigashi 已提交
800

801
				}
Y
yamahigashi 已提交
802

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

T
Takahiro 已提交
805 806
					if ( ! displayedWeightsWarning ) {

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

					}
Y
yamahigashi 已提交
811

M
Mr.doob 已提交
812 813
					var WIndex = [ 0, 0, 0, 0 ];
					var Weight = [ 0, 0, 0, 0 ];
Y
yamahigashi 已提交
814

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

M
Mr.doob 已提交
817 818
						var currentWeight = weight;
						var currentIndex = weightIndices[ weightIndex ];
Y
yamahigashi 已提交
819

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

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

M
Mr.doob 已提交
824 825
								comparedWeightArray[ comparedWeightIndex ] = currentWeight;
								currentWeight = comparedWeight;
Y
yamahigashi 已提交
826

M
Mr.doob 已提交
827 828 829
								var tmp = WIndex[ comparedWeightIndex ];
								WIndex[ comparedWeightIndex ] = currentIndex;
								currentIndex = tmp;
Y
yamahigashi 已提交
830

M
Mr.doob 已提交
831
							}
Y
yamahigashi 已提交
832

M
Mr.doob 已提交
833
						} );
Y
yamahigashi 已提交
834

M
Mr.doob 已提交
835
					} );
Y
yamahigashi 已提交
836

M
Mr.doob 已提交
837 838
					weightIndices = WIndex;
					weights = Weight;
Y
yamahigashi 已提交
839

M
Mr.doob 已提交
840
				}
Y
yamahigashi 已提交
841

L
Lewy Blue 已提交
842
				// if the weight array is shorter than 4 pad with 0s
M
Mr.doob 已提交
843
				for ( var i = weights.length; i < 4; ++ i ) {
Y
yamahigashi 已提交
844

M
Mr.doob 已提交
845 846
					weights[ i ] = 0;
					weightIndices[ i ] = 0;
Y
yamahigashi 已提交
847

M
Mr.doob 已提交
848
				}
Y
yamahigashi 已提交
849

L
Lewy Blue 已提交
850 851
				for ( var i = 0; i < 4; ++ i ) {

L
tidying  
Lewy Blue 已提交
852 853
					faceWeights.push( weights[ i ] );
					faceWeightIndices.push( weightIndices[ i ] );
L
Lewy Blue 已提交
854 855

				}
Y
yamahigashi 已提交
856

M
Mr.doob 已提交
857
			}
Y
yamahigashi 已提交
858

M
Mr.doob 已提交
859
			if ( normalInfo ) {
Y
yamahigashi 已提交
860

861 862 863
				var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, normalInfo );

				faceNormals.push( data[ 0 ], data[ 1 ], data[ 2 ] );
Y
yamahigashi 已提交
864

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

M
Mr.doob 已提交
867
			if ( uvInfo ) {
Y
yamahigashi 已提交
868

L
Lewy Blue 已提交
869
				for ( var i = 0; i < uvInfo.length; i ++ ) {
L
Lewy Blue 已提交
870

871
					var data = getData( polygonVertexIndex, polygonIndex, vertexIndex, uvInfo[ i ] );
L
Lewy Blue 已提交
872

L
Lewy Blue 已提交
873
					if ( faceUVs[ i ] === undefined ) {
Y
yamahigashi 已提交
874

L
Lewy Blue 已提交
875
						faceUVs[ i ] = [];
Y
yamahigashi 已提交
876

L
Lewy Blue 已提交
877
					}
Y
yamahigashi 已提交
878

879
					faceUVs[ i ].push(
L
Lewy Blue 已提交
880 881 882
						data[ 0 ],
						data[ 1 ]
					);
L
Lewy Blue 已提交
883 884

				}
Y
yamahigashi 已提交
885

886
			}
Y
yamahigashi 已提交
887

888
			faceLength ++;
Y
yamahigashi 已提交
889

L
tidying  
Lewy Blue 已提交
890 891
			// we have reached the end of a face - it may have 4 sides though
			// in which case the data is split into to represent 3 sides faces
M
Mr.doob 已提交
892
			if ( endOfFace ) {
Y
yamahigashi 已提交
893

894
				for ( var i = 2; i < faceLength; i ++ ) {
Y
yamahigashi 已提交
895

L
Lewy Blue 已提交
896 897 898
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 0 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 1 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 2 ] ] );
Y
yamahigashi 已提交
899

L
Lewy Blue 已提交
900 901 902
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 + 1 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 + 2 ] ] );
Y
yamahigashi 已提交
903

L
Lewy Blue 已提交
904 905 906
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 1 ] ] );
					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 2 ] ] );
907

L
tidying  
Lewy Blue 已提交
908
				}
909

L
tidying  
Lewy Blue 已提交
910
				if ( deformer ) {
911

L
tidying  
Lewy Blue 已提交
912
					for ( var i = 2; i < faceLength; i ++ ) {
913

L
Lewy Blue 已提交
914
						vertexWeightsBuffer.push( faceWeights[ 0 ] );
L
Lewy Blue 已提交
915 916 917
						vertexWeightsBuffer.push( faceWeights[ 1 ] );
						vertexWeightsBuffer.push( faceWeights[ 2 ] );
						vertexWeightsBuffer.push( faceWeights[ 3 ] );
L
Lewy Blue 已提交
918

L
Lewy Blue 已提交
919 920 921 922
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 ] );
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 + 1 ] );
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 + 2 ] );
						vertexWeightsBuffer.push( faceWeights[ ( i - 1 ) * 4 + 3 ] );
L
Lewy Blue 已提交
923

L
Lewy Blue 已提交
924 925 926 927
						vertexWeightsBuffer.push( faceWeights[ i * 4 ] );
						vertexWeightsBuffer.push( faceWeights[ i * 4 + 1 ] );
						vertexWeightsBuffer.push( faceWeights[ i * 4 + 2 ] );
						vertexWeightsBuffer.push( faceWeights[ i * 4 + 3 ] );
L
Lewy Blue 已提交
928

L
Lewy Blue 已提交
929 930 931 932
						weightsIndicesBuffer.push( faceWeightIndices[ 0 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ 1 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ 2 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ 3 ] );
L
Lewy Blue 已提交
933

L
Lewy Blue 已提交
934 935 936 937
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 + 1 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 + 2 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ ( i - 1 ) * 4 + 3 ] );
L
Lewy Blue 已提交
938

L
Lewy Blue 已提交
939 940 941 942
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 + 1 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 + 2 ] );
						weightsIndicesBuffer.push( faceWeightIndices[ i * 4 + 3 ] );
943

L
tidying  
Lewy Blue 已提交
944 945 946
					}

				}
947 948 949 950 951

				if ( normalInfo ) {

					for ( var i = 2; i < faceLength; i ++ ) {

L
Lewy Blue 已提交
952 953 954
						normalBuffer.push( faceNormals[ 0 ] );
						normalBuffer.push( faceNormals[ 1 ] );
						normalBuffer.push( faceNormals[ 2 ] );
955

L
Lewy Blue 已提交
956 957 958
						normalBuffer.push( faceNormals[ ( i - 1 ) * 3 ] );
						normalBuffer.push( faceNormals[ ( i - 1 ) * 3 + 1 ] );
						normalBuffer.push( faceNormals[ ( i - 1 ) * 3 + 2 ] );
Y
yamahigashi 已提交
959

L
Lewy Blue 已提交
960 961 962
						normalBuffer.push( faceNormals[ i * 3 ] );
						normalBuffer.push( faceNormals[ i * 3 + 1 ] );
						normalBuffer.push( faceNormals[ i * 3 + 2 ] );
963 964

					}
Y
yamahigashi 已提交
965

M
Mr.doob 已提交
966
				}
967

968
				if ( uvInfo ) {
969

L
tidying  
Lewy Blue 已提交
970
					for ( var j = 0; j < uvInfo.length; j ++ ) {
Y
yamahigashi 已提交
971

L
Lewy Blue 已提交
972
						if ( uvsBuffer[ j ] === undefined ) uvsBuffer[ j ] = [];
Y
yamahigashi 已提交
973

L
tidying  
Lewy Blue 已提交
974
						for ( var i = 2; i < faceLength; i ++ ) {
Y
yamahigashi 已提交
975

L
Lewy Blue 已提交
976 977
							uvsBuffer[ j ].push( faceUVs[ j ][ 0 ] );
							uvsBuffer[ j ].push( faceUVs[ j ][ 1 ] );
Y
yamahigashi 已提交
978

L
Lewy Blue 已提交
979
							uvsBuffer[ j ].push( faceUVs[ j ][ ( i - 1 ) * 2 ] );
L
Lewy Blue 已提交
980
							uvsBuffer[ j ].push( faceUVs[ j ][ ( i - 1 ) * 2 + 1 ] );
Y
yamahigashi 已提交
981

L
Lewy Blue 已提交
982 983
							uvsBuffer[ j ].push( faceUVs[ j ][ i * 2 ] );
							uvsBuffer[ j ].push( faceUVs[ j ][ i * 2 + 1 ] );
Y
yamahigashi 已提交
984

985
						}
Y
yamahigashi 已提交
986

987
					}
L
Lewy Blue 已提交
988

989
				}
L
Lewy Blue 已提交
990

991
				if ( colorInfo ) {
L
Lewy Blue 已提交
992

993 994 995
					for ( var i = 2; i < faceLength; i ++ ) {


L
Lewy Blue 已提交
996 997 998
						colorsBuffer.push( faceColors[ 0 ] );
						colorsBuffer.push( faceColors[ 1 ] );
						colorsBuffer.push( faceColors[ 2 ] );
L
Lewy Blue 已提交
999

L
Lewy Blue 已提交
1000 1001 1002
						colorsBuffer.push( faceColors[ ( i - 1 ) * 3 ] );
						colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 1 ] );
						colorsBuffer.push( faceColors[ ( i - 1 ) * 3 + 2 ] );
1003

L
Lewy Blue 已提交
1004 1005 1006
						colorsBuffer.push( faceColors[ i * 3 ] );
						colorsBuffer.push( faceColors[ i * 3 + 1 ] );
						colorsBuffer.push( faceColors[ i * 3 + 2 ] );
1007 1008

					}
L
Lewy Blue 已提交
1009 1010

				}
Y
yamahigashi 已提交
1011

L
tidying  
Lewy Blue 已提交
1012
				if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) {
Y
yamahigashi 已提交
1013

L
tidying  
Lewy Blue 已提交
1014
					var materialIndex = getData( polygonVertexIndex, polygonIndex, vertexIndex, materialInfo )[ 0 ];
Y
yamahigashi 已提交
1015

L
tidying  
Lewy Blue 已提交
1016
					for ( var i = 2; i < faceLength; i ++ ) {
Y
yamahigashi 已提交
1017

L
Lewy Blue 已提交
1018 1019 1020
						materialIndexBuffer.push( materialIndex );
						materialIndexBuffer.push( materialIndex );
						materialIndexBuffer.push( materialIndex );
L
tidying  
Lewy Blue 已提交
1021 1022

					}
1023

M
Mr.doob 已提交
1024
				}
1025

M
Mr.doob 已提交
1026
				polygonIndex ++;
1027

M
Mr.doob 已提交
1028
				endOfFace = false;
L
tidying  
Lewy Blue 已提交
1029 1030 1031
				faceLength = 0;

				// reset arrays for the next face
1032 1033
				vertexPositionIndexes = [];
				faceNormals = [];
1034 1035
				faceColors = [];
				faceUVs = [];
L
Lewy Blue 已提交
1036 1037
				faceWeights = [];
				faceWeightIndices = [];
L
Lewy Blue 已提交
1038 1039

			}
Y
yamahigashi 已提交
1040

M
Mr.doob 已提交
1041
		}
L
Lewy Blue 已提交
1042

M
Mr.doob 已提交
1043 1044
		var geo = new THREE.BufferGeometry();
		geo.name = geometryNode.name;
L
tidying  
Lewy Blue 已提交
1045

L
Lewy Blue 已提交
1046
		geo.addAttribute( 'position', new THREE.Float32BufferAttribute( vertexBuffer, 3 ) );
Y
yamahigashi 已提交
1047

L
Lewy Blue 已提交
1048
		if ( colorsBuffer.length > 0 ) {
L
tidying  
Lewy Blue 已提交
1049

L
Lewy Blue 已提交
1050
			geo.addAttribute( 'color', new THREE.Float32BufferAttribute( colorsBuffer, 3 ) );
Y
yamahigashi 已提交
1051

M
Mr.doob 已提交
1052
		}
Y
yamahigashi 已提交
1053

M
Mr.doob 已提交
1054
		if ( deformer ) {
Y
yamahigashi 已提交
1055

L
Lewy Blue 已提交
1056
			geo.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( weightsIndicesBuffer, 4 ) );
Y
yamahigashi 已提交
1057

L
Lewy Blue 已提交
1058
			geo.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( vertexWeightsBuffer, 4 ) );
Y
yamahigashi 已提交
1059

L
Lewy Blue 已提交
1060
			// used later to bind the skeleton to the model
M
Mr.doob 已提交
1061
			geo.FBX_Deformer = deformer;
Y
yamahigashi 已提交
1062

M
Mr.doob 已提交
1063
		}
Y
yamahigashi 已提交
1064

L
Lewy Blue 已提交
1065
		if ( normalBuffer.length > 0 ) {
Y
yamahigashi 已提交
1066

L
Lewy Blue 已提交
1067
			geo.addAttribute( 'normal', new THREE.Float32BufferAttribute( normalBuffer, 3 ) );
Y
yamahigashi 已提交
1068

M
Mr.doob 已提交
1069
		}
L
Lewy Blue 已提交
1070
		if ( uvsBuffer.length > 0 ) {
L
Lewy Blue 已提交
1071

L
Lewy Blue 已提交
1072
			for ( var i = 0; i < uvsBuffer.length; i ++ ) {
L
Lewy Blue 已提交
1073 1074 1075 1076 1077 1078 1079

				var name = 'uv' + ( i + 1 ).toString();
				if ( i == 0 ) {

					name = 'uv';

				}
Y
yamahigashi 已提交
1080

L
Lewy Blue 已提交
1081
				geo.addAttribute( name, new THREE.Float32BufferAttribute( uvsBuffer[ i ], 2 ) );
L
Lewy Blue 已提交
1082 1083

			}
Y
yamahigashi 已提交
1084

M
Mr.doob 已提交
1085
		}
L
Lewy Blue 已提交
1086

1087
		if ( materialInfo && materialInfo.mappingType !== 'AllSame' ) {
Y
yamahigashi 已提交
1088

1089 1090 1091
			// Convert the material indices of each vertex into rendering groups on the geometry.
			var prevMaterialIndex = materialIndexBuffer[ 0 ];
			var startIndex = 0;
Y
yamahigashi 已提交
1092

1093
			for ( var i = 0; i < materialIndexBuffer.length; ++ i ) {
Y
yamahigashi 已提交
1094

1095
				if ( materialIndexBuffer[ i ] !== prevMaterialIndex ) {
Y
yamahigashi 已提交
1096

1097
					geo.addGroup( startIndex, i - startIndex, prevMaterialIndex );
M
Mr.doob 已提交
1098

1099 1100 1101 1102
					prevMaterialIndex = materialIndexBuffer[ i ];
					startIndex = i;

				}
Y
yamahigashi 已提交
1103

Y
yamahigashi 已提交
1104
			}
Y
yamahigashi 已提交
1105

1106 1107
			// the loop above doesn't add the last group, do that here.
			if ( geo.groups.length > 0 ) {
Y
yamahigashi 已提交
1108

1109 1110
				var lastGroup = geo.groups[ geo.groups.length - 1 ];
				var lastIndex = lastGroup.start + lastGroup.count;
1111

1112
				if ( lastIndex !== materialIndexBuffer.length ) {
1113

1114
					geo.addGroup( lastIndex, materialIndexBuffer.length - lastIndex, prevMaterialIndex );
1115

1116
				}
1117 1118 1119

			}

1120 1121 1122
			// case where there are multiple materials but the whole geometry is only
			// using one of them
			if ( geo.groups.length === 0 ) {
1123

1124
				geo.addGroup( 0, materialIndexBuffer.length, materialIndexBuffer[ 0 ] );
1125

1126
			}
1127 1128 1129

		}

M
Mr.doob 已提交
1130
		return geo;
Y
yamahigashi 已提交
1131

M
Mr.doob 已提交
1132
	}
Y
yamahigashi 已提交
1133

L
Lewy Blue 已提交
1134
	// Parse normal from FBXTree.Objects.subNodes.Geometry.subNodes.LayerElementNormal if it exists
M
Mr.doob 已提交
1135
	function getNormals( NormalNode ) {
Y
yamahigashi 已提交
1136

M
Mr.doob 已提交
1137 1138
		var mappingType = NormalNode.properties.MappingInformationType;
		var referenceType = NormalNode.properties.ReferenceInformationType;
1139
		var buffer = NormalNode.subNodes.Normals.properties.a;
M
Mr.doob 已提交
1140 1141
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1142

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

1145
				indexBuffer = NormalNode.subNodes.NormalIndex.properties.a;
Y
yamahigashi 已提交
1146

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

1149
				indexBuffer = NormalNode.subNodes.NormalsIndex.properties.a;
Y
yamahigashi 已提交
1150

1151
			}
Y
yamahigashi 已提交
1152

M
Mr.doob 已提交
1153
		}
Y
yamahigashi 已提交
1154

M
Mr.doob 已提交
1155 1156 1157 1158 1159 1160 1161
		return {
			dataSize: 3,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1162

M
Mr.doob 已提交
1163
	}
Y
yamahigashi 已提交
1164

L
Lewy Blue 已提交
1165
	// Parse UVs from FBXTree.Objects.subNodes.Geometry.subNodes.LayerElementUV if it exists
M
Mr.doob 已提交
1166
	function getUVs( UVNode ) {
Y
yamahigashi 已提交
1167

M
Mr.doob 已提交
1168 1169
		var mappingType = UVNode.properties.MappingInformationType;
		var referenceType = UVNode.properties.ReferenceInformationType;
1170
		var buffer = UVNode.subNodes.UV.properties.a;
M
Mr.doob 已提交
1171 1172
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1173

1174
			indexBuffer = UVNode.subNodes.UVIndex.properties.a;
Y
yamahigashi 已提交
1175

M
Mr.doob 已提交
1176
		}
Y
yamahigashi 已提交
1177

M
Mr.doob 已提交
1178 1179 1180 1181 1182 1183 1184
		return {
			dataSize: 2,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1185

M
Mr.doob 已提交
1186
	}
Y
yamahigashi 已提交
1187

L
Lewy Blue 已提交
1188
	// Parse Vertex Colors from FBXTree.Objects.subNodes.Geometry.subNodes.LayerElementColor if it exists
M
Mr.doob 已提交
1189
	function getColors( ColorNode ) {
Y
yamahigashi 已提交
1190

M
Mr.doob 已提交
1191 1192
		var mappingType = ColorNode.properties.MappingInformationType;
		var referenceType = ColorNode.properties.ReferenceInformationType;
1193
		var buffer = ColorNode.subNodes.Colors.properties.a;
M
Mr.doob 已提交
1194 1195
		var indexBuffer = [];
		if ( referenceType === 'IndexToDirect' ) {
Y
yamahigashi 已提交
1196

1197
			indexBuffer = ColorNode.subNodes.ColorIndex.properties.a;
1198

Y
yamahigashi 已提交
1199
		}
Y
yamahigashi 已提交
1200

M
Mr.doob 已提交
1201 1202 1203 1204 1205 1206 1207
		return {
			dataSize: 4,
			buffer: buffer,
			indices: indexBuffer,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1208

M
Mr.doob 已提交
1209
	}
Y
yamahigashi 已提交
1210

L
Lewy Blue 已提交
1211
	// Parse mapping and material data in FBXTree.Objects.subNodes.Geometry.subNodes.LayerElementMaterial if it exists
M
Mr.doob 已提交
1212
	function getMaterials( MaterialNode ) {
Y
yamahigashi 已提交
1213

M
Mr.doob 已提交
1214 1215
		var mappingType = MaterialNode.properties.MappingInformationType;
		var referenceType = MaterialNode.properties.ReferenceInformationType;
Y
yamahigashi 已提交
1216

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

M
Mr.doob 已提交
1219 1220 1221 1222 1223 1224 1225
			return {
				dataSize: 1,
				buffer: [ 0 ],
				indices: [ 0 ],
				mappingType: 'AllSame',
				referenceType: referenceType
			};
Y
yamahigashi 已提交
1226

M
Mr.doob 已提交
1227
		}
Y
yamahigashi 已提交
1228

1229
		var materialIndexBuffer = MaterialNode.subNodes.Materials.properties.a;
Y
yamahigashi 已提交
1230

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

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

M
Mr.doob 已提交
1238
			materialIndices.push( materialIndexBufferIndex );
Y
yamahigashi 已提交
1239

M
Mr.doob 已提交
1240
		}
Y
yamahigashi 已提交
1241

M
Mr.doob 已提交
1242 1243 1244 1245 1246 1247 1248
		return {
			dataSize: 1,
			buffer: materialIndexBuffer,
			indices: materialIndices,
			mappingType: mappingType,
			referenceType: referenceType
		};
Y
yamahigashi 已提交
1249

M
Mr.doob 已提交
1250 1251
	}

L
Lewy Blue 已提交
1252 1253 1254 1255 1256
	// Functions use the infoObject and given indices to return value array of geometry.
	// infoObject can be materialInfo, normalInfo, UVInfo or colorInfo
	// polygonVertexIndex - Index of vertex in draw order (which index of the index buffer refers to this vertex).
	// polygonIndex - Index of polygon in geometry.
	// vertexIndex - Index of vertex inside vertex buffer (used because some data refers to old index buffer that we don't use anymore).
M
Mr.doob 已提交
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
	var dataArray = [];

	var GetData = {

		ByPolygonVertex: {

			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 );

			},

			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 已提交
1283

Y
yamahigashi 已提交
1284
		},
Y
yamahigashi 已提交
1285

M
Mr.doob 已提交
1286
		ByPolygon: {
Y
yamahigashi 已提交
1287

M
Mr.doob 已提交
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
			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 );

			},

			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 已提交
1308

Y
yamahigashi 已提交
1309
		},
Y
yamahigashi 已提交
1310

1311
		ByVertice: {
Y
yamahigashi 已提交
1312

M
Mr.doob 已提交
1313 1314 1315 1316 1317 1318 1319 1320 1321
			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 已提交
1322

Y
yamahigashi 已提交
1323
		},
Y
yamahigashi 已提交
1324

M
Mr.doob 已提交
1325
		AllSame: {
Y
yamahigashi 已提交
1326

M
Mr.doob 已提交
1327
			IndexToDirect: function ( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {
Y
yamahigashi 已提交
1328

M
Mr.doob 已提交
1329 1330
				var from = infoObject.indices[ 0 ] * infoObject.dataSize;
				var to = infoObject.indices[ 0 ] * infoObject.dataSize + infoObject.dataSize;
Y
yamahigashi 已提交
1331

M
Mr.doob 已提交
1332 1333
				// return infoObject.buffer.slice( from, to );
				return slice( dataArray, infoObject.buffer, from, to );
Y
yamahigashi 已提交
1334

M
Mr.doob 已提交
1335
			}
Y
yamahigashi 已提交
1336

M
Mr.doob 已提交
1337
		}
Y
yamahigashi 已提交
1338

M
Mr.doob 已提交
1339
	};
Y
yamahigashi 已提交
1340

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

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

M
Mr.doob 已提交
1345
	}
Y
yamahigashi 已提交
1346

L
Lewy Blue 已提交
1347
	// Generate a NurbGeometry from a node in FBXTree.Objects.subNodes.Geometry
M
Mr.doob 已提交
1348
	function parseNurbsGeometry( geometryNode ) {
Y
yamahigashi 已提交
1349

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

M
Mugen87 已提交
1352
			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 已提交
1353
			return new THREE.BufferGeometry();
Y
yamahigashi 已提交
1354

M
Mr.doob 已提交
1355
		}
Y
yamahigashi 已提交
1356

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

M
Mr.doob 已提交
1359
		if ( isNaN( order ) ) {
Y
yamahigashi 已提交
1360

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

M
Mr.doob 已提交
1364
		}
Y
yamahigashi 已提交
1365

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

1368
		var knots = geometryNode.subNodes.KnotVector.properties.a;
M
Mr.doob 已提交
1369
		var controlPoints = [];
1370
		var pointsValues = geometryNode.subNodes.Points.properties.a;
Y
yamahigashi 已提交
1371

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

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

M
Mr.doob 已提交
1376
		}
Y
yamahigashi 已提交
1377

M
Mr.doob 已提交
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
		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;

	}

L
Lewy Blue 已提交
1415 1416

	// parse nodes in FBXTree.Objects.subNodes.Model and generate a THREE.Group
M
Mr.doob 已提交
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452
	function parseScene( FBXTree, connections, deformers, geometryMap, materialMap ) {

		var sceneGraph = new THREE.Group();

		var ModelNode = FBXTree.Objects.subNodes.Model;

		var modelArray = [];

		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 已提交
1453

Y
yamahigashi 已提交
1454
				}
Y
yamahigashi 已提交
1455

Y
yamahigashi 已提交
1456
			}
Y
yamahigashi 已提交
1457

M
Mr.doob 已提交
1458
			if ( ! model ) {
Y
yamahigashi 已提交
1459

M
Mr.doob 已提交
1460
				switch ( node.attrType ) {
Y
yamahigashi 已提交
1461

L
Lewy Blue 已提交
1462
					// create a THREE.PerspectiveCamera or THREE.OrthographicCamera
L
Lewy Blue 已提交
1463
					case 'Camera':
L
Lewy Blue 已提交
1464

L
Lewy Blue 已提交
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
						var cameraAttribute;

						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 ) {

								cameraAttribute = attr.properties;

							}

						}

						if ( cameraAttribute === undefined ) {

							model = new THREE.Object3D();

						} else {

							var type = 0;
1488
							if ( cameraAttribute.CameraProjectionType !== undefined && cameraAttribute.CameraProjectionType.value === 1 ) {
L
Lewy Blue 已提交
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513

								type = 1;

							}

							var nearClippingPlane = 1;
							if ( cameraAttribute.NearPlane !== undefined ) {

								nearClippingPlane = cameraAttribute.NearPlane.value / 1000;

							}

							var farClippingPlane = 1000;
							if ( cameraAttribute.FarPlane !== undefined ) {

								farClippingPlane = cameraAttribute.FarPlane.value / 1000;

							}


							var width = window.innerWidth;
							var height = window.innerHeight;

							if ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) {

1514 1515
								width = cameraAttribute.AspectWidth.value;
								height = cameraAttribute.AspectHeight.value;
L
Lewy Blue 已提交
1516 1517 1518 1519 1520 1521 1522 1523

							}

							var aspect = width / height;

							var fov = 45;
							if ( cameraAttribute.FieldOfView !== undefined ) {

1524
								fov = cameraAttribute.FieldOfView.value;
L
Lewy Blue 已提交
1525 1526 1527 1528 1529

							}

							switch ( type ) {

1530
								case 0: // Perspective
L
Lewy Blue 已提交
1531 1532 1533
									model = new THREE.PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane );
									break;

1534
								case 1: // Orthographic
L
Lewy Blue 已提交
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548
									model = new THREE.OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane );
									break;

								default:
									console.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' );
									model = new THREE.Object3D();
									break;

							}

						}

						break;

L
Lewy Blue 已提交
1549 1550

					// Create a THREE.DirectionalLight, THREE.PointLight or THREE.SpotLight
L
Lewy Blue 已提交
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
					case 'Light':

						var lightAttribute;

						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 ) {

								lightAttribute = attr.properties;

							}

						}

						if ( lightAttribute === undefined ) {

							model = new THREE.Object3D();

						} else {

							var type;

							// LightType can be undefined for Point lights
							if ( lightAttribute.LightType === undefined ) {

								type = 0;

							} else {

								type = lightAttribute.LightType.value;

							}

							var color = 0xffffff;

							if ( lightAttribute.Color !== undefined ) {

L
Lewy Blue 已提交
1592
								color = parseColor( lightAttribute.Color.value );
L
Lewy Blue 已提交
1593 1594 1595 1596 1597 1598

							}

							var intensity = ( lightAttribute.Intensity === undefined ) ? 1 : lightAttribute.Intensity.value / 100;

							// light disabled
1599
							if ( lightAttribute.CastLightOnObject !== undefined && lightAttribute.CastLightOnObject.value === 0 ) {
L
Lewy Blue 已提交
1600 1601 1602 1603 1604 1605 1606 1607

								intensity = 0;

							}

							var distance = 0;
							if ( lightAttribute.FarAttenuationEnd !== undefined ) {

1608
								if ( lightAttribute.EnableFarAttenuation !== undefined && lightAttribute.EnableFarAttenuation.value === 0 ) {
L
Lewy Blue 已提交
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619

									distance = 0;

								} else {

									distance = lightAttribute.FarAttenuationEnd.value / 1000;

								}

							}

L
Lewy Blue 已提交
1620
							// TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd?
L
Lewy Blue 已提交
1621 1622 1623 1624
							var decay = 1;

							switch ( type ) {

1625
								case 0: // Point
L
Lewy Blue 已提交
1626 1627 1628
									model = new THREE.PointLight( color, intensity, distance, decay );
									break;

1629
								case 1: // Directional
L
Lewy Blue 已提交
1630 1631 1632
									model = new THREE.DirectionalLight( color, intensity );
									break;

1633
								case 2: // Spot
L
Lewy Blue 已提交
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
									var angle = Math.PI / 3;

									if ( lightAttribute.InnerAngle !== undefined ) {

										angle = THREE.Math.degToRad( lightAttribute.InnerAngle.value );

									}

									var penumbra = 0;
									if ( lightAttribute.OuterAngle !== undefined ) {

										// TODO: this is not correct - FBX calculates outer and inner angle in degrees
										// with OuterAngle > InnerAngle && OuterAngle <= Math.PI
										// while three.js uses a penumbra between (0, 1) to attenuate the inner angle
										penumbra = THREE.Math.degToRad( lightAttribute.OuterAngle.value );
										penumbra = Math.max( penumbra, 1 );

									}

									model = new THREE.SpotLight( color, intensity, distance, angle, penumbra, decay );
									break;

								default:
									console.warn( 'THREE.FBXLoader: Unknown light type ' + lightAttribute.LightType.value + ', defaulting to a THREE.PointLight.' );
									model = new THREE.PointLight( color, intensity );
									break;

							}

1663
							if ( lightAttribute.CastShadows !== undefined && lightAttribute.CastShadows.value === 1 ) {
L
Lewy Blue 已提交
1664 1665 1666 1667 1668 1669 1670 1671 1672

								model.castShadow = true;

							}

						}

						break;

M
Mugen87 已提交
1673
					case 'Mesh':
Y
yamahigashi 已提交
1674

L
Lewy Blue 已提交
1675
						var geometry = null;
M
Mr.doob 已提交
1676 1677
						var material = null;
						var materials = [];
Y
yamahigashi 已提交
1678

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

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

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

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

M
Mr.doob 已提交
1687
							}
Y
yamahigashi 已提交
1688

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

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

M
Mr.doob 已提交
1693
							}
Y
yamahigashi 已提交
1694

M
Mr.doob 已提交
1695 1696 1697
						}
						if ( materials.length > 1 ) {

1698
							material = materials;
M
Mr.doob 已提交
1699 1700 1701 1702

						} else if ( materials.length > 0 ) {

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

Y
yamahigashi 已提交
1704
						} else {
Y
yamahigashi 已提交
1705

L
typo  
Lewy Blue 已提交
1706
							material = new THREE.MeshPhongMaterial( { color: 0xcccccc } );
M
Mr.doob 已提交
1707
							materials.push( material );
Y
yamahigashi 已提交
1708

Y
yamahigashi 已提交
1709
						}
M
Mr.doob 已提交
1710
						if ( 'color' in geometry.attributes ) {
Y
yamahigashi 已提交
1711

L
Lewy Blue 已提交
1712
							for ( var materialIndex = 0, numMaterials = materials.length; materialIndex < numMaterials; ++ materialIndex ) {
Y
yamahigashi 已提交
1713

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

M
Mr.doob 已提交
1716
							}
Y
yamahigashi 已提交
1717

M
Mr.doob 已提交
1718 1719
						}
						if ( geometry.FBX_Deformer ) {
Y
yamahigashi 已提交
1720

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

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

M
Mr.doob 已提交
1725 1726
							}
							model = new THREE.SkinnedMesh( geometry, material );
1727

M
Mr.doob 已提交
1728
						} else {
1729

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

M
Mr.doob 已提交
1732 1733 1734
						}
						break;

M
Mugen87 已提交
1735
					case 'NurbsCurve':
M
Mr.doob 已提交
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
						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:
1756
						model = new THREE.Group();
M
Mr.doob 已提交
1757
						break;
Y
yamahigashi 已提交
1758

Y
yamahigashi 已提交
1759
				}
Y
yamahigashi 已提交
1760

Y
yamahigashi 已提交
1761
			}
Y
yamahigashi 已提交
1762

1763
			model.name = THREE.PropertyBinding.sanitizeNodeName( node.attrName );
M
Mr.doob 已提交
1764
			model.FBX_ID = id;
Y
yamahigashi 已提交
1765

M
Mr.doob 已提交
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
			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 ) {

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

Y
yamahigashi 已提交
1781
			}
Y
yamahigashi 已提交
1782

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

L
Lewy Blue 已提交
1785
				var rotation = node.properties.Lcl_Rotation.value.map( THREE.Math.degToRad );
M
Mr.doob 已提交
1786 1787
				rotation.push( 'ZYX' );
				model.rotation.fromArray( rotation );
Y
yamahigashi 已提交
1788

M
Mr.doob 已提交
1789
			}
Y
yamahigashi 已提交
1790

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

1793
				model.scale.fromArray( node.properties.Lcl_Scaling.value );
Y
yamahigashi 已提交
1794

M
Mr.doob 已提交
1795
			}
Y
yamahigashi 已提交
1796

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

L
Lewy Blue 已提交
1799 1800 1801 1802 1803
				var array = node.properties.PreRotation.value.map( THREE.Math.degToRad );
				array[ 3 ] = 'ZYX';

				var preRotations = new THREE.Euler().fromArray( array );

M
Mr.doob 已提交
1804 1805 1806 1807 1808 1809 1810
				preRotations = new THREE.Quaternion().setFromEuler( preRotations );
				var currentRotation = new THREE.Quaternion().setFromEuler( model.rotation );
				preRotations.multiply( currentRotation );
				model.rotation.setFromQuaternion( preRotations, 'ZYX' );

			}

L
Lewy Blue 已提交
1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
			// allow transformed pivots - see https://github.com/mrdoob/three.js/issues/11895
			if ( 'GeometricTranslation' in node.properties ) {

				var array = node.properties.GeometricTranslation.value;

				model.traverse( function ( child ) {

					if ( child.geometry ) {

						child.geometry.translate( array[ 0 ], array[ 1 ], array[ 2 ] );

					}

				} );

			}

L
Lewy Blue 已提交
1828 1829 1830 1831 1832 1833 1834 1835
			if ( 'LookAtProperty' in node.properties ) {

				var conns = connections.get( model.FBX_ID );

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

					var child = conns.children[ childrenIndex ];

L
Lewy Blue 已提交
1836
					if ( child.relationship === 'LookAtProperty' ) {
L
Lewy Blue 已提交
1837 1838 1839 1840 1841

						var lookAtTarget = FBXTree.Objects.subNodes.Model[ child.ID ];

						if ( 'Lcl_Translation' in lookAtTarget.properties ) {

1842
							var pos = lookAtTarget.properties.Lcl_Translation.value;
L
Lewy Blue 已提交
1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864

							// DirectionalLight, SpotLight
							if ( model.target !== undefined ) {

								model.target.position.set( pos[ 0 ], pos[ 1 ], pos[ 2 ] );
								sceneGraph.add( model.target );


							} else { // Cameras and other Object3Ds

								model.lookAt( new THREE.Vector3( pos[ 0 ], pos[ 1 ], pos[ 2 ] ) );

							}

						}

					}

				}

			}

M
Mr.doob 已提交
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
			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 已提交
1877

Y
yamahigashi 已提交
1878
				}
Y
yamahigashi 已提交
1879

Y
yamahigashi 已提交
1880
			}
M
Mr.doob 已提交
1881
			if ( model.parent === null ) {
Y
yamahigashi 已提交
1882

M
Mr.doob 已提交
1883
				sceneGraph.add( model );
Y
yamahigashi 已提交
1884

M
Mr.doob 已提交
1885 1886 1887 1888 1889 1890 1891 1892
			}

		}


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

1893
		var worldMatrices = new Map();
M
Mr.doob 已提交
1894 1895

		// Put skeleton into bind pose.
1896
		if ( 'Pose' in FBXTree.Objects.subNodes ) {
M
Mr.doob 已提交
1897

1898 1899
			var BindPoseNode = FBXTree.Objects.subNodes.Pose;
			for ( var nodeID in BindPoseNode ) {
M
Mr.doob 已提交
1900

1901
				if ( BindPoseNode[ nodeID ].attrType === 'BindPose' ) {
Y
yamahigashi 已提交
1902

1903 1904
					BindPoseNode = BindPoseNode[ nodeID ];
					break;
Y
yamahigashi 已提交
1905

1906 1907 1908
				}

			}
Y
yamahigashi 已提交
1909

M
Mr.doob 已提交
1910
			var PoseNode = BindPoseNode.subNodes.PoseNode;
Y
yamahigashi 已提交
1911

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

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

1916
				var rawMatWrd = new THREE.Matrix4().fromArray( node.subNodes.Matrix.properties.a );
Y
yamahigashi 已提交
1917

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

M
Mr.doob 已提交
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937
			}

		}

		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;

				var bone = deformer.bones[ subDeformerIndex ];
				if ( ! worldMatrices.has( bone.FBX_ID ) ) {

					break;
Y
yamahigashi 已提交
1938

Y
yamahigashi 已提交
1939
				}
M
Mr.doob 已提交
1940 1941
				var mat = worldMatrices.get( bone.FBX_ID );
				bone.matrixWorld.copy( mat );
Y
yamahigashi 已提交
1942

Y
yamahigashi 已提交
1943
			}
Y
yamahigashi 已提交
1944

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

M
Mr.doob 已提交
1948 1949
			var conns = connections.get( deformer.FBX_ID );
			var parents = conns.parents;
Y
yamahigashi 已提交
1950

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

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

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

M
Mr.doob 已提交
1957 1958 1959 1960 1961 1962 1963 1964
					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 );
L
Lewy Blue 已提交
1965

M
Mr.doob 已提交
1966 1967 1968 1969 1970 1971
							model.bind( deformer.skeleton, model.matrixWorld );
							break;

						}

					}
Y
yamahigashi 已提交
1972

Y
yamahigashi 已提交
1973
				}
Y
yamahigashi 已提交
1974

Y
yamahigashi 已提交
1975
			}
Y
yamahigashi 已提交
1976

M
Mr.doob 已提交
1977
		}
Y
yamahigashi 已提交
1978

L
Lewy Blue 已提交
1979
		//Skeleton is now bound, return objects to starting world positions.
M
Mr.doob 已提交
1980
		sceneGraph.updateMatrixWorld( true );
Y
yamahigashi 已提交
1981

L
Lewy Blue 已提交
1982
		// Silly hack with the animation parsing. We're gonna pretend the scene graph has a skeleton
L
Lewy Blue 已提交
1983
		// to attach animations to, since FBX treats animations as animations for the entire scene,
M
Mr.doob 已提交
1984 1985 1986 1987
		// not just for individual objects.
		sceneGraph.skeleton = {
			bones: modelArray
		};
Y
yamahigashi 已提交
1988

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

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

L
Lewy Blue 已提交
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010

		// Parse ambient color - if it's not set to black (default), create an ambient light
		if ( 'GlobalSettings' in FBXTree && 'AmbientColor' in FBXTree.GlobalSettings.properties ) {

			var ambientColor = FBXTree.GlobalSettings.properties.AmbientColor.value;
			var r = ambientColor[ 0 ];
			var g = ambientColor[ 1 ];
			var b = ambientColor[ 2 ];

			if ( r !== 0 || g !== 0 || b !== 0 ) {

				var color = new THREE.Color( r, g, b );
				sceneGraph.add( new THREE.AmbientLight( color, 1 ) );

			}

		}

M
Mr.doob 已提交
2011
		return sceneGraph;
Y
yamahigashi 已提交
2012

M
Mr.doob 已提交
2013
	}
Y
yamahigashi 已提交
2014

L
Lewy Blue 已提交
2015 2016 2017 2018 2019
	// Parses animation information from nodes in
	// FBXTree.Objects.subNodes.AnimationCurve ( connected to AnimationCurveNode )
	// FBXTree.Objects.subNodes.AnimationCurveNode ( connected to AnimationLayer and an animated property in some other node )
	// FBXTree.Objects.subNodes.AnimationLayer ( connected to AnimationStack )
	// FBXTree.Objects.subNodes.AnimationStack
M
Mr.doob 已提交
2020 2021 2022 2023 2024 2025 2026
	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;

2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050
		var fps = 30; // default framerate

		if ( 'GlobalSettings' in FBXTree && 'TimeMode' in FBXTree.GlobalSettings.properties ) {

			/* Autodesk time mode documentation can be found here:
			*	http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/class_fbx_time.html,topicNumber=cpp_ref_class_fbx_time_html
			*/
			var timeModeEnum = [
				30, // 0: eDefaultMode
				120, // 1: eFrames120
				100, // 2: eFrames100
				60, // 3: eFrames60
				50, // 4: eFrames50
				48, // 5: eFrames48
				30, // 6: eFrames30 (black and white NTSC )
				30, // 7: eFrames30Drop
				29.97, // 8: eNTSCDropFrame
				29.97, // 90: eNTSCFullFrame
				25, // 10: ePal ( PAL/SECAM )
				24, // 11: eFrames24 (Film/Cinema)
				1, // 12: eFrames1000 (use for date time))
				23.976, // 13: eFilmFullFrame
				30, // 14: eCustom: use GlobalSettings.properties.CustomFrameRate.value
				96, // 15: eFrames96
L
Lewy Blue 已提交
2051
				72, // 16: eFrames72
2052 2053 2054 2055 2056 2057 2058 2059 2060
				59.94, // 17: eFrames59dot94
			];

			var eMode = FBXTree.GlobalSettings.properties.TimeMode.value;

			if ( eMode === 14 ) {

				if ( 'CustomFrameRate' in FBXTree.GlobalSettings.properties ) {

L
Lewy Blue 已提交
2061
					fps = FBXTree.GlobalSettings.properties.CustomFrameRate.value;
2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075

					fps = ( fps === - 1 ) ? 30 : fps;

				}

			} else if ( eMode <= 17 ) { // for future proofing - if more eModes get added, they will default to 30fps

				fps = timeModeEnum[ eMode ];

			}

		}


M
Mr.doob 已提交
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 2162 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 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 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 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 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 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 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
		/**
		 * @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,
2449
			fps: fps,
M
Mr.doob 已提交
2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461
			frames: 0
		};

		var animationCurveNodes = [];
		for ( var nodeID in rawNodes ) {

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

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

			}
Y
yamahigashi 已提交
2462

M
Mr.doob 已提交
2463 2464 2465 2466
		}

		var tmpMap = new Map();
		for ( var animationCurveNodeIndex = 0; animationCurveNodeIndex < animationCurveNodes.length; ++ animationCurveNodeIndex ) {
Y
yamahigashi 已提交
2467

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

M
Mr.doob 已提交
2470
				continue;
Y
yamahigashi 已提交
2471

M
Mr.doob 已提交
2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504
			}
			tmpMap.set( animationCurveNodes[ animationCurveNodeIndex ].id, animationCurveNodes[ animationCurveNodeIndex ] );

		}

		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 已提交
2505

Y
yamahigashi 已提交
2506
				} else {
Y
yamahigashi 已提交
2507

M
Mr.doob 已提交
2508
					continue;
Y
yamahigashi 已提交
2509

Y
yamahigashi 已提交
2510
				}
Y
yamahigashi 已提交
2511

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

Y
yamahigashi 已提交
2514
			}
Y
yamahigashi 已提交
2515

M
Mr.doob 已提交
2516
		}
Y
yamahigashi 已提交
2517

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

M
Mr.doob 已提交
2520 2521
			var id = curveNode.containerBoneID;
			if ( ! returnObject.curves.has( id ) ) {
Y
yamahigashi 已提交
2522

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

M
Mr.doob 已提交
2525 2526
			}
			returnObject.curves.get( id )[ curveNode.attr ] = curveNode;
2527

M
Mr.doob 已提交
2528
			if ( curveNode.attr === 'R' ) {
Y
yamahigashi 已提交
2529

M
Mr.doob 已提交
2530
				var curves = curveNode.curves;
2531

L
Lewy Blue 已提交
2532 2533
				// Some FBX files have an AnimationCurveNode
				// which isn't any connected to any AnimationCurve.
2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
				// 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 ]
					};

				}

L
Lewy Blue 已提交
2566 2567 2568
				curves.x.values = curves.x.values.map( THREE.Math.degToRad );
				curves.y.values = curves.y.values.map( THREE.Math.degToRad );
				curves.z.values = curves.z.values.map( THREE.Math.degToRad );
Y
yamahigashi 已提交
2569

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

M
Mr.doob 已提交
2572 2573 2574 2575 2576
					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 已提交
2577

M
Mr.doob 已提交
2578 2579 2580 2581 2582 2583
						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 已提交
2584

M
Mr.doob 已提交
2585 2586 2587
					}

				}
Y
yamahigashi 已提交
2588

Y
yamahigashi 已提交
2589
			}
Y
yamahigashi 已提交
2590

M
Mr.doob 已提交
2591
		} );
Y
yamahigashi 已提交
2592

M
Mr.doob 已提交
2593 2594 2595 2596
		for ( var nodeID in rawLayers ) {

			var layer = [];
			var children = connections.get( parseInt( nodeID ) ).children;
Y
yamahigashi 已提交
2597

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

M
Mr.doob 已提交
2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617
				// 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 已提交
2618

Y
yamahigashi 已提交
2619
			}
Y
yamahigashi 已提交
2620

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

M
Mr.doob 已提交
2623
		}
Y
yamahigashi 已提交
2624

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

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

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

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

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

M
Mr.doob 已提交
2637
					layers.push( currentLayer );
Y
yamahigashi 已提交
2638

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

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

M
Mr.doob 已提交
2643
						if ( layer ) {
Y
yamahigashi 已提交
2644

M
Mr.doob 已提交
2645 2646 2647 2648 2649 2650 2651
							getCurveNodeMaxMinTimeStamps( layer, timestamps );

						}

					}

				}
Y
yamahigashi 已提交
2652

M
Mr.doob 已提交
2653 2654 2655 2656 2657 2658 2659 2660 2661
			}

			// 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,
2662
					frames: ( timestamps.max - timestamps.min ) * returnObject.fps
M
Mr.doob 已提交
2663
				};
Y
yamahigashi 已提交
2664

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

M
Mr.doob 已提交
2667
		}
Y
yamahigashi 已提交
2668

M
Mr.doob 已提交
2669
		return returnObject;
Y
yamahigashi 已提交
2670

Y
yamahigashi 已提交
2671
	}
Y
yamahigashi 已提交
2672

M
Mr.doob 已提交
2673 2674 2675 2676 2677 2678
	function parseAnimationNode( FBXTree, animationCurveNode, connections, sceneGraph ) {

		var rawModels = FBXTree.Objects.subNodes.Model;

		var returnObject = {

L
Lewy Blue 已提交
2679
			id: animationCurveNode.id,
M
Mr.doob 已提交
2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692
			attr: animationCurveNode.attrName,
			internalID: animationCurveNode.id,
			attrX: false,
			attrY: false,
			attrZ: false,
			containerBoneID: - 1,
			containerID: - 1,
			curves: {
				x: null,
				y: null,
				z: null
			},
			preRotations: null
L
Lewy Blue 已提交
2693

M
Mr.doob 已提交
2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707
		};

		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 已提交
2708

M
Mr.doob 已提交
2709 2710
				}
				if ( attributeKey.match( /Z/ ) ) {
Y
yamahigashi 已提交
2711

M
Mr.doob 已提交
2712
					returnObject.attrZ = true;
Y
yamahigashi 已提交
2713

M
Mr.doob 已提交
2714
				}
Y
yamahigashi 已提交
2715

M
Mr.doob 已提交
2716
			}
Y
yamahigashi 已提交
2717

M
Mr.doob 已提交
2718
		} else {
Y
yamahigashi 已提交
2719

M
Mr.doob 已提交
2720
			return null;
Y
yamahigashi 已提交
2721

M
Mr.doob 已提交
2722
		}
Y
yamahigashi 已提交
2723

M
Mr.doob 已提交
2724 2725
		var conns = connections.get( returnObject.id );
		var containerIndices = conns.parents;
Y
yamahigashi 已提交
2726

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

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

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

M
Mr.doob 已提交
2733 2734
			} );
			if ( boneID > - 1 ) {
Y
yamahigashi 已提交
2735

M
Mr.doob 已提交
2736 2737 2738 2739
				returnObject.containerBoneID = boneID;
				returnObject.containerID = containerIndices[ containerIndicesIndex ].ID;
				var model = rawModels[ returnObject.containerID.toString() ];
				if ( 'PreRotation' in model.properties ) {
Y
yamahigashi 已提交
2740

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

Y
yamahigashi 已提交
2743
				}
M
Mr.doob 已提交
2744
				break;
Y
yamahigashi 已提交
2745

Y
yamahigashi 已提交
2746
			}
Y
yamahigashi 已提交
2747

Y
yamahigashi 已提交
2748
		}
Y
yamahigashi 已提交
2749

M
Mr.doob 已提交
2750
		return returnObject;
Y
yamahigashi 已提交
2751

M
Mr.doob 已提交
2752
	}
Y
yamahigashi 已提交
2753

M
Mr.doob 已提交
2754
	function parseAnimationCurve( animationCurve ) {
Y
yamahigashi 已提交
2755

M
Mr.doob 已提交
2756 2757 2758 2759
		return {
			version: null,
			id: animationCurve.id,
			internalID: animationCurve.id,
2760 2761
			times: animationCurve.subNodes.KeyTime.properties.a.map( convertFBXTimeToSeconds ),
			values: animationCurve.subNodes.KeyValueFloat.properties.a,
M
Mr.doob 已提交
2762

2763
			attrFlag: animationCurve.subNodes.KeyAttrFlags.properties.a,
2764
			attrData: animationCurve.subNodes.KeyAttrDataFloat.properties.a,
M
Mr.doob 已提交
2765
		};
Y
yamahigashi 已提交
2766

M
Mr.doob 已提交
2767
	}
Y
yamahigashi 已提交
2768

L
Lewy Blue 已提交
2769 2770
	// Sets the maxTimeStamp and minTimeStamp variables if it has timeStamps that are either larger or smaller
	// than the max or min respectively.
M
Mr.doob 已提交
2771 2772 2773 2774 2775
	function getCurveNodeMaxMinTimeStamps( layer, timestamps ) {

		if ( layer.R ) {

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

M
Mr.doob 已提交
2777 2778
		}
		if ( layer.S ) {
Y
yamahigashi 已提交
2779

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

M
Mr.doob 已提交
2782 2783
		}
		if ( layer.T ) {
Y
yamahigashi 已提交
2784

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

M
Mr.doob 已提交
2787
		}
Y
yamahigashi 已提交
2788

M
Mr.doob 已提交
2789
	}
Y
yamahigashi 已提交
2790

L
Lewy Blue 已提交
2791 2792
	// Sets the maxTimeStamp and minTimeStamp if one of the curve's time stamps
	// exceeds the maximum or minimum.
M
Mr.doob 已提交
2793
	function getCurveMaxMinTimeStamp( curve, timestamps ) {
Y
yamahigashi 已提交
2794

M
Mr.doob 已提交
2795
		if ( curve.x ) {
Y
yamahigashi 已提交
2796

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

Y
yamahigashi 已提交
2799
		}
M
Mr.doob 已提交
2800
		if ( curve.y ) {
Y
yamahigashi 已提交
2801

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

M
Mr.doob 已提交
2804 2805
		}
		if ( curve.z ) {
2806

M
Mr.doob 已提交
2807
			getCurveAxisMaxMinTimeStamps( curve.z, timestamps );
2808

M
Mr.doob 已提交
2809
		}
2810

M
Mr.doob 已提交
2811
	}
Y
yamahigashi 已提交
2812

L
Lewy Blue 已提交
2813
	// Sets the maxTimeStamp and minTimeStamp if one of its timestamps exceeds the maximum or minimum.
M
Mr.doob 已提交
2814
	function getCurveAxisMaxMinTimeStamps( axis, timestamps ) {
Y
yamahigashi 已提交
2815

M
Mr.doob 已提交
2816 2817
		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 已提交
2818

M
Mr.doob 已提交
2819
	}
Y
yamahigashi 已提交
2820

M
Mr.doob 已提交
2821 2822 2823 2824 2825
	function addAnimations( group, animations ) {

		if ( group.animations === undefined ) {

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

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

M
Mr.doob 已提交
2829 2830 2831 2832 2833 2834 2835 2836
		var stacks = animations.stacks;

		for ( var key in stacks ) {

			var stack = stacks[ key ];

			var animationData = {
				name: stack.name,
2837
				fps: animations.fps,
M
Mr.doob 已提交
2838 2839 2840
				length: stack.length,
				hierarchy: []
			};
Y
yamahigashi 已提交
2841

M
Mr.doob 已提交
2842
			var bones = group.skeleton.bones;
Y
yamahigashi 已提交
2843

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

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

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

M
Mr.doob 已提交
2851
					return bone.parent === parentBone;
Y
yamahigashi 已提交
2852

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

Y
yamahigashi 已提交
2856
			}
Y
yamahigashi 已提交
2857

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

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

M
Mr.doob 已提交
2862 2863
					var bone = bones[ bonesIndex ];
					var boneIndex = bonesIndex;
Y
yamahigashi 已提交
2864

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

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

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

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

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

M
Mr.doob 已提交
2875
						}
Y
yamahigashi 已提交
2876

M
Mr.doob 已提交
2877
					}
Y
yamahigashi 已提交
2878

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

Y
yamahigashi 已提交
2881
			}
Y
yamahigashi 已提交
2882

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

Y
yamahigashi 已提交
2885
		}
Y
yamahigashi 已提交
2886

M
Mr.doob 已提交
2887
	}
Y
yamahigashi 已提交
2888

M
Mr.doob 已提交
2889 2890
	var euler = new THREE.Euler();
	var quaternion = new THREE.Quaternion();
Y
yamahigashi 已提交
2891

M
Mr.doob 已提交
2892
	function generateKey( animations, animationNode, bone, frame ) {
Y
yamahigashi 已提交
2893

M
Mr.doob 已提交
2894 2895 2896 2897 2898 2899 2900 2901
		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 已提交
2902

L
Lewy Blue 已提交
2903 2904
		euler.setFromQuaternion( bone.quaternion, 'ZYX', false );

M
Mr.doob 已提交
2905
		try {
Y
yamahigashi 已提交
2906

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

2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925
				if ( animationNode.T.curves.x.values[ frame ] ) {

					key.pos[ 0 ] = animationNode.T.curves.x.values[ frame ];

				}

				if ( animationNode.T.curves.y.values[ frame ] ) {

					key.pos[ 1 ] = animationNode.T.curves.y.values[ frame ];

				}

				if ( animationNode.T.curves.z.values[ frame ] ) {

					key.pos[ 2 ] = animationNode.T.curves.z.values[ frame ];

				}
Y
yamahigashi 已提交
2926

M
Mr.doob 已提交
2927
			}
Y
yamahigashi 已提交
2928

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

2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948
				// Only update the euler's values if rotation is defined for the axis on this frame
				if ( animationNode.R.curves.x.values[ frame ] ) {

					euler.x = animationNode.R.curves.x.values[ frame ];

				}

				if ( animationNode.R.curves.y.values[ frame ] ) {

					euler.y = animationNode.R.curves.y.values[ frame ];

				}

				if ( animationNode.R.curves.z.values[ frame ] ) {

					euler.z = animationNode.R.curves.z.values[ frame ];

				}
M
Mr.doob 已提交
2949

2950
				quaternion.setFromEuler( euler );
M
Mr.doob 已提交
2951
				key.rot = quaternion.toArray();
Y
yamahigashi 已提交
2952

Y
yamahigashi 已提交
2953
			}
Y
yamahigashi 已提交
2954

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

2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973
				if ( animationNode.T.curves.x.values[ frame ] ) {

					key.scl[ 0 ] = animationNode.S.curves.x.values[ frame ];

				}

				if ( animationNode.T.curves.y.values[ frame ] ) {

					key.scl[ 1 ] = animationNode.S.curves.y.values[ frame ];

				}

				if ( animationNode.T.curves.z.values[ frame ] ) {

					key.scl[ 2 ] = animationNode.S.curves.z.values[ frame ];

				}
Y
yamahigashi 已提交
2974

M
Mr.doob 已提交
2975
			}
Y
yamahigashi 已提交
2976

M
Mr.doob 已提交
2977
		} catch ( error ) {
Y
yamahigashi 已提交
2978

M
Mr.doob 已提交
2979
			// Curve is not fully plotted.
M
Mugen87 已提交
2980 2981
			console.log( 'THREE.FBXLoader: ', bone );
			console.log( 'THREE.FBXLoader: ', error );
Y
yamahigashi 已提交
2982

Y
yamahigashi 已提交
2983
		}
Y
yamahigashi 已提交
2984

M
Mr.doob 已提交
2985
		return key;
2986

M
Mr.doob 已提交
2987
	}
2988

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

M
Mr.doob 已提交
2991
	function hasCurve( animationNode, attribute ) {
2992

M
Mr.doob 已提交
2993
		if ( animationNode === undefined ) {
2994

M
Mr.doob 已提交
2995 2996 2997
			return false;

		}
Y
yamahigashi 已提交
2998

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

M
Mr.doob 已提交
3001
		if ( ! attributeNode ) {
Y
yamahigashi 已提交
3002

M
Mr.doob 已提交
3003
			return false;
Y
yamahigashi 已提交
3004

Y
yamahigashi 已提交
3005
		}
Y
yamahigashi 已提交
3006

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

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

M
Mr.doob 已提交
3011
		} );
Y
yamahigashi 已提交
3012

M
Mr.doob 已提交
3013
	}
Y
yamahigashi 已提交
3014

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

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

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

M
Mr.doob 已提交
3021
		} );
Y
yamahigashi 已提交
3022

M
Mr.doob 已提交
3023
	}
Y
yamahigashi 已提交
3024

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

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

M
Mr.doob 已提交
3029
	}
Y
yamahigashi 已提交
3030

L
Lewy Blue 已提交
3031
	// parse an FBX file in ASCII format
L
Lewy Blue 已提交
3032
	function TextParser() {}
Y
yamahigashi 已提交
3033

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

M
Mr.doob 已提交
3036
		getPrevNode: function () {
Y
yamahigashi 已提交
3037

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

M
Mr.doob 已提交
3040
		},
Y
yamahigashi 已提交
3041

M
Mr.doob 已提交
3042
		getCurrentNode: function () {
Y
yamahigashi 已提交
3043

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

M
Mr.doob 已提交
3046
		},
Y
yamahigashi 已提交
3047

M
Mr.doob 已提交
3048
		getCurrentProp: function () {
Y
yamahigashi 已提交
3049

M
Mr.doob 已提交
3050
			return this.currentProp;
Y
yamahigashi 已提交
3051

M
Mr.doob 已提交
3052
		},
Y
yamahigashi 已提交
3053

M
Mr.doob 已提交
3054
		pushStack: function ( node ) {
Y
yamahigashi 已提交
3055

M
Mr.doob 已提交
3056 3057
			this.nodeStack.push( node );
			this.currentIndent += 1;
Y
yamahigashi 已提交
3058

M
Mr.doob 已提交
3059
		},
Y
yamahigashi 已提交
3060

M
Mr.doob 已提交
3061
		popStack: function () {
Y
yamahigashi 已提交
3062

M
Mr.doob 已提交
3063 3064
			this.nodeStack.pop();
			this.currentIndent -= 1;
Y
yamahigashi 已提交
3065

M
Mr.doob 已提交
3066
		},
Y
yamahigashi 已提交
3067

M
Mr.doob 已提交
3068
		setCurrentProp: function ( val, name ) {
Y
yamahigashi 已提交
3069

M
Mr.doob 已提交
3070 3071
			this.currentProp = val;
			this.currentPropName = name;
Y
yamahigashi 已提交
3072

M
Mr.doob 已提交
3073
		},
Y
yamahigashi 已提交
3074

M
Mr.doob 已提交
3075
		parse: function ( text ) {
Y
yamahigashi 已提交
3076

M
Mr.doob 已提交
3077 3078 3079 3080 3081
			this.currentIndent = 0;
			this.allNodes = new FBXTree();
			this.nodeStack = [];
			this.currentProp = [];
			this.currentPropName = '';
Y
yamahigashi 已提交
3082

M
Mugen87 已提交
3083
			var split = text.split( '\n' );
Y
yamahigashi 已提交
3084

3085
			for ( var lineNum = 0, lineLength = split.length; lineNum < lineLength; lineNum ++ ) {
Y
yamahigashi 已提交
3086

3087
				var l = split[ lineNum ];
Y
yamahigashi 已提交
3088

3089
				// skip comment line
M
Mr.doob 已提交
3090 3091 3092
				if ( l.match( /^[\s\t]*;/ ) ) {

					continue;
Y
yamahigashi 已提交
3093

3094 3095 3096
				}

				// skip empty line
M
Mr.doob 已提交
3097
				if ( l.match( /^[\s\t]*$/ ) ) {
Y
yamahigashi 已提交
3098

M
Mr.doob 已提交
3099
					continue;
Y
yamahigashi 已提交
3100

3101
				}
Y
yamahigashi 已提交
3102

M
Mr.doob 已提交
3103
				// beginning of node
M
Mugen87 已提交
3104
				var beginningOfNodeExp = new RegExp( '^\\t{' + this.currentIndent + '}(\\w+):(.*){', '' );
M
Mr.doob 已提交
3105
				var match = l.match( beginningOfNodeExp );
3106

M
Mr.doob 已提交
3107
				if ( match ) {
Y
yamahigashi 已提交
3108

M
Mugen87 已提交
3109
					var nodeName = match[ 1 ].trim().replace( /^"/, '' ).replace( /"$/, '' );
M
Mr.doob 已提交
3110
					var nodeAttrs = match[ 2 ].split( ',' );
Y
yamahigashi 已提交
3111

M
Mr.doob 已提交
3112
					for ( var i = 0, l = nodeAttrs.length; i < l; i ++ ) {
L
Lewy Blue 已提交
3113

M
Mr.doob 已提交
3114
						nodeAttrs[ i ] = nodeAttrs[ i ].trim().replace( /^"/, '' ).replace( /"$/, '' );
L
Lewy Blue 已提交
3115

M
Mr.doob 已提交
3116 3117 3118 3119 3120 3121
					}

					this.parseNodeBegin( l, nodeName, nodeAttrs || null );
					continue;

				}
Y
yamahigashi 已提交
3122

M
Mr.doob 已提交
3123
				// node's property
M
Mugen87 已提交
3124
				var propExp = new RegExp( '^\\t{' + ( this.currentIndent ) + '}(\\w+):[\\s\\t\\r\\n](.*)' );
M
Mr.doob 已提交
3125
				var match = l.match( propExp );
3126

M
Mr.doob 已提交
3127
				if ( match ) {
Y
yamahigashi 已提交
3128

M
Mugen87 已提交
3129 3130
					var propName = match[ 1 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
					var propValue = match[ 2 ].replace( /^"/, '' ).replace( /"$/, '' ).trim();
Y
yamahigashi 已提交
3131

3132 3133 3134 3135 3136
					// for special case: base64 image data follows "Content: ," line
					//	Content: ,
					//	 "iVB..."
					if ( propName === 'Content' && propValue === ',' ) {

L
Lewy Blue 已提交
3137
						propValue = split[ ++ lineNum ].replace( /"/g, '' ).replace( /,$/, '' ).trim();
3138 3139 3140

					}

M
Mr.doob 已提交
3141 3142
					this.parseNodeProperty( l, propName, propValue );
					continue;
Y
yamahigashi 已提交
3143

M
Mr.doob 已提交
3144
				}
Y
yamahigashi 已提交
3145

M
Mr.doob 已提交
3146
				// end of node
M
Mugen87 已提交
3147
				var endOfNodeExp = new RegExp( '^\\t{' + ( this.currentIndent - 1 ) + '}}' );
3148

M
Mr.doob 已提交
3149
				if ( l.match( endOfNodeExp ) ) {
Y
yamahigashi 已提交
3150

M
Mr.doob 已提交
3151 3152
					this.nodeEnd();
					continue;
Y
yamahigashi 已提交
3153

Y
yamahigashi 已提交
3154
				}
Y
yamahigashi 已提交
3155

3156 3157
				// large arrays are split over multiple lines terminated with a ',' character
				// if this is encountered the line needs to be joined to the previous line
M
Mr.doob 已提交
3158
				if ( l.match( /^[^\s\t}]/ ) ) {
Y
yamahigashi 已提交
3159

M
Mr.doob 已提交
3160
					this.parseNodePropertyContinued( l );
Y
yamahigashi 已提交
3161

M
Mr.doob 已提交
3162
				}
Y
yamahigashi 已提交
3163

Y
yamahigashi 已提交
3164
			}
Y
yamahigashi 已提交
3165

M
Mr.doob 已提交
3166
			return this.allNodes;
Y
yamahigashi 已提交
3167

M
Mr.doob 已提交
3168
		},
Y
yamahigashi 已提交
3169

M
Mr.doob 已提交
3170
		parseNodeBegin: function ( line, nodeName, nodeAttrs ) {
Y
yamahigashi 已提交
3171

M
Mr.doob 已提交
3172 3173 3174
			var node = { 'name': nodeName, properties: {}, 'subNodes': {} };
			var attrs = this.parseNodeAttr( nodeAttrs );
			var currentNode = this.getCurrentNode();
Y
yamahigashi 已提交
3175

M
Mr.doob 已提交
3176 3177
			// a top node
			if ( this.currentIndent === 0 ) {
Y
yamahigashi 已提交
3178

M
Mr.doob 已提交
3179
				this.allNodes.add( nodeName, node );
Y
yamahigashi 已提交
3180

3181
			} else { // a subnode
Y
yamahigashi 已提交
3182

3183
				// if the subnode already exists, append it
M
Mr.doob 已提交
3184
				if ( nodeName in currentNode.subNodes ) {
Y
yamahigashi 已提交
3185

M
Mr.doob 已提交
3186
					var tmp = currentNode.subNodes[ nodeName ];
Y
yamahigashi 已提交
3187

M
Mr.doob 已提交
3188
					if ( this.isFlattenNode( currentNode.subNodes[ nodeName ] ) ) {
Y
yamahigashi 已提交
3189

M
Mr.doob 已提交
3190
						if ( attrs.id === '' ) {
Y
yamahigashi 已提交
3191

M
Mr.doob 已提交
3192 3193
							currentNode.subNodes[ nodeName ] = [];
							currentNode.subNodes[ nodeName ].push( tmp );
Y
yamahigashi 已提交
3194

M
Mr.doob 已提交
3195
						} else {
Y
yamahigashi 已提交
3196

M
Mr.doob 已提交
3197 3198
							currentNode.subNodes[ nodeName ] = {};
							currentNode.subNodes[ nodeName ][ tmp.id ] = tmp;
Y
yamahigashi 已提交
3199

M
Mr.doob 已提交
3200
						}
Y
yamahigashi 已提交
3201

M
Mr.doob 已提交
3202
					}
Y
yamahigashi 已提交
3203

M
Mr.doob 已提交
3204
					if ( attrs.id === '' ) {
Y
yamahigashi 已提交
3205

M
Mr.doob 已提交
3206
						currentNode.subNodes[ nodeName ].push( node );
3207

M
Mr.doob 已提交
3208
					} else {
Y
yamahigashi 已提交
3209

M
Mr.doob 已提交
3210
						currentNode.subNodes[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
3211

M
Mr.doob 已提交
3212
					}
Y
yamahigashi 已提交
3213

M
Mr.doob 已提交
3214
				} else if ( typeof attrs.id === 'number' || attrs.id.match( /^\d+$/ ) ) {
Y
yamahigashi 已提交
3215

M
Mr.doob 已提交
3216 3217
					currentNode.subNodes[ nodeName ] = {};
					currentNode.subNodes[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
3218

M
Mr.doob 已提交
3219
				} else {
Y
yamahigashi 已提交
3220

M
Mr.doob 已提交
3221
					currentNode.subNodes[ nodeName ] = node;
Y
yamahigashi 已提交
3222

M
Mr.doob 已提交
3223
				}
K
Kyle Larson 已提交
3224

Y
yamahigashi 已提交
3225
			}
Y
yamahigashi 已提交
3226

3227

L
Lewy Blue 已提交
3228
			// for this	↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
M
Mr.doob 已提交
3229 3230
			// NodeAttribute: 1001463072, "NodeAttribute::", "LimbNode" {
			if ( nodeAttrs ) {
Y
yamahigashi 已提交
3231

M
Mr.doob 已提交
3232 3233 3234
				node.id = attrs.id;
				node.attrName = attrs.name;
				node.attrType = attrs.type;
K
Kyle Larson 已提交
3235

M
Mr.doob 已提交
3236
			}
K
Kyle Larson 已提交
3237

M
Mr.doob 已提交
3238
			this.pushStack( node );
K
Kyle Larson 已提交
3239

M
Mr.doob 已提交
3240
		},
K
Kyle Larson 已提交
3241

M
Mr.doob 已提交
3242
		parseNodeAttr: function ( attrs ) {
K
Kyle Larson 已提交
3243

M
Mr.doob 已提交
3244
			var id = attrs[ 0 ];
K
Kyle Larson 已提交
3245

M
Mugen87 已提交
3246
			if ( attrs[ 0 ] !== '' ) {
Y
yamahigashi 已提交
3247

M
Mr.doob 已提交
3248
				id = parseInt( attrs[ 0 ] );
Y
yamahigashi 已提交
3249

M
Mr.doob 已提交
3250
				if ( isNaN( id ) ) {
Y
yamahigashi 已提交
3251

M
Mr.doob 已提交
3252
					id = attrs[ 0 ];
Y
yamahigashi 已提交
3253

M
Mr.doob 已提交
3254
				}
Y
yamahigashi 已提交
3255

M
Mr.doob 已提交
3256
			}
Y
yamahigashi 已提交
3257

M
Mr.doob 已提交
3258
			var name = '', type = '';
Y
yamahigashi 已提交
3259

M
Mr.doob 已提交
3260
			if ( attrs.length > 1 ) {
Y
yamahigashi 已提交
3261

M
Mr.doob 已提交
3262 3263
				name = attrs[ 1 ].replace( /^(\w+)::/, '' );
				type = attrs[ 2 ];
Y
yamahigashi 已提交
3264

M
Mr.doob 已提交
3265
			}
Y
yamahigashi 已提交
3266

M
Mr.doob 已提交
3267
			return { id: id, name: name, type: type };
Y
yamahigashi 已提交
3268

M
Mr.doob 已提交
3269
		},
Y
yamahigashi 已提交
3270

M
Mr.doob 已提交
3271
		parseNodeProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
3272

M
Mr.doob 已提交
3273 3274
			var currentNode = this.getCurrentNode();
			var parentName = currentNode.name;
Y
yamahigashi 已提交
3275

3276 3277
			// special case where the parent node is something like "Properties70"
			// these children nodes must treated carefully
M
Mr.doob 已提交
3278
			if ( parentName !== undefined ) {
Y
yamahigashi 已提交
3279

M
Mr.doob 已提交
3280 3281
				var propMatch = parentName.match( /Properties(\d)+/ );
				if ( propMatch ) {
Y
yamahigashi 已提交
3282

M
Mr.doob 已提交
3283 3284
					this.parseNodeSpecialProperty( line, propName, propValue );
					return;
Y
yamahigashi 已提交
3285

M
Mr.doob 已提交
3286
				}
Y
yamahigashi 已提交
3287

M
Mr.doob 已提交
3288
			}
Y
yamahigashi 已提交
3289

3290
			// Connections
M
Mugen87 已提交
3291
			if ( propName === 'C' ) {
Y
yamahigashi 已提交
3292

M
Mr.doob 已提交
3293 3294 3295
				var connProps = propValue.split( ',' ).slice( 1 );
				var from = parseInt( connProps[ 0 ] );
				var to = parseInt( connProps[ 1 ] );
Y
yamahigashi 已提交
3296

M
Mr.doob 已提交
3297
				var rest = propValue.split( ',' ).slice( 3 );
Y
yamahigashi 已提交
3298

3299 3300 3301 3302 3303 3304
				rest = rest.map( function ( elem ) {

					return elem.trim().replace( /^"/, '' );

				} );

M
Mr.doob 已提交
3305 3306 3307
				propName = 'connections';
				propValue = [ from, to ];
				append( propValue, rest );
Y
yamahigashi 已提交
3308

M
Mr.doob 已提交
3309
				if ( currentNode.properties[ propName ] === undefined ) {
Y
yamahigashi 已提交
3310

M
Mr.doob 已提交
3311
					currentNode.properties[ propName ] = [];
Y
yamahigashi 已提交
3312

M
Mr.doob 已提交
3313
				}
Y
yamahigashi 已提交
3314

M
Mr.doob 已提交
3315
			}
Y
yamahigashi 已提交
3316

3317
			// Node
M
Mugen87 已提交
3318
			if ( propName === 'Node' ) {
Y
yamahigashi 已提交
3319

M
Mr.doob 已提交
3320 3321 3322
				var id = parseInt( propValue );
				currentNode.properties.id = id;
				currentNode.id = id;
Y
yamahigashi 已提交
3323

M
Mr.doob 已提交
3324
			}
Y
yamahigashi 已提交
3325

M
Mr.doob 已提交
3326 3327
			// already exists in properties, then append this
			if ( propName in currentNode.properties ) {
Y
yamahigashi 已提交
3328

M
Mr.doob 已提交
3329
				if ( Array.isArray( currentNode.properties[ propName ] ) ) {
Y
yamahigashi 已提交
3330

M
Mr.doob 已提交
3331
					currentNode.properties[ propName ].push( propValue );
Y
yamahigashi 已提交
3332

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

M
Mr.doob 已提交
3335
					currentNode.properties[ propName ] += propValue;
Y
yamahigashi 已提交
3336

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

M
Mr.doob 已提交
3339
			} else {
Y
yamahigashi 已提交
3340

M
Mr.doob 已提交
3341
				if ( Array.isArray( currentNode.properties[ propName ] ) ) {
Y
yamahigashi 已提交
3342

M
Mr.doob 已提交
3343
					currentNode.properties[ propName ].push( propValue );
Y
yamahigashi 已提交
3344

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

M
Mr.doob 已提交
3347
					currentNode.properties[ propName ] = propValue;
Y
yamahigashi 已提交
3348

M
Mr.doob 已提交
3349
				}
Y
yamahigashi 已提交
3350

M
Mr.doob 已提交
3351
			}
Y
yamahigashi 已提交
3352

M
Mr.doob 已提交
3353
			this.setCurrentProp( currentNode.properties, propName );
Y
yamahigashi 已提交
3354

3355 3356 3357 3358 3359 3360 3361
			// convert string to array, unless it ends in ',' in which case more will be added to it
			if ( propName === 'a' && propValue.slice( - 1 ) !== ',' ) {

				currentNode.properties.a = parseNumberArray( propValue );

			}

M
Mr.doob 已提交
3362
		},
Y
yamahigashi 已提交
3363

M
Mr.doob 已提交
3364
		parseNodePropertyContinued: function ( line ) {
Y
yamahigashi 已提交
3365

M
Mr.doob 已提交
3366
			this.currentProp[ this.currentPropName ] += line;
Y
yamahigashi 已提交
3367

3368 3369 3370 3371 3372 3373 3374 3375 3376
			// if the line doesn't end in ',' we have reached the end of the property value
			// so convert the string to an array
			if ( line.slice( - 1 ) !== ',' ) {

				var currentNode = this.getCurrentNode();
				currentNode.properties.a = parseNumberArray( currentNode.properties.a );

			}

M
Mr.doob 已提交
3377
		},
Y
yamahigashi 已提交
3378

M
Mr.doob 已提交
3379
		parseNodeSpecialProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
3380

M
Mr.doob 已提交
3381 3382 3383 3384 3385
			// 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 已提交
3386

M
Mr.doob 已提交
3387
			for ( var i = 0, l = props.length; i < l; i ++ ) {
L
Lewy Blue 已提交
3388

M
Mr.doob 已提交
3389
				props[ i ] = props[ i ].trim().replace( /^\"/, '' ).replace( /\s/, '_' );
L
Lewy Blue 已提交
3390

Y
yamahigashi 已提交
3391 3392
			}

M
Mr.doob 已提交
3393 3394 3395 3396 3397
			var innerPropName = props[ 0 ];
			var innerPropType1 = props[ 1 ];
			var innerPropType2 = props[ 2 ];
			var innerPropFlag = props[ 3 ];
			var innerPropValue = props[ 4 ];
Y
yamahigashi 已提交
3398

M
Mr.doob 已提交
3399 3400 3401 3402 3403
			/*
			if ( innerPropValue === undefined ) {
				innerPropValue = props[3];
			}
			*/
Y
yamahigashi 已提交
3404

3405
			// cast value to its type
M
Mr.doob 已提交
3406
			switch ( innerPropType1 ) {
Y
yamahigashi 已提交
3407

M
Mugen87 已提交
3408
				case 'int':
3409 3410 3411
				case 'enum':
				case 'bool':
				case 'ULongLong':
M
Mr.doob 已提交
3412 3413
					innerPropValue = parseInt( innerPropValue );
					break;
Y
yamahigashi 已提交
3414

M
Mugen87 已提交
3415
				case 'double':
3416 3417
				case 'Number':
				case 'FieldOfView':
M
Mr.doob 已提交
3418 3419
					innerPropValue = parseFloat( innerPropValue );
					break;
Y
yamahigashi 已提交
3420

M
Mugen87 已提交
3421 3422
				case 'ColorRGB':
				case 'Vector3D':
3423 3424 3425
				case 'Lcl_Translation':
				case 'Lcl_Rotation':
				case 'Lcl_Scaling':
3426
					innerPropValue = parseNumberArray( innerPropValue );
M
Mr.doob 已提交
3427
					break;
Y
yamahigashi 已提交
3428

M
Mr.doob 已提交
3429
			}
Y
yamahigashi 已提交
3430

M
Mr.doob 已提交
3431 3432
			// CAUTION: these props must append to parent's parent
			this.getPrevNode().properties[ innerPropName ] = {
Y
yamahigashi 已提交
3433

M
Mr.doob 已提交
3434 3435 3436 3437
				'type': innerPropType1,
				'type2': innerPropType2,
				'flag': innerPropFlag,
				'value': innerPropValue
Y
yamahigashi 已提交
3438

M
Mr.doob 已提交
3439
			};
Y
yamahigashi 已提交
3440

M
Mr.doob 已提交
3441
			this.setCurrentProp( this.getPrevNode().properties, innerPropName );
Y
yamahigashi 已提交
3442

M
Mr.doob 已提交
3443
		},
3444

M
Mr.doob 已提交
3445
		nodeEnd: function () {
3446

M
Mr.doob 已提交
3447
			this.popStack();
3448

M
Mr.doob 已提交
3449
		},
Y
yamahigashi 已提交
3450

M
Mr.doob 已提交
3451
		isFlattenNode: function ( node ) {
Y
yamahigashi 已提交
3452

M
Mr.doob 已提交
3453
			return ( 'subNodes' in node && 'properties' in node ) ? true : false;
Y
yamahigashi 已提交
3454

M
Mr.doob 已提交
3455
		}
Y
yamahigashi 已提交
3456

M
Mr.doob 已提交
3457
	} );
Y
yamahigashi 已提交
3458

L
Lewy Blue 已提交
3459
	// Parse an FBX file in Binary format
L
Lewy Blue 已提交
3460
	function BinaryParser() {}
Y
yamahigashi 已提交
3461

M
Mr.doob 已提交
3462
	Object.assign( BinaryParser.prototype, {
Y
yamahigashi 已提交
3463

M
Mr.doob 已提交
3464
		parse: function ( buffer ) {
Y
yamahigashi 已提交
3465

M
Mr.doob 已提交
3466 3467
			var reader = new BinaryReader( buffer );
			reader.skip( 23 ); // skip magic 23 bytes
Y
yamahigashi 已提交
3468

M
Mr.doob 已提交
3469
			var version = reader.getUint32();
Y
yamahigashi 已提交
3470

M
Mugen87 已提交
3471
			console.log( 'THREE.FBXLoader: FBX binary version: ' + version );
Y
yamahigashi 已提交
3472

M
Mr.doob 已提交
3473
			var allNodes = new FBXTree();
Y
yamahigashi 已提交
3474

M
Mr.doob 已提交
3475
			while ( ! this.endOfContent( reader ) ) {
Y
yamahigashi 已提交
3476

M
Mr.doob 已提交
3477 3478
				var node = this.parseNode( reader, version );
				if ( node !== null ) allNodes.add( node.name, node );
Y
yamahigashi 已提交
3479

M
Mr.doob 已提交
3480
			}
3481

M
Mr.doob 已提交
3482
			return allNodes;
Y
yamahigashi 已提交
3483

M
Mr.doob 已提交
3484
		},
Y
yamahigashi 已提交
3485

L
Lewy Blue 已提交
3486
		// Check if reader has reached the end of content.
L
Lewy Blue 已提交
3487
		endOfContent: function ( reader ) {
M
Mr.doob 已提交
3488 3489 3490

			// footer size: 160bytes + 16-byte alignment padding
			// - 16bytes: magic
3491
			// - padding til 16-byte alignment (at least 1byte?)
L
Lewy Blue 已提交
3492
			//	(seems like some exporters embed fixed 15 or 16bytes?)
M
Mr.doob 已提交
3493 3494 3495 3496 3497 3498
			// - 4bytes: magic
			// - 4bytes: version
			// - 120bytes: zero
			// - 16bytes: magic
			if ( reader.size() % 16 === 0 ) {

L
Lewy Blue 已提交
3499
				return ( ( reader.getOffset() + 160 + 16 ) & ~ 0xf ) >= reader.size();
Y
yamahigashi 已提交
3500

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

3503
				return reader.getOffset() + 160 + 16 >= reader.size();
Y
yamahigashi 已提交
3504

M
Mr.doob 已提交
3505
			}
Y
yamahigashi 已提交
3506

M
Mr.doob 已提交
3507
		},
Y
yamahigashi 已提交
3508

M
Mr.doob 已提交
3509
		parseNode: function ( reader, version ) {
Y
yamahigashi 已提交
3510

M
Mr.doob 已提交
3511 3512 3513
			// The first three data sizes depends on version.
			var endOffset = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
			var numProperties = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
L
tidying  
Lewy Blue 已提交
3514 3515

			// note: do not remove this even if you get a linter warning as it moves the buffer forward
M
Mr.doob 已提交
3516
			var propertyListLen = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
L
tidying  
Lewy Blue 已提交
3517

M
Mr.doob 已提交
3518 3519
			var nameLen = reader.getUint8();
			var name = reader.getString( nameLen );
Y
yamahigashi 已提交
3520

M
Mr.doob 已提交
3521 3522
			// Regards this node as NULL-record if endOffset is zero
			if ( endOffset === 0 ) return null;
Y
yamahigashi 已提交
3523

M
Mr.doob 已提交
3524
			var propertyList = [];
Y
yamahigashi 已提交
3525

M
Mr.doob 已提交
3526
			for ( var i = 0; i < numProperties; i ++ ) {
Y
yamahigashi 已提交
3527

M
Mr.doob 已提交
3528
				propertyList.push( this.parseProperty( reader ) );
Y
yamahigashi 已提交
3529

M
Mr.doob 已提交
3530
			}
Y
yamahigashi 已提交
3531

M
Mr.doob 已提交
3532 3533 3534 3535
			// 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 已提交
3536

M
Mr.doob 已提交
3537 3538
			var subNodes = {};
			var properties = {};
Y
yamahigashi 已提交
3539

M
Mr.doob 已提交
3540
			var isSingleProperty = false;
Y
yamahigashi 已提交
3541

L
Lewy Blue 已提交
3542
			// check if this node represents just a single property
M
Mr.doob 已提交
3543 3544
			// 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 已提交
3545

M
Mr.doob 已提交
3546
				isSingleProperty = true;
Y
yamahigashi 已提交
3547

M
Mr.doob 已提交
3548
			}
Y
yamahigashi 已提交
3549

M
Mr.doob 已提交
3550
			while ( endOffset > reader.getOffset() ) {
Y
yamahigashi 已提交
3551

M
Mr.doob 已提交
3552
				var node = this.parseNode( reader, version );
Y
yamahigashi 已提交
3553

M
Mr.doob 已提交
3554
				if ( node === null ) continue;
Y
yamahigashi 已提交
3555

M
Mr.doob 已提交
3556 3557
				// special case: child node is single property
				if ( node.singleProperty === true ) {
Y
yamahigashi 已提交
3558

M
Mr.doob 已提交
3559
					var value = node.propertyList[ 0 ];
Y
yamahigashi 已提交
3560

M
Mr.doob 已提交
3561
					if ( Array.isArray( value ) ) {
Y
yamahigashi 已提交
3562

M
Mr.doob 已提交
3563 3564
						node.properties[ node.name ] = node.propertyList[ 0 ];
						subNodes[ node.name ] = node;
Y
yamahigashi 已提交
3565

3566
						node.properties.a = value;
Y
yamahigashi 已提交
3567

M
Mr.doob 已提交
3568
					} else {
Y
yamahigashi 已提交
3569

M
Mr.doob 已提交
3570
						properties[ node.name ] = value;
Y
yamahigashi 已提交
3571

M
Mr.doob 已提交
3572
					}
Y
yamahigashi 已提交
3573

M
Mr.doob 已提交
3574
					continue;
Y
yamahigashi 已提交
3575

M
Mr.doob 已提交
3576
				}
Y
yamahigashi 已提交
3577

L
Lewy Blue 已提交
3578
				// parse connections
M
Mr.doob 已提交
3579
				if ( name === 'Connections' && node.name === 'C' ) {
Y
yamahigashi 已提交
3580

M
Mr.doob 已提交
3581
					var array = [];
Y
yamahigashi 已提交
3582

M
Mr.doob 已提交
3583
					for ( var i = 1, il = node.propertyList.length; i < il; i ++ ) {
Y
yamahigashi 已提交
3584

M
Mr.doob 已提交
3585
						array[ i - 1 ] = node.propertyList[ i ];
Y
yamahigashi 已提交
3586

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

M
Mr.doob 已提交
3589
					if ( properties.connections === undefined ) {
Y
yamahigashi 已提交
3590

M
Mr.doob 已提交
3591
						properties.connections = [];
Y
yamahigashi 已提交
3592

M
Mr.doob 已提交
3593
					}
Y
yamahigashi 已提交
3594

M
Mr.doob 已提交
3595
					properties.connections.push( array );
Y
yamahigashi 已提交
3596

M
Mr.doob 已提交
3597
					continue;
Y
yamahigashi 已提交
3598

M
Mr.doob 已提交
3599
				}
Y
yamahigashi 已提交
3600

M
Mr.doob 已提交
3601
				// special case: child node is Properties\d+
L
Lewy Blue 已提交
3602
				// move child node's properties to this node.
M
Mr.doob 已提交
3603
				if ( node.name.match( /^Properties\d+$/ ) ) {
Y
yamahigashi 已提交
3604

M
Mr.doob 已提交
3605
					var keys = Object.keys( node.properties );
Y
yamahigashi 已提交
3606

M
Mr.doob 已提交
3607
					for ( var i = 0, il = keys.length; i < il; i ++ ) {
Y
yamahigashi 已提交
3608

M
Mr.doob 已提交
3609 3610
						var key = keys[ i ];
						properties[ key ] = node.properties[ key ];
Y
yamahigashi 已提交
3611

M
Mr.doob 已提交
3612
					}
Y
yamahigashi 已提交
3613

M
Mr.doob 已提交
3614
					continue;
Y
yamahigashi 已提交
3615

M
Mr.doob 已提交
3616
				}
Y
yamahigashi 已提交
3617

L
Lewy Blue 已提交
3618
				// parse 'properties70'
M
Mr.doob 已提交
3619
				if ( name.match( /^Properties\d+$/ ) && node.name === 'P' ) {
Y
yamahigashi 已提交
3620

M
Mr.doob 已提交
3621 3622 3623 3624 3625
					var innerPropName = node.propertyList[ 0 ];
					var innerPropType1 = node.propertyList[ 1 ];
					var innerPropType2 = node.propertyList[ 2 ];
					var innerPropFlag = node.propertyList[ 3 ];
					var innerPropValue;
Y
yamahigashi 已提交
3626

M
Mr.doob 已提交
3627 3628
					if ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );
					if ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );
Y
yamahigashi 已提交
3629

L
Lewy Blue 已提交
3630
					if ( innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' || innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
Y
yamahigashi 已提交
3631

M
Mr.doob 已提交
3632 3633 3634 3635 3636
						innerPropValue = [
							node.propertyList[ 4 ],
							node.propertyList[ 5 ],
							node.propertyList[ 6 ]
						];
Y
yamahigashi 已提交
3637

M
Mr.doob 已提交
3638
					} else {
Y
yamahigashi 已提交
3639

M
Mr.doob 已提交
3640
						innerPropValue = node.propertyList[ 4 ];
Y
yamahigashi 已提交
3641

M
Mr.doob 已提交
3642
					}
Y
yamahigashi 已提交
3643

L
Lewy Blue 已提交
3644
					// this will be copied to parent, see above
M
Mr.doob 已提交
3645
					properties[ innerPropName ] = {
Y
yamahigashi 已提交
3646

M
Mr.doob 已提交
3647 3648 3649 3650
						'type': innerPropType1,
						'type2': innerPropType2,
						'flag': innerPropFlag,
						'value': innerPropValue
Y
yamahigashi 已提交
3651

M
Mr.doob 已提交
3652
					};
Y
yamahigashi 已提交
3653

M
Mr.doob 已提交
3654
					continue;
Y
yamahigashi 已提交
3655

M
Mr.doob 已提交
3656
				}
Y
yamahigashi 已提交
3657

M
Mr.doob 已提交
3658
				if ( subNodes[ node.name ] === undefined ) {
Y
yamahigashi 已提交
3659

M
Mr.doob 已提交
3660
					if ( typeof node.id === 'number' ) {
K
Kyle Larson 已提交
3661

M
Mr.doob 已提交
3662 3663
						subNodes[ node.name ] = {};
						subNodes[ node.name ][ node.id ] = node;
Y
yamahigashi 已提交
3664

M
Mr.doob 已提交
3665
					} else {
Y
yamahigashi 已提交
3666

M
Mr.doob 已提交
3667
						subNodes[ node.name ] = node;
Y
yamahigashi 已提交
3668

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

M
Mr.doob 已提交
3671
				} else {
Y
yamahigashi 已提交
3672

M
Mr.doob 已提交
3673
					if ( node.id === '' ) {
Y
yamahigashi 已提交
3674

M
Mr.doob 已提交
3675
						if ( ! Array.isArray( subNodes[ node.name ] ) ) {
Y
yamahigashi 已提交
3676

M
Mr.doob 已提交
3677
							subNodes[ node.name ] = [ subNodes[ node.name ] ];
Y
yamahigashi 已提交
3678

M
Mr.doob 已提交
3679
						}
Y
yamahigashi 已提交
3680

M
Mr.doob 已提交
3681
						subNodes[ node.name ].push( node );
Y
yamahigashi 已提交
3682

M
Mr.doob 已提交
3683
					} else {
Y
yamahigashi 已提交
3684

M
Mr.doob 已提交
3685
						if ( subNodes[ node.name ][ node.id ] === undefined ) {
Y
yamahigashi 已提交
3686

M
Mr.doob 已提交
3687
							subNodes[ node.name ][ node.id ] = node;
Y
yamahigashi 已提交
3688

M
Mr.doob 已提交
3689
						} else {
Y
yamahigashi 已提交
3690

M
Mr.doob 已提交
3691 3692
							// conflict id. irregular?
							if ( ! Array.isArray( subNodes[ node.name ][ node.id ] ) ) {
Y
yamahigashi 已提交
3693

M
Mr.doob 已提交
3694
								subNodes[ node.name ][ node.id ] = [ subNodes[ node.name ][ node.id ] ];
Y
yamahigashi 已提交
3695

M
Mr.doob 已提交
3696
							}
Y
yamahigashi 已提交
3697

M
Mr.doob 已提交
3698
							subNodes[ node.name ][ node.id ].push( node );
K
Kyle Larson 已提交
3699

M
Mr.doob 已提交
3700
						}
K
Kyle Larson 已提交
3701

M
Mr.doob 已提交
3702
					}
K
Kyle Larson 已提交
3703

M
Mr.doob 已提交
3704
				}
K
Kyle Larson 已提交
3705

M
Mr.doob 已提交
3706
			}
K
Kyle Larson 已提交
3707

M
Mr.doob 已提交
3708
			return {
K
Kyle Larson 已提交
3709

M
Mr.doob 已提交
3710 3711 3712 3713 3714 3715
				singleProperty: isSingleProperty,
				id: id,
				attrName: attrName,
				attrType: attrType,
				name: name,
				properties: properties,
L
Lewy Blue 已提交
3716
				propertyList: propertyList, // raw property list used by parent
M
Mr.doob 已提交
3717
				subNodes: subNodes
K
Kyle Larson 已提交
3718

M
Mr.doob 已提交
3719
			};
K
Kyle Larson 已提交
3720

M
Mr.doob 已提交
3721
		},
K
Kyle Larson 已提交
3722

M
Mr.doob 已提交
3723
		parseProperty: function ( reader ) {
K
Kyle Larson 已提交
3724

M
Mr.doob 已提交
3725
			var type = reader.getChar();
K
Kyle Larson 已提交
3726

M
Mr.doob 已提交
3727
			switch ( type ) {
K
Kyle Larson 已提交
3728

3729 3730
				case 'C':
					return reader.getBoolean();
K
Kyle Larson 已提交
3731

M
Mr.doob 已提交
3732 3733
				case 'D':
					return reader.getFloat64();
K
Kyle Larson 已提交
3734

3735 3736
				case 'F':
					return reader.getFloat32();
K
Kyle Larson 已提交
3737

M
Mr.doob 已提交
3738 3739
				case 'I':
					return reader.getInt32();
K
Kyle Larson 已提交
3740

3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751
				case 'L':
					return reader.getInt64();

				case 'R':
					var length = reader.getUint32();
					return reader.getArrayBuffer( length );

				case 'S':
					var length = reader.getUint32();
					return reader.getString( length );

M
Mr.doob 已提交
3752 3753
				case 'Y':
					return reader.getInt16();
K
Kyle Larson 已提交
3754

3755 3756
				case 'b':
				case 'c':
M
Mr.doob 已提交
3757
				case 'd':
3758
				case 'f':
M
Mr.doob 已提交
3759
				case 'i':
3760
				case 'l':
K
Kyle Larson 已提交
3761

M
Mr.doob 已提交
3762 3763 3764
					var arrayLength = reader.getUint32();
					var encoding = reader.getUint32(); // 0: non-compressed, 1: compressed
					var compressedLength = reader.getUint32();
K
Kyle Larson 已提交
3765

M
Mr.doob 已提交
3766
					if ( encoding === 0 ) {
K
Kyle Larson 已提交
3767

M
Mr.doob 已提交
3768
						switch ( type ) {
K
Kyle Larson 已提交
3769

3770 3771 3772
							case 'b':
							case 'c':
								return reader.getBooleanArray( arrayLength );
K
Kyle Larson 已提交
3773

M
Mr.doob 已提交
3774 3775
							case 'd':
								return reader.getFloat64Array( arrayLength );
K
Kyle Larson 已提交
3776

3777 3778
							case 'f':
								return reader.getFloat32Array( arrayLength );
K
Kyle Larson 已提交
3779

M
Mr.doob 已提交
3780 3781
							case 'i':
								return reader.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3782

3783 3784
							case 'l':
								return reader.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3785

M
Mr.doob 已提交
3786
						}
Y
yamahigashi 已提交
3787

M
Mr.doob 已提交
3788
					}
Y
yamahigashi 已提交
3789

M
Mr.doob 已提交
3790
					if ( window.Zlib === undefined ) {
Y
yamahigashi 已提交
3791

M
Mugen87 已提交
3792
						throw new Error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
Y
yamahigashi 已提交
3793

M
Mr.doob 已提交
3794
					}
Y
yamahigashi 已提交
3795

L
Lewy Blue 已提交
3796
					var inflate = new Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) ); // eslint-disable-line no-undef
M
Mr.doob 已提交
3797
					var reader2 = new BinaryReader( inflate.decompress().buffer );
Y
yamahigashi 已提交
3798

M
Mr.doob 已提交
3799
					switch ( type ) {
Y
yamahigashi 已提交
3800

3801 3802 3803
						case 'b':
						case 'c':
							return reader2.getBooleanArray( arrayLength );
Y
yamahigashi 已提交
3804

M
Mr.doob 已提交
3805 3806
						case 'd':
							return reader2.getFloat64Array( arrayLength );
Y
yamahigashi 已提交
3807

3808 3809
						case 'f':
							return reader2.getFloat32Array( arrayLength );
Y
yamahigashi 已提交
3810

M
Mr.doob 已提交
3811 3812
						case 'i':
							return reader2.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3813

3814 3815
						case 'l':
							return reader2.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3816

M
Mr.doob 已提交
3817
					}
Y
yamahigashi 已提交
3818

M
Mr.doob 已提交
3819
				default:
M
Mugen87 已提交
3820
					throw new Error( 'THREE.FBXLoader: Unknown property type ' + type );
Y
yamahigashi 已提交
3821

M
Mr.doob 已提交
3822
			}
Y
yamahigashi 已提交
3823

M
Mr.doob 已提交
3824
		}
Y
yamahigashi 已提交
3825

M
Mr.doob 已提交
3826
	} );
Y
yamahigashi 已提交
3827 3828


M
Mr.doob 已提交
3829
	function BinaryReader( buffer, littleEndian ) {
Y
yamahigashi 已提交
3830

M
Mr.doob 已提交
3831 3832 3833
		this.dv = new DataView( buffer );
		this.offset = 0;
		this.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;
Y
yamahigashi 已提交
3834

M
Mr.doob 已提交
3835
	}
Y
yamahigashi 已提交
3836

M
Mr.doob 已提交
3837
	Object.assign( BinaryReader.prototype, {
Y
yamahigashi 已提交
3838

M
Mr.doob 已提交
3839
		getOffset: function () {
Y
yamahigashi 已提交
3840

M
Mr.doob 已提交
3841
			return this.offset;
Y
yamahigashi 已提交
3842

M
Mr.doob 已提交
3843
		},
Y
yamahigashi 已提交
3844

M
Mr.doob 已提交
3845
		size: function () {
Y
yamahigashi 已提交
3846

M
Mr.doob 已提交
3847
			return this.dv.buffer.byteLength;
Y
yamahigashi 已提交
3848

M
Mr.doob 已提交
3849
		},
Y
yamahigashi 已提交
3850

M
Mr.doob 已提交
3851
		skip: function ( length ) {
Y
yamahigashi 已提交
3852

M
Mr.doob 已提交
3853
			this.offset += length;
Y
yamahigashi 已提交
3854

M
Mr.doob 已提交
3855
		},
Y
yamahigashi 已提交
3856

M
Mr.doob 已提交
3857
		// seems like true/false representation depends on exporter.
L
Lewy Blue 已提交
3858
		// true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)
M
Mr.doob 已提交
3859 3860
		// then sees LSB.
		getBoolean: function () {
Y
yamahigashi 已提交
3861

M
Mr.doob 已提交
3862
			return ( this.getUint8() & 1 ) === 1;
Y
yamahigashi 已提交
3863

M
Mr.doob 已提交
3864
		},
Y
yamahigashi 已提交
3865

M
Mr.doob 已提交
3866
		getBooleanArray: function ( size ) {
Y
yamahigashi 已提交
3867

M
Mr.doob 已提交
3868
			var a = [];
Y
yamahigashi 已提交
3869

M
Mr.doob 已提交
3870
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3871

M
Mr.doob 已提交
3872
				a.push( this.getBoolean() );
Y
yamahigashi 已提交
3873 3874 3875

			}

M
Mr.doob 已提交
3876
			return a;
Y
yamahigashi 已提交
3877

M
Mr.doob 已提交
3878
		},
Y
yamahigashi 已提交
3879

M
Mr.doob 已提交
3880
		getInt8: function () {
Y
yamahigashi 已提交
3881

M
Mr.doob 已提交
3882 3883 3884
			var value = this.dv.getInt8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
3885

M
Mr.doob 已提交
3886
		},
Y
yamahigashi 已提交
3887

M
Mr.doob 已提交
3888
		getInt8Array: function ( size ) {
Y
yamahigashi 已提交
3889

M
Mr.doob 已提交
3890
			var a = [];
Y
yamahigashi 已提交
3891

M
Mr.doob 已提交
3892
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3893

M
Mr.doob 已提交
3894
				a.push( this.getInt8() );
Y
yamahigashi 已提交
3895

M
Mr.doob 已提交
3896
			}
Y
yamahigashi 已提交
3897

M
Mr.doob 已提交
3898
			return a;
Y
yamahigashi 已提交
3899

M
Mr.doob 已提交
3900
		},
Y
yamahigashi 已提交
3901

M
Mr.doob 已提交
3902
		getUint8: function () {
Y
yamahigashi 已提交
3903

M
Mr.doob 已提交
3904 3905 3906
			var value = this.dv.getUint8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
3907

M
Mr.doob 已提交
3908
		},
Y
yamahigashi 已提交
3909

M
Mr.doob 已提交
3910
		getUint8Array: function ( size ) {
Y
yamahigashi 已提交
3911

M
Mr.doob 已提交
3912
			var a = [];
Y
yamahigashi 已提交
3913

M
Mr.doob 已提交
3914
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3915

M
Mr.doob 已提交
3916
				a.push( this.getUint8() );
Y
yamahigashi 已提交
3917 3918 3919

			}

M
Mr.doob 已提交
3920
			return a;
Y
yamahigashi 已提交
3921

M
Mr.doob 已提交
3922
		},
Y
yamahigashi 已提交
3923

M
Mr.doob 已提交
3924
		getInt16: function () {
Y
yamahigashi 已提交
3925

M
Mr.doob 已提交
3926 3927 3928
			var value = this.dv.getInt16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
3929

M
Mr.doob 已提交
3930
		},
Y
yamahigashi 已提交
3931

M
Mr.doob 已提交
3932
		getInt16Array: function ( size ) {
Y
yamahigashi 已提交
3933

M
Mr.doob 已提交
3934
			var a = [];
Y
yamahigashi 已提交
3935

M
Mr.doob 已提交
3936
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3937

M
Mr.doob 已提交
3938
				a.push( this.getInt16() );
Y
yamahigashi 已提交
3939

M
Mr.doob 已提交
3940
			}
Y
yamahigashi 已提交
3941

M
Mr.doob 已提交
3942
			return a;
3943

M
Mr.doob 已提交
3944
		},
3945

M
Mr.doob 已提交
3946
		getUint16: function () {
Y
yamahigashi 已提交
3947

M
Mr.doob 已提交
3948 3949 3950
			var value = this.dv.getUint16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
3951

M
Mr.doob 已提交
3952
		},
Y
yamahigashi 已提交
3953

M
Mr.doob 已提交
3954
		getUint16Array: function ( size ) {
Y
yamahigashi 已提交
3955

M
Mr.doob 已提交
3956
			var a = [];
Y
yamahigashi 已提交
3957

M
Mr.doob 已提交
3958
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3959

M
Mr.doob 已提交
3960
				a.push( this.getUint16() );
Y
yamahigashi 已提交
3961 3962 3963

			}

M
Mr.doob 已提交
3964
			return a;
Y
yamahigashi 已提交
3965

M
Mr.doob 已提交
3966
		},
3967

M
Mr.doob 已提交
3968
		getInt32: function () {
3969

M
Mr.doob 已提交
3970 3971 3972
			var value = this.dv.getInt32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
3973

M
Mr.doob 已提交
3974
		},
3975

M
Mr.doob 已提交
3976
		getInt32Array: function ( size ) {
3977

M
Mr.doob 已提交
3978
			var a = [];
3979

M
Mr.doob 已提交
3980
			for ( var i = 0; i < size; i ++ ) {
3981

M
Mr.doob 已提交
3982
				a.push( this.getInt32() );
3983 3984 3985

			}

M
Mr.doob 已提交
3986
			return a;
3987

M
Mr.doob 已提交
3988
		},
3989

M
Mr.doob 已提交
3990
		getUint32: function () {
3991

M
Mr.doob 已提交
3992 3993 3994 3995 3996
			var value = this.dv.getUint32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;

		},
3997

M
Mr.doob 已提交
3998
		getUint32Array: function ( size ) {
3999

M
Mr.doob 已提交
4000
			var a = [];
4001

M
Mr.doob 已提交
4002
			for ( var i = 0; i < size; i ++ ) {
4003

M
Mr.doob 已提交
4004
				a.push( this.getUint32() );
4005

M
Mr.doob 已提交
4006
			}
4007

M
Mr.doob 已提交
4008
			return a;
4009

M
Mr.doob 已提交
4010
		},
4011

L
Lewy Blue 已提交
4012
		// JavaScript doesn't support 64-bit integer so calculate this here
M
Mr.doob 已提交
4013
		// 1 << 32 will return 1 so using multiply operation instead here.
L
Lewy Blue 已提交
4014
		// There's a possibility that this method returns wrong value if the value
M
Mr.doob 已提交
4015 4016 4017
		// is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.
		// TODO: safely handle 64-bit integer
		getInt64: function () {
4018

M
Mr.doob 已提交
4019
			var low, high;
4020

M
Mr.doob 已提交
4021
			if ( this.littleEndian ) {
4022

M
Mr.doob 已提交
4023 4024
				low = this.getUint32();
				high = this.getUint32();
4025

M
Mr.doob 已提交
4026
			} else {
4027

M
Mr.doob 已提交
4028 4029
				high = this.getUint32();
				low = this.getUint32();
4030

M
Mr.doob 已提交
4031
			}
4032

M
Mr.doob 已提交
4033 4034
			// calculate negative value
			if ( high & 0x80000000 ) {
4035

L
Lewy Blue 已提交
4036 4037
				high = ~ high & 0xFFFFFFFF;
				low = ~ low & 0xFFFFFFFF;
4038

M
Mr.doob 已提交
4039
				if ( low === 0xFFFFFFFF ) high = ( high + 1 ) & 0xFFFFFFFF;
4040

M
Mr.doob 已提交
4041
				low = ( low + 1 ) & 0xFFFFFFFF;
4042

M
Mr.doob 已提交
4043
				return - ( high * 0x100000000 + low );
4044

M
Mr.doob 已提交
4045
			}
4046

M
Mr.doob 已提交
4047
			return high * 0x100000000 + low;
4048

M
Mr.doob 已提交
4049
		},
4050

M
Mr.doob 已提交
4051
		getInt64Array: function ( size ) {
4052

M
Mr.doob 已提交
4053
			var a = [];
4054

M
Mr.doob 已提交
4055
			for ( var i = 0; i < size; i ++ ) {
4056

M
Mr.doob 已提交
4057
				a.push( this.getInt64() );
4058 4059 4060

			}

M
Mr.doob 已提交
4061 4062 4063
			return a;

		},
4064

M
Mr.doob 已提交
4065 4066
		// Note: see getInt64() comment
		getUint64: function () {
4067

M
Mr.doob 已提交
4068
			var low, high;
4069

M
Mr.doob 已提交
4070 4071 4072 4073 4074 4075 4076 4077 4078
			if ( this.littleEndian ) {

				low = this.getUint32();
				high = this.getUint32();

			} else {

				high = this.getUint32();
				low = this.getUint32();
4079 4080

			}
4081

M
Mr.doob 已提交
4082
			return high * 0x100000000 + low;
4083

M
Mr.doob 已提交
4084
		},
Y
yamahigashi 已提交
4085

M
Mr.doob 已提交
4086
		getUint64Array: function ( size ) {
Y
yamahigashi 已提交
4087

M
Mr.doob 已提交
4088
			var a = [];
Y
yamahigashi 已提交
4089

M
Mr.doob 已提交
4090
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4091

M
Mr.doob 已提交
4092
				a.push( this.getUint64() );
Y
yamahigashi 已提交
4093

M
Mr.doob 已提交
4094
			}
Y
yamahigashi 已提交
4095

M
Mr.doob 已提交
4096
			return a;
Y
yamahigashi 已提交
4097

M
Mr.doob 已提交
4098
		},
K
Kyle Larson 已提交
4099

M
Mr.doob 已提交
4100
		getFloat32: function () {
Y
yamahigashi 已提交
4101

M
Mr.doob 已提交
4102 4103 4104
			var value = this.dv.getFloat32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
Y
yamahigashi 已提交
4105

M
Mr.doob 已提交
4106
		},
Y
yamahigashi 已提交
4107

M
Mr.doob 已提交
4108
		getFloat32Array: function ( size ) {
Y
yamahigashi 已提交
4109

M
Mr.doob 已提交
4110
			var a = [];
Y
yamahigashi 已提交
4111

M
Mr.doob 已提交
4112
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4113

M
Mr.doob 已提交
4114
				a.push( this.getFloat32() );
Y
yamahigashi 已提交
4115 4116 4117

			}

M
Mr.doob 已提交
4118
			return a;
Y
yamahigashi 已提交
4119

M
Mr.doob 已提交
4120
		},
Y
yamahigashi 已提交
4121

M
Mr.doob 已提交
4122
		getFloat64: function () {
Y
yamahigashi 已提交
4123

M
Mr.doob 已提交
4124 4125 4126
			var value = this.dv.getFloat64( this.offset, this.littleEndian );
			this.offset += 8;
			return value;
Y
yamahigashi 已提交
4127

M
Mr.doob 已提交
4128
		},
Y
yamahigashi 已提交
4129

M
Mr.doob 已提交
4130
		getFloat64Array: function ( size ) {
Y
yamahigashi 已提交
4131

M
Mr.doob 已提交
4132
			var a = [];
Y
yamahigashi 已提交
4133

M
Mr.doob 已提交
4134
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
4135

M
Mr.doob 已提交
4136
				a.push( this.getFloat64() );
Y
yamahigashi 已提交
4137

M
Mr.doob 已提交
4138
			}
Y
yamahigashi 已提交
4139

M
Mr.doob 已提交
4140
			return a;
Y
yamahigashi 已提交
4141

M
Mr.doob 已提交
4142
		},
Y
yamahigashi 已提交
4143

M
Mr.doob 已提交
4144
		getArrayBuffer: function ( size ) {
Y
yamahigashi 已提交
4145

M
Mr.doob 已提交
4146 4147 4148
			var value = this.dv.buffer.slice( this.offset, this.offset + size );
			this.offset += size;
			return value;
Y
yamahigashi 已提交
4149

M
Mr.doob 已提交
4150
		},
Y
yamahigashi 已提交
4151

M
Mr.doob 已提交
4152
		getChar: function () {
Y
yamahigashi 已提交
4153

M
Mr.doob 已提交
4154
			return String.fromCharCode( this.getUint8() );
Y
yamahigashi 已提交
4155

M
Mr.doob 已提交
4156
		},
Y
yamahigashi 已提交
4157

M
Mr.doob 已提交
4158
		getString: function ( size ) {
Y
yamahigashi 已提交
4159

M
Mr.doob 已提交
4160
			var s = '';
Y
yamahigashi 已提交
4161

M
Mr.doob 已提交
4162
			while ( size > 0 ) {
Y
yamahigashi 已提交
4163

M
Mr.doob 已提交
4164
				var value = this.getUint8();
L
Lewy Blue 已提交
4165
				size --;
Y
yamahigashi 已提交
4166

M
Mr.doob 已提交
4167
				if ( value === 0 ) break;
Y
yamahigashi 已提交
4168

M
Mr.doob 已提交
4169
				s += String.fromCharCode( value );
Y
yamahigashi 已提交
4170

M
Mr.doob 已提交
4171
			}
Y
yamahigashi 已提交
4172

L
Lewy Blue 已提交
4173 4174 4175
			// Manage UTF8 encoding
			s = decodeURIComponent( escape( s ) );

M
Mr.doob 已提交
4176
			this.skip( size );
Y
yamahigashi 已提交
4177

M
Mr.doob 已提交
4178
			return s;
Y
yamahigashi 已提交
4179

M
Mr.doob 已提交
4180
		}
Y
yamahigashi 已提交
4181

M
Mr.doob 已提交
4182
	} );
Y
yamahigashi 已提交
4183

L
Lewy Blue 已提交
4184 4185
	// FBXTree holds a representation of the FBX data, returned by the TextParser ( FBX ASCII format)
	// and BinaryParser( FBX Binary format)
L
Lewy Blue 已提交
4186
	function FBXTree() {}
Y
yamahigashi 已提交
4187

M
Mr.doob 已提交
4188
	Object.assign( FBXTree.prototype, {
Y
yamahigashi 已提交
4189

M
Mr.doob 已提交
4190
		add: function ( key, val ) {
Y
yamahigashi 已提交
4191

M
Mr.doob 已提交
4192
			this[ key ] = val;
Y
yamahigashi 已提交
4193

M
Mr.doob 已提交
4194
		},
Y
yamahigashi 已提交
4195

M
Mr.doob 已提交
4196
	} );
Y
yamahigashi 已提交
4197

M
Mr.doob 已提交
4198
	function isFbxFormatBinary( buffer ) {
Y
yamahigashi 已提交
4199

M
Mr.doob 已提交
4200
		var CORRECT = 'Kaydara FBX Binary  \0';
Y
yamahigashi 已提交
4201

M
Mr.doob 已提交
4202
		return buffer.byteLength >= CORRECT.length && CORRECT === convertArrayBufferToString( buffer, 0, CORRECT.length );
Y
yamahigashi 已提交
4203

M
Mr.doob 已提交
4204
	}
Y
yamahigashi 已提交
4205

M
Mr.doob 已提交
4206
	function isFbxFormatASCII( text ) {
Y
yamahigashi 已提交
4207

M
Mr.doob 已提交
4208
		var CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
Y
yamahigashi 已提交
4209

M
Mr.doob 已提交
4210
		var cursor = 0;
Y
yamahigashi 已提交
4211

M
Mr.doob 已提交
4212
		function read( offset ) {
Y
yamahigashi 已提交
4213

M
Mr.doob 已提交
4214 4215 4216 4217
			var result = text[ offset - 1 ];
			text = text.slice( cursor + offset );
			cursor ++;
			return result;
Y
yamahigashi 已提交
4218 4219 4220

		}

M
Mr.doob 已提交
4221
		for ( var i = 0; i < CORRECT.length; ++ i ) {
Y
yamahigashi 已提交
4222

M
Mr.doob 已提交
4223
			var num = read( 1 );
M
Mugen87 已提交
4224
			if ( num === CORRECT[ i ] ) {
Y
yamahigashi 已提交
4225

M
Mr.doob 已提交
4226
				return false;
Y
yamahigashi 已提交
4227 4228 4229

			}

M
Mr.doob 已提交
4230
		}
Y
yamahigashi 已提交
4231

M
Mr.doob 已提交
4232
		return true;
Y
yamahigashi 已提交
4233

M
Mr.doob 已提交
4234
	}
Y
yamahigashi 已提交
4235

M
Mr.doob 已提交
4236
	function getFbxVersion( text ) {
Y
yamahigashi 已提交
4237

M
Mr.doob 已提交
4238 4239 4240 4241 4242 4243
		var versionRegExp = /FBXVersion: (\d+)/;
		var match = text.match( versionRegExp );
		if ( match ) {

			var version = parseInt( match[ 1 ] );
			return version;
Y
yamahigashi 已提交
4244 4245

		}
M
Mugen87 已提交
4246
		throw new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );
Y
yamahigashi 已提交
4247

M
Mr.doob 已提交
4248 4249
	}

L
Lewy Blue 已提交
4250
	// Converts FBX ticks into real time seconds.
M
Mr.doob 已提交
4251 4252 4253
	function convertFBXTimeToSeconds( time ) {

		return time / 46186158000;
Y
yamahigashi 已提交
4254

K
Kyle Larson 已提交
4255
	}
Y
yamahigashi 已提交
4256

L
Lewy Blue 已提交
4257 4258 4259

	// Parses comma separated list of numbers and returns them an array.
	// Used internally by the TextParser
4260
	function parseNumberArray( value ) {
Y
yamahigashi 已提交
4261

4262
		var array = value.split( ',' );
Y
yamahigashi 已提交
4263

M
Mr.doob 已提交
4264
		for ( var i = 0, l = array.length; i < l; i ++ ) {
Y
yamahigashi 已提交
4265

4266
			array[ i ] = parseFloat( array[ i ] );
Y
yamahigashi 已提交
4267 4268 4269

		}

M
Mr.doob 已提交
4270
		return array;
Y
yamahigashi 已提交
4271

M
Mr.doob 已提交
4272
	}
Y
yamahigashi 已提交
4273

M
Mr.doob 已提交
4274
	function parseVector3( property ) {
Y
yamahigashi 已提交
4275

M
Mr.doob 已提交
4276
		return new THREE.Vector3().fromArray( property.value );
Y
yamahigashi 已提交
4277

M
Mr.doob 已提交
4278
	}
Y
yamahigashi 已提交
4279

M
Mr.doob 已提交
4280
	function parseColor( property ) {
Y
yamahigashi 已提交
4281

M
Mr.doob 已提交
4282
		return new THREE.Color().fromArray( property.value );
Y
yamahigashi 已提交
4283 4284 4285

	}

L
Lewy Blue 已提交
4286
	// Converts ArrayBuffer to String.
M
Mr.doob 已提交
4287
	function convertArrayBufferToString( buffer, from, to ) {
Y
yamahigashi 已提交
4288

M
Mr.doob 已提交
4289 4290
		if ( from === undefined ) from = 0;
		if ( to === undefined ) to = buffer.byteLength;
Y
yamahigashi 已提交
4291

M
Mr.doob 已提交
4292
		var array = new Uint8Array( buffer, from, to );
Y
yamahigashi 已提交
4293

4294 4295 4296 4297 4298 4299
		if ( window.TextDecoder !== undefined ) {

			return new TextDecoder().decode( array );

		}

M
Mr.doob 已提交
4300
		var s = '';
Y
yamahigashi 已提交
4301

M
Mr.doob 已提交
4302
		for ( var i = 0, il = array.length; i < il; i ++ ) {
Y
yamahigashi 已提交
4303

M
Mr.doob 已提交
4304
			s += String.fromCharCode( array[ i ] );
Y
yamahigashi 已提交
4305

M
Mr.doob 已提交
4306
		}
Y
yamahigashi 已提交
4307

M
Mr.doob 已提交
4308
		return s;
Y
yamahigashi 已提交
4309

M
Mr.doob 已提交
4310
	}
Y
yamahigashi 已提交
4311

M
Mr.doob 已提交
4312
	function findIndex( array, func ) {
Y
yamahigashi 已提交
4313

M
Mr.doob 已提交
4314 4315 4316 4317 4318 4319
		for ( var i = 0, l = array.length; i < l; i ++ ) {

			if ( func( array[ i ] ) ) return i;

		}

L
Lewy Blue 已提交
4320
		return - 1;
Y
yamahigashi 已提交
4321

4322
	}
Y
yamahigashi 已提交
4323

M
Mr.doob 已提交
4324
	function append( a, b ) {
Y
yamahigashi 已提交
4325

M
Mr.doob 已提交
4326
		for ( var i = 0, j = a.length, l = b.length; i < l; i ++, j ++ ) {
Y
yamahigashi 已提交
4327

M
Mr.doob 已提交
4328
			a[ j ] = b[ i ];
Y
yamahigashi 已提交
4329

M
Mr.doob 已提交
4330
		}
Y
yamahigashi 已提交
4331

4332
	}
Y
yamahigashi 已提交
4333

M
Mr.doob 已提交
4334 4335 4336 4337 4338 4339 4340
	function slice( a, b, from, to ) {

		for ( var i = from, j = 0; i < to; i ++, j ++ ) {

			a[ j ] = b[ i ];

		}
Y
yamahigashi 已提交
4341

M
Mr.doob 已提交
4342
		return a;
Y
yamahigashi 已提交
4343

4344
	}
Y
yamahigashi 已提交
4345 4346

} )();