FBXLoader.js 88.7 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

1918
				worldMatrices.set( parseInt( node.properties.Node ), 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

					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 已提交
2075 2076 2077 2078 2079
		var returnObject = {
			curves: new Map(),
			layers: {},
			stacks: {},
			length: 0,
2080
			fps: fps,
M
Mr.doob 已提交
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092
			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 已提交
2093

M
Mr.doob 已提交
2094 2095 2096 2097
		}

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

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

M
Mr.doob 已提交
2101
				continue;
Y
yamahigashi 已提交
2102

M
Mr.doob 已提交
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
			}
			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 已提交
2136

Y
yamahigashi 已提交
2137
				} else {
Y
yamahigashi 已提交
2138

M
Mr.doob 已提交
2139
					continue;
Y
yamahigashi 已提交
2140

Y
yamahigashi 已提交
2141
				}
Y
yamahigashi 已提交
2142

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

Y
yamahigashi 已提交
2145
			}
Y
yamahigashi 已提交
2146

M
Mr.doob 已提交
2147
		}
Y
yamahigashi 已提交
2148

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

M
Mr.doob 已提交
2151 2152
			var id = curveNode.containerBoneID;
			if ( ! returnObject.curves.has( id ) ) {
Y
yamahigashi 已提交
2153

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

M
Mr.doob 已提交
2156 2157
			}
			returnObject.curves.get( id )[ curveNode.attr ] = curveNode;
2158

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

M
Mr.doob 已提交
2161
				var curves = curveNode.curves;
2162

L
Lewy Blue 已提交
2163 2164
				// Some FBX files have an AnimationCurveNode
				// which isn't any connected to any AnimationCurve.
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
				// 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 已提交
2197 2198 2199
				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 已提交
2200

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

M
Mr.doob 已提交
2203 2204 2205 2206 2207
					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 已提交
2208

M
Mr.doob 已提交
2209 2210 2211 2212 2213 2214
						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 已提交
2215

M
Mr.doob 已提交
2216 2217 2218
					}

				}
Y
yamahigashi 已提交
2219

Y
yamahigashi 已提交
2220
			}
Y
yamahigashi 已提交
2221

M
Mr.doob 已提交
2222
		} );
Y
yamahigashi 已提交
2223

M
Mr.doob 已提交
2224 2225 2226 2227
		for ( var nodeID in rawLayers ) {

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

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

M
Mr.doob 已提交
2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248
				// 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 已提交
2249

Y
yamahigashi 已提交
2250
			}
Y
yamahigashi 已提交
2251

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

M
Mr.doob 已提交
2254
		}
Y
yamahigashi 已提交
2255

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

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

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

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

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

M
Mr.doob 已提交
2268
					layers.push( currentLayer );
Y
yamahigashi 已提交
2269

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

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

M
Mr.doob 已提交
2274
						if ( layer ) {
Y
yamahigashi 已提交
2275

M
Mr.doob 已提交
2276 2277 2278 2279 2280 2281 2282
							getCurveNodeMaxMinTimeStamps( layer, timestamps );

						}

					}

				}
Y
yamahigashi 已提交
2283

M
Mr.doob 已提交
2284 2285 2286 2287 2288 2289 2290 2291 2292
			}

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

M
Mr.doob 已提交
2296
			}
Y
yamahigashi 已提交
2297

M
Mr.doob 已提交
2298
		}
Y
yamahigashi 已提交
2299

M
Mr.doob 已提交
2300
		return returnObject;
Y
yamahigashi 已提交
2301

Y
yamahigashi 已提交
2302
	}
Y
yamahigashi 已提交
2303

M
Mr.doob 已提交
2304 2305 2306 2307 2308 2309
	function parseAnimationNode( FBXTree, animationCurveNode, connections, sceneGraph ) {

		var rawModels = FBXTree.Objects.subNodes.Model;

		var returnObject = {

L
Lewy Blue 已提交
2310
			id: animationCurveNode.id,
M
Mr.doob 已提交
2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323
			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 已提交
2324

M
Mr.doob 已提交
2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
		};

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

M
Mr.doob 已提交
2340 2341
				}
				if ( attributeKey.match( /Z/ ) ) {
Y
yamahigashi 已提交
2342

M
Mr.doob 已提交
2343
					returnObject.attrZ = true;
Y
yamahigashi 已提交
2344

M
Mr.doob 已提交
2345
				}
Y
yamahigashi 已提交
2346

M
Mr.doob 已提交
2347
			}
Y
yamahigashi 已提交
2348

M
Mr.doob 已提交
2349
		} else {
Y
yamahigashi 已提交
2350

M
Mr.doob 已提交
2351
			return null;
Y
yamahigashi 已提交
2352

M
Mr.doob 已提交
2353
		}
Y
yamahigashi 已提交
2354

M
Mr.doob 已提交
2355 2356
		var conns = connections.get( returnObject.id );
		var containerIndices = conns.parents;
Y
yamahigashi 已提交
2357

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

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

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

M
Mr.doob 已提交
2364 2365
			} );
			if ( boneID > - 1 ) {
Y
yamahigashi 已提交
2366

M
Mr.doob 已提交
2367 2368 2369 2370
				returnObject.containerBoneID = boneID;
				returnObject.containerID = containerIndices[ containerIndicesIndex ].ID;
				var model = rawModels[ returnObject.containerID.toString() ];
				if ( 'PreRotation' in model.properties ) {
Y
yamahigashi 已提交
2371

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

Y
yamahigashi 已提交
2374
				}
M
Mr.doob 已提交
2375
				break;
Y
yamahigashi 已提交
2376

Y
yamahigashi 已提交
2377
			}
Y
yamahigashi 已提交
2378

Y
yamahigashi 已提交
2379
		}
Y
yamahigashi 已提交
2380

M
Mr.doob 已提交
2381
		return returnObject;
Y
yamahigashi 已提交
2382

M
Mr.doob 已提交
2383
	}
Y
yamahigashi 已提交
2384

M
Mr.doob 已提交
2385
	function parseAnimationCurve( animationCurve ) {
Y
yamahigashi 已提交
2386

M
Mr.doob 已提交
2387 2388 2389 2390
		return {
			version: null,
			id: animationCurve.id,
			internalID: animationCurve.id,
2391 2392
			times: animationCurve.subNodes.KeyTime.properties.a.map( convertFBXTimeToSeconds ),
			values: animationCurve.subNodes.KeyValueFloat.properties.a,
M
Mr.doob 已提交
2393

2394
			attrFlag: animationCurve.subNodes.KeyAttrFlags.properties.a,
2395
			attrData: animationCurve.subNodes.KeyAttrDataFloat.properties.a,
M
Mr.doob 已提交
2396
		};
Y
yamahigashi 已提交
2397

M
Mr.doob 已提交
2398
	}
Y
yamahigashi 已提交
2399

L
Lewy Blue 已提交
2400 2401
	// 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 已提交
2402 2403 2404 2405 2406
	function getCurveNodeMaxMinTimeStamps( layer, timestamps ) {

		if ( layer.R ) {

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

M
Mr.doob 已提交
2408 2409
		}
		if ( layer.S ) {
Y
yamahigashi 已提交
2410

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

M
Mr.doob 已提交
2413 2414
		}
		if ( layer.T ) {
Y
yamahigashi 已提交
2415

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

M
Mr.doob 已提交
2418
		}
Y
yamahigashi 已提交
2419

M
Mr.doob 已提交
2420
	}
Y
yamahigashi 已提交
2421

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

M
Mr.doob 已提交
2426
		if ( curve.x ) {
Y
yamahigashi 已提交
2427

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

Y
yamahigashi 已提交
2430
		}
M
Mr.doob 已提交
2431
		if ( curve.y ) {
Y
yamahigashi 已提交
2432

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

M
Mr.doob 已提交
2435 2436
		}
		if ( curve.z ) {
2437

M
Mr.doob 已提交
2438
			getCurveAxisMaxMinTimeStamps( curve.z, timestamps );
2439

M
Mr.doob 已提交
2440
		}
2441

M
Mr.doob 已提交
2442
	}
Y
yamahigashi 已提交
2443

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

M
Mr.doob 已提交
2447 2448
		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 已提交
2449

M
Mr.doob 已提交
2450
	}
Y
yamahigashi 已提交
2451

M
Mr.doob 已提交
2452 2453 2454 2455 2456
	function addAnimations( group, animations ) {

		if ( group.animations === undefined ) {

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

M
Mr.doob 已提交
2458
		}
Y
yamahigashi 已提交
2459

M
Mr.doob 已提交
2460 2461 2462 2463 2464 2465 2466 2467
		var stacks = animations.stacks;

		for ( var key in stacks ) {

			var stack = stacks[ key ];

			var animationData = {
				name: stack.name,
2468
				fps: animations.fps,
M
Mr.doob 已提交
2469 2470 2471
				length: stack.length,
				hierarchy: []
			};
Y
yamahigashi 已提交
2472

M
Mr.doob 已提交
2473
			var bones = group.skeleton.bones;
Y
yamahigashi 已提交
2474

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

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

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

M
Mr.doob 已提交
2482
					return bone.parent === parentBone;
Y
yamahigashi 已提交
2483

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

Y
yamahigashi 已提交
2487
			}
Y
yamahigashi 已提交
2488

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

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

M
Mr.doob 已提交
2493 2494
					var bone = bones[ bonesIndex ];
					var boneIndex = bonesIndex;
Y
yamahigashi 已提交
2495

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

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

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

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

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

M
Mr.doob 已提交
2506
						}
Y
yamahigashi 已提交
2507

M
Mr.doob 已提交
2508
					}
Y
yamahigashi 已提交
2509

M
Mr.doob 已提交
2510
				}
Y
yamahigashi 已提交
2511

Y
yamahigashi 已提交
2512
			}
Y
yamahigashi 已提交
2513

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

Y
yamahigashi 已提交
2516
		}
Y
yamahigashi 已提交
2517

M
Mr.doob 已提交
2518
	}
Y
yamahigashi 已提交
2519

M
Mr.doob 已提交
2520 2521
	var euler = new THREE.Euler();
	var quaternion = new THREE.Quaternion();
Y
yamahigashi 已提交
2522

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

M
Mr.doob 已提交
2525 2526 2527 2528 2529 2530 2531 2532
		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 已提交
2533

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

M
Mr.doob 已提交
2536
		try {
Y
yamahigashi 已提交
2537

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

2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556
				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 已提交
2557

M
Mr.doob 已提交
2558
			}
Y
yamahigashi 已提交
2559

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

2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579
				// 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 已提交
2580

2581
				quaternion.setFromEuler( euler );
M
Mr.doob 已提交
2582
				key.rot = quaternion.toArray();
Y
yamahigashi 已提交
2583

Y
yamahigashi 已提交
2584
			}
Y
yamahigashi 已提交
2585

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

2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604
				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 已提交
2605

M
Mr.doob 已提交
2606
			}
Y
yamahigashi 已提交
2607

M
Mr.doob 已提交
2608
		} catch ( error ) {
Y
yamahigashi 已提交
2609

M
Mr.doob 已提交
2610
			// Curve is not fully plotted.
M
Mugen87 已提交
2611 2612
			console.log( 'THREE.FBXLoader: ', bone );
			console.log( 'THREE.FBXLoader: ', error );
Y
yamahigashi 已提交
2613

Y
yamahigashi 已提交
2614
		}
Y
yamahigashi 已提交
2615

M
Mr.doob 已提交
2616
		return key;
2617

M
Mr.doob 已提交
2618
	}
2619

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

M
Mr.doob 已提交
2622
	function hasCurve( animationNode, attribute ) {
2623

M
Mr.doob 已提交
2624
		if ( animationNode === undefined ) {
2625

M
Mr.doob 已提交
2626 2627 2628
			return false;

		}
Y
yamahigashi 已提交
2629

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

M
Mr.doob 已提交
2632
		if ( ! attributeNode ) {
Y
yamahigashi 已提交
2633

M
Mr.doob 已提交
2634
			return false;
Y
yamahigashi 已提交
2635

Y
yamahigashi 已提交
2636
		}
Y
yamahigashi 已提交
2637

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

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

M
Mr.doob 已提交
2642
		} );
Y
yamahigashi 已提交
2643

M
Mr.doob 已提交
2644
	}
Y
yamahigashi 已提交
2645

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

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

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

M
Mr.doob 已提交
2652
		} );
Y
yamahigashi 已提交
2653

M
Mr.doob 已提交
2654
	}
Y
yamahigashi 已提交
2655

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

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

M
Mr.doob 已提交
2660
	}
Y
yamahigashi 已提交
2661

L
Lewy Blue 已提交
2662
	// parse an FBX file in ASCII format
L
Lewy Blue 已提交
2663
	function TextParser() {}
Y
yamahigashi 已提交
2664

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

M
Mr.doob 已提交
2667
		getPrevNode: function () {
Y
yamahigashi 已提交
2668

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

M
Mr.doob 已提交
2671
		},
Y
yamahigashi 已提交
2672

M
Mr.doob 已提交
2673
		getCurrentNode: function () {
Y
yamahigashi 已提交
2674

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

M
Mr.doob 已提交
2677
		},
Y
yamahigashi 已提交
2678

M
Mr.doob 已提交
2679
		getCurrentProp: function () {
Y
yamahigashi 已提交
2680

M
Mr.doob 已提交
2681
			return this.currentProp;
Y
yamahigashi 已提交
2682

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

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

M
Mr.doob 已提交
2687 2688
			this.nodeStack.push( node );
			this.currentIndent += 1;
Y
yamahigashi 已提交
2689

M
Mr.doob 已提交
2690
		},
Y
yamahigashi 已提交
2691

M
Mr.doob 已提交
2692
		popStack: function () {
Y
yamahigashi 已提交
2693

M
Mr.doob 已提交
2694 2695
			this.nodeStack.pop();
			this.currentIndent -= 1;
Y
yamahigashi 已提交
2696

M
Mr.doob 已提交
2697
		},
Y
yamahigashi 已提交
2698

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

M
Mr.doob 已提交
2701 2702
			this.currentProp = val;
			this.currentPropName = name;
Y
yamahigashi 已提交
2703

M
Mr.doob 已提交
2704
		},
Y
yamahigashi 已提交
2705

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

M
Mr.doob 已提交
2708 2709 2710 2711 2712
			this.currentIndent = 0;
			this.allNodes = new FBXTree();
			this.nodeStack = [];
			this.currentProp = [];
			this.currentPropName = '';
Y
yamahigashi 已提交
2713

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

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

2718
				var l = split[ lineNum ];
Y
yamahigashi 已提交
2719

2720
				// skip comment line
M
Mr.doob 已提交
2721 2722 2723
				if ( l.match( /^[\s\t]*;/ ) ) {

					continue;
Y
yamahigashi 已提交
2724

2725 2726 2727
				}

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

M
Mr.doob 已提交
2730
					continue;
Y
yamahigashi 已提交
2731

2732
				}
Y
yamahigashi 已提交
2733

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

M
Mr.doob 已提交
2738
				if ( match ) {
Y
yamahigashi 已提交
2739

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

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

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

M
Mr.doob 已提交
2747 2748 2749 2750 2751 2752
					}

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

				}
Y
yamahigashi 已提交
2753

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

M
Mr.doob 已提交
2758
				if ( match ) {
Y
yamahigashi 已提交
2759

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

2763 2764 2765 2766 2767
					// for special case: base64 image data follows "Content: ," line
					//	Content: ,
					//	 "iVB..."
					if ( propName === 'Content' && propValue === ',' ) {

L
Lewy Blue 已提交
2768
						propValue = split[ ++ lineNum ].replace( /"/g, '' ).replace( /,$/, '' ).trim();
2769 2770 2771

					}

M
Mr.doob 已提交
2772 2773
					this.parseNodeProperty( l, propName, propValue );
					continue;
Y
yamahigashi 已提交
2774

M
Mr.doob 已提交
2775
				}
Y
yamahigashi 已提交
2776

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

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

M
Mr.doob 已提交
2782 2783
					this.nodeEnd();
					continue;
Y
yamahigashi 已提交
2784

Y
yamahigashi 已提交
2785
				}
Y
yamahigashi 已提交
2786

2787 2788
				// 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 已提交
2789
				if ( l.match( /^[^\s\t}]/ ) ) {
Y
yamahigashi 已提交
2790

M
Mr.doob 已提交
2791
					this.parseNodePropertyContinued( l );
Y
yamahigashi 已提交
2792

M
Mr.doob 已提交
2793
				}
Y
yamahigashi 已提交
2794

Y
yamahigashi 已提交
2795
			}
Y
yamahigashi 已提交
2796

M
Mr.doob 已提交
2797
			return this.allNodes;
Y
yamahigashi 已提交
2798

M
Mr.doob 已提交
2799
		},
Y
yamahigashi 已提交
2800

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

M
Mr.doob 已提交
2803 2804 2805
			var node = { 'name': nodeName, properties: {}, 'subNodes': {} };
			var attrs = this.parseNodeAttr( nodeAttrs );
			var currentNode = this.getCurrentNode();
Y
yamahigashi 已提交
2806

M
Mr.doob 已提交
2807 2808
			// a top node
			if ( this.currentIndent === 0 ) {
Y
yamahigashi 已提交
2809

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

2812
			} else { // a subnode
Y
yamahigashi 已提交
2813

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

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

M
Mr.doob 已提交
2819
					if ( this.isFlattenNode( currentNode.subNodes[ nodeName ] ) ) {
Y
yamahigashi 已提交
2820

M
Mr.doob 已提交
2821
						if ( attrs.id === '' ) {
Y
yamahigashi 已提交
2822

M
Mr.doob 已提交
2823 2824
							currentNode.subNodes[ nodeName ] = [];
							currentNode.subNodes[ nodeName ].push( tmp );
Y
yamahigashi 已提交
2825

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

M
Mr.doob 已提交
2828 2829
							currentNode.subNodes[ nodeName ] = {};
							currentNode.subNodes[ nodeName ][ tmp.id ] = tmp;
Y
yamahigashi 已提交
2830

M
Mr.doob 已提交
2831
						}
Y
yamahigashi 已提交
2832

M
Mr.doob 已提交
2833
					}
Y
yamahigashi 已提交
2834

M
Mr.doob 已提交
2835
					if ( attrs.id === '' ) {
Y
yamahigashi 已提交
2836

M
Mr.doob 已提交
2837
						currentNode.subNodes[ nodeName ].push( node );
2838

M
Mr.doob 已提交
2839
					} else {
Y
yamahigashi 已提交
2840

M
Mr.doob 已提交
2841
						currentNode.subNodes[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
2842

M
Mr.doob 已提交
2843
					}
Y
yamahigashi 已提交
2844

M
Mr.doob 已提交
2845
				} else if ( typeof attrs.id === 'number' || attrs.id.match( /^\d+$/ ) ) {
Y
yamahigashi 已提交
2846

M
Mr.doob 已提交
2847 2848
					currentNode.subNodes[ nodeName ] = {};
					currentNode.subNodes[ nodeName ][ attrs.id ] = node;
Y
yamahigashi 已提交
2849

M
Mr.doob 已提交
2850
				} else {
Y
yamahigashi 已提交
2851

M
Mr.doob 已提交
2852
					currentNode.subNodes[ nodeName ] = node;
Y
yamahigashi 已提交
2853

M
Mr.doob 已提交
2854
				}
K
Kyle Larson 已提交
2855

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

2858

L
Lewy Blue 已提交
2859
			// for this	↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
M
Mr.doob 已提交
2860 2861
			// NodeAttribute: 1001463072, "NodeAttribute::", "LimbNode" {
			if ( nodeAttrs ) {
Y
yamahigashi 已提交
2862

M
Mr.doob 已提交
2863 2864 2865
				node.id = attrs.id;
				node.attrName = attrs.name;
				node.attrType = attrs.type;
K
Kyle Larson 已提交
2866

M
Mr.doob 已提交
2867
			}
K
Kyle Larson 已提交
2868

M
Mr.doob 已提交
2869
			this.pushStack( node );
K
Kyle Larson 已提交
2870

M
Mr.doob 已提交
2871
		},
K
Kyle Larson 已提交
2872

M
Mr.doob 已提交
2873
		parseNodeAttr: function ( attrs ) {
K
Kyle Larson 已提交
2874

M
Mr.doob 已提交
2875
			var id = attrs[ 0 ];
K
Kyle Larson 已提交
2876

M
Mugen87 已提交
2877
			if ( attrs[ 0 ] !== '' ) {
Y
yamahigashi 已提交
2878

M
Mr.doob 已提交
2879
				id = parseInt( attrs[ 0 ] );
Y
yamahigashi 已提交
2880

M
Mr.doob 已提交
2881
				if ( isNaN( id ) ) {
Y
yamahigashi 已提交
2882

M
Mr.doob 已提交
2883
					id = attrs[ 0 ];
Y
yamahigashi 已提交
2884

M
Mr.doob 已提交
2885
				}
Y
yamahigashi 已提交
2886

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

M
Mr.doob 已提交
2889
			var name = '', type = '';
Y
yamahigashi 已提交
2890

M
Mr.doob 已提交
2891
			if ( attrs.length > 1 ) {
Y
yamahigashi 已提交
2892

M
Mr.doob 已提交
2893 2894
				name = attrs[ 1 ].replace( /^(\w+)::/, '' );
				type = attrs[ 2 ];
Y
yamahigashi 已提交
2895

M
Mr.doob 已提交
2896
			}
Y
yamahigashi 已提交
2897

M
Mr.doob 已提交
2898
			return { id: id, name: name, type: type };
Y
yamahigashi 已提交
2899

M
Mr.doob 已提交
2900
		},
Y
yamahigashi 已提交
2901

M
Mr.doob 已提交
2902
		parseNodeProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
2903

M
Mr.doob 已提交
2904 2905
			var currentNode = this.getCurrentNode();
			var parentName = currentNode.name;
Y
yamahigashi 已提交
2906

2907 2908
			// special case where the parent node is something like "Properties70"
			// these children nodes must treated carefully
M
Mr.doob 已提交
2909
			if ( parentName !== undefined ) {
Y
yamahigashi 已提交
2910

M
Mr.doob 已提交
2911 2912
				var propMatch = parentName.match( /Properties(\d)+/ );
				if ( propMatch ) {
Y
yamahigashi 已提交
2913

M
Mr.doob 已提交
2914 2915
					this.parseNodeSpecialProperty( line, propName, propValue );
					return;
Y
yamahigashi 已提交
2916

M
Mr.doob 已提交
2917
				}
Y
yamahigashi 已提交
2918

M
Mr.doob 已提交
2919
			}
Y
yamahigashi 已提交
2920

2921
			// Connections
M
Mugen87 已提交
2922
			if ( propName === 'C' ) {
Y
yamahigashi 已提交
2923

M
Mr.doob 已提交
2924 2925 2926
				var connProps = propValue.split( ',' ).slice( 1 );
				var from = parseInt( connProps[ 0 ] );
				var to = parseInt( connProps[ 1 ] );
Y
yamahigashi 已提交
2927

M
Mr.doob 已提交
2928
				var rest = propValue.split( ',' ).slice( 3 );
Y
yamahigashi 已提交
2929

2930 2931 2932 2933 2934 2935
				rest = rest.map( function ( elem ) {

					return elem.trim().replace( /^"/, '' );

				} );

M
Mr.doob 已提交
2936 2937 2938
				propName = 'connections';
				propValue = [ from, to ];
				append( propValue, rest );
Y
yamahigashi 已提交
2939

M
Mr.doob 已提交
2940
				if ( currentNode.properties[ propName ] === undefined ) {
Y
yamahigashi 已提交
2941

M
Mr.doob 已提交
2942
					currentNode.properties[ propName ] = [];
Y
yamahigashi 已提交
2943

M
Mr.doob 已提交
2944
				}
Y
yamahigashi 已提交
2945

M
Mr.doob 已提交
2946
			}
Y
yamahigashi 已提交
2947

2948
			// Node
M
Mugen87 已提交
2949
			if ( propName === 'Node' ) {
Y
yamahigashi 已提交
2950

M
Mr.doob 已提交
2951 2952 2953
				var id = parseInt( propValue );
				currentNode.properties.id = id;
				currentNode.id = id;
Y
yamahigashi 已提交
2954

M
Mr.doob 已提交
2955
			}
Y
yamahigashi 已提交
2956

M
Mr.doob 已提交
2957 2958
			// already exists in properties, then append this
			if ( propName in currentNode.properties ) {
Y
yamahigashi 已提交
2959

M
Mr.doob 已提交
2960
				if ( Array.isArray( currentNode.properties[ propName ] ) ) {
Y
yamahigashi 已提交
2961

M
Mr.doob 已提交
2962
					currentNode.properties[ propName ].push( propValue );
Y
yamahigashi 已提交
2963

M
Mr.doob 已提交
2964
				} else {
Y
yamahigashi 已提交
2965

M
Mr.doob 已提交
2966
					currentNode.properties[ propName ] += propValue;
Y
yamahigashi 已提交
2967

M
Mr.doob 已提交
2968
				}
Y
yamahigashi 已提交
2969

M
Mr.doob 已提交
2970
			} else {
Y
yamahigashi 已提交
2971

M
Mr.doob 已提交
2972
				if ( Array.isArray( currentNode.properties[ propName ] ) ) {
Y
yamahigashi 已提交
2973

M
Mr.doob 已提交
2974
					currentNode.properties[ propName ].push( propValue );
Y
yamahigashi 已提交
2975

M
Mr.doob 已提交
2976
				} else {
Y
yamahigashi 已提交
2977

M
Mr.doob 已提交
2978
					currentNode.properties[ propName ] = propValue;
Y
yamahigashi 已提交
2979

M
Mr.doob 已提交
2980
				}
Y
yamahigashi 已提交
2981

M
Mr.doob 已提交
2982
			}
Y
yamahigashi 已提交
2983

M
Mr.doob 已提交
2984
			this.setCurrentProp( currentNode.properties, propName );
Y
yamahigashi 已提交
2985

2986 2987 2988 2989 2990 2991 2992
			// 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 已提交
2993
		},
Y
yamahigashi 已提交
2994

M
Mr.doob 已提交
2995
		parseNodePropertyContinued: function ( line ) {
Y
yamahigashi 已提交
2996

M
Mr.doob 已提交
2997
			this.currentProp[ this.currentPropName ] += line;
Y
yamahigashi 已提交
2998

2999 3000 3001 3002 3003 3004 3005 3006 3007
			// 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 已提交
3008
		},
Y
yamahigashi 已提交
3009

M
Mr.doob 已提交
3010
		parseNodeSpecialProperty: function ( line, propName, propValue ) {
Y
yamahigashi 已提交
3011

M
Mr.doob 已提交
3012 3013 3014 3015 3016
			// 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 已提交
3017

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

M
Mr.doob 已提交
3020
				props[ i ] = props[ i ].trim().replace( /^\"/, '' ).replace( /\s/, '_' );
L
Lewy Blue 已提交
3021

Y
yamahigashi 已提交
3022 3023
			}

M
Mr.doob 已提交
3024 3025 3026 3027 3028
			var innerPropName = props[ 0 ];
			var innerPropType1 = props[ 1 ];
			var innerPropType2 = props[ 2 ];
			var innerPropFlag = props[ 3 ];
			var innerPropValue = props[ 4 ];
Y
yamahigashi 已提交
3029

3030
			// cast value to its type
M
Mr.doob 已提交
3031
			switch ( innerPropType1 ) {
Y
yamahigashi 已提交
3032

M
Mugen87 已提交
3033
				case 'int':
3034 3035 3036
				case 'enum':
				case 'bool':
				case 'ULongLong':
M
Mr.doob 已提交
3037 3038
					innerPropValue = parseInt( innerPropValue );
					break;
Y
yamahigashi 已提交
3039

M
Mugen87 已提交
3040
				case 'double':
3041 3042
				case 'Number':
				case 'FieldOfView':
M
Mr.doob 已提交
3043 3044
					innerPropValue = parseFloat( innerPropValue );
					break;
Y
yamahigashi 已提交
3045

M
Mugen87 已提交
3046 3047
				case 'ColorRGB':
				case 'Vector3D':
3048 3049 3050
				case 'Lcl_Translation':
				case 'Lcl_Rotation':
				case 'Lcl_Scaling':
3051
					innerPropValue = parseNumberArray( innerPropValue );
M
Mr.doob 已提交
3052
					break;
Y
yamahigashi 已提交
3053

M
Mr.doob 已提交
3054
			}
Y
yamahigashi 已提交
3055

M
Mr.doob 已提交
3056 3057
			// CAUTION: these props must append to parent's parent
			this.getPrevNode().properties[ innerPropName ] = {
Y
yamahigashi 已提交
3058

M
Mr.doob 已提交
3059 3060 3061 3062
				'type': innerPropType1,
				'type2': innerPropType2,
				'flag': innerPropFlag,
				'value': innerPropValue
Y
yamahigashi 已提交
3063

M
Mr.doob 已提交
3064
			};
Y
yamahigashi 已提交
3065

M
Mr.doob 已提交
3066
			this.setCurrentProp( this.getPrevNode().properties, innerPropName );
Y
yamahigashi 已提交
3067

M
Mr.doob 已提交
3068
		},
3069

M
Mr.doob 已提交
3070
		nodeEnd: function () {
3071

M
Mr.doob 已提交
3072
			this.popStack();
3073

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

M
Mr.doob 已提交
3076
		isFlattenNode: function ( node ) {
Y
yamahigashi 已提交
3077

M
Mr.doob 已提交
3078
			return ( 'subNodes' in node && 'properties' in node ) ? true : false;
Y
yamahigashi 已提交
3079

M
Mr.doob 已提交
3080
		}
Y
yamahigashi 已提交
3081

M
Mr.doob 已提交
3082
	} );
Y
yamahigashi 已提交
3083

L
Lewy Blue 已提交
3084
	// Parse an FBX file in Binary format
L
Lewy Blue 已提交
3085
	function BinaryParser() {}
Y
yamahigashi 已提交
3086

M
Mr.doob 已提交
3087
	Object.assign( BinaryParser.prototype, {
Y
yamahigashi 已提交
3088

M
Mr.doob 已提交
3089
		parse: function ( buffer ) {
Y
yamahigashi 已提交
3090

M
Mr.doob 已提交
3091 3092
			var reader = new BinaryReader( buffer );
			reader.skip( 23 ); // skip magic 23 bytes
Y
yamahigashi 已提交
3093

M
Mr.doob 已提交
3094
			var version = reader.getUint32();
Y
yamahigashi 已提交
3095

M
Mugen87 已提交
3096
			console.log( 'THREE.FBXLoader: FBX binary version: ' + version );
Y
yamahigashi 已提交
3097

M
Mr.doob 已提交
3098
			var allNodes = new FBXTree();
Y
yamahigashi 已提交
3099

M
Mr.doob 已提交
3100
			while ( ! this.endOfContent( reader ) ) {
Y
yamahigashi 已提交
3101

M
Mr.doob 已提交
3102 3103
				var node = this.parseNode( reader, version );
				if ( node !== null ) allNodes.add( node.name, node );
Y
yamahigashi 已提交
3104

M
Mr.doob 已提交
3105
			}
3106

M
Mr.doob 已提交
3107
			return allNodes;
Y
yamahigashi 已提交
3108

M
Mr.doob 已提交
3109
		},
Y
yamahigashi 已提交
3110

L
Lewy Blue 已提交
3111
		// Check if reader has reached the end of content.
L
Lewy Blue 已提交
3112
		endOfContent: function ( reader ) {
M
Mr.doob 已提交
3113 3114 3115

			// footer size: 160bytes + 16-byte alignment padding
			// - 16bytes: magic
3116
			// - padding til 16-byte alignment (at least 1byte?)
L
Lewy Blue 已提交
3117
			//	(seems like some exporters embed fixed 15 or 16bytes?)
M
Mr.doob 已提交
3118 3119 3120 3121 3122 3123
			// - 4bytes: magic
			// - 4bytes: version
			// - 120bytes: zero
			// - 16bytes: magic
			if ( reader.size() % 16 === 0 ) {

L
Lewy Blue 已提交
3124
				return ( ( reader.getOffset() + 160 + 16 ) & ~ 0xf ) >= reader.size();
Y
yamahigashi 已提交
3125

M
Mr.doob 已提交
3126
			} else {
Y
yamahigashi 已提交
3127

3128
				return reader.getOffset() + 160 + 16 >= reader.size();
Y
yamahigashi 已提交
3129

M
Mr.doob 已提交
3130
			}
Y
yamahigashi 已提交
3131

M
Mr.doob 已提交
3132
		},
Y
yamahigashi 已提交
3133

M
Mr.doob 已提交
3134
		parseNode: function ( reader, version ) {
Y
yamahigashi 已提交
3135

M
Mr.doob 已提交
3136 3137 3138
			// 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 已提交
3139 3140

			// note: do not remove this even if you get a linter warning as it moves the buffer forward
M
Mr.doob 已提交
3141
			var propertyListLen = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();
L
tidying  
Lewy Blue 已提交
3142

M
Mr.doob 已提交
3143 3144
			var nameLen = reader.getUint8();
			var name = reader.getString( nameLen );
Y
yamahigashi 已提交
3145

M
Mr.doob 已提交
3146 3147
			// Regards this node as NULL-record if endOffset is zero
			if ( endOffset === 0 ) return null;
Y
yamahigashi 已提交
3148

M
Mr.doob 已提交
3149
			var propertyList = [];
Y
yamahigashi 已提交
3150

M
Mr.doob 已提交
3151
			for ( var i = 0; i < numProperties; i ++ ) {
Y
yamahigashi 已提交
3152

M
Mr.doob 已提交
3153
				propertyList.push( this.parseProperty( reader ) );
Y
yamahigashi 已提交
3154

M
Mr.doob 已提交
3155
			}
Y
yamahigashi 已提交
3156

M
Mr.doob 已提交
3157 3158 3159 3160
			// 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 已提交
3161

M
Mr.doob 已提交
3162 3163
			var subNodes = {};
			var properties = {};
Y
yamahigashi 已提交
3164

M
Mr.doob 已提交
3165
			var isSingleProperty = false;
Y
yamahigashi 已提交
3166

L
Lewy Blue 已提交
3167
			// check if this node represents just a single property
M
Mr.doob 已提交
3168 3169
			// 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 已提交
3170

M
Mr.doob 已提交
3171
				isSingleProperty = true;
Y
yamahigashi 已提交
3172

M
Mr.doob 已提交
3173
			}
Y
yamahigashi 已提交
3174

M
Mr.doob 已提交
3175
			while ( endOffset > reader.getOffset() ) {
Y
yamahigashi 已提交
3176

M
Mr.doob 已提交
3177
				var node = this.parseNode( reader, version );
Y
yamahigashi 已提交
3178

M
Mr.doob 已提交
3179
				if ( node === null ) continue;
Y
yamahigashi 已提交
3180

M
Mr.doob 已提交
3181 3182
				// special case: child node is single property
				if ( node.singleProperty === true ) {
Y
yamahigashi 已提交
3183

M
Mr.doob 已提交
3184
					var value = node.propertyList[ 0 ];
Y
yamahigashi 已提交
3185

M
Mr.doob 已提交
3186
					if ( Array.isArray( value ) ) {
Y
yamahigashi 已提交
3187

M
Mr.doob 已提交
3188 3189
						node.properties[ node.name ] = node.propertyList[ 0 ];
						subNodes[ node.name ] = node;
Y
yamahigashi 已提交
3190

3191
						node.properties.a = value;
Y
yamahigashi 已提交
3192

M
Mr.doob 已提交
3193
					} else {
Y
yamahigashi 已提交
3194

M
Mr.doob 已提交
3195
						properties[ node.name ] = value;
Y
yamahigashi 已提交
3196

M
Mr.doob 已提交
3197
					}
Y
yamahigashi 已提交
3198

M
Mr.doob 已提交
3199
					continue;
Y
yamahigashi 已提交
3200

M
Mr.doob 已提交
3201
				}
Y
yamahigashi 已提交
3202

L
Lewy Blue 已提交
3203
				// parse connections
M
Mr.doob 已提交
3204
				if ( name === 'Connections' && node.name === 'C' ) {
Y
yamahigashi 已提交
3205

M
Mr.doob 已提交
3206
					var array = [];
Y
yamahigashi 已提交
3207

M
Mr.doob 已提交
3208
					for ( var i = 1, il = node.propertyList.length; i < il; i ++ ) {
Y
yamahigashi 已提交
3209

M
Mr.doob 已提交
3210
						array[ i - 1 ] = node.propertyList[ i ];
Y
yamahigashi 已提交
3211

M
Mr.doob 已提交
3212
					}
Y
yamahigashi 已提交
3213

M
Mr.doob 已提交
3214
					if ( properties.connections === undefined ) {
Y
yamahigashi 已提交
3215

M
Mr.doob 已提交
3216
						properties.connections = [];
Y
yamahigashi 已提交
3217

M
Mr.doob 已提交
3218
					}
Y
yamahigashi 已提交
3219

M
Mr.doob 已提交
3220
					properties.connections.push( array );
Y
yamahigashi 已提交
3221

M
Mr.doob 已提交
3222
					continue;
Y
yamahigashi 已提交
3223

M
Mr.doob 已提交
3224
				}
Y
yamahigashi 已提交
3225

M
Mr.doob 已提交
3226
				// special case: child node is Properties\d+
L
Lewy Blue 已提交
3227
				// move child node's properties to this node.
M
Mr.doob 已提交
3228
				if ( node.name.match( /^Properties\d+$/ ) ) {
Y
yamahigashi 已提交
3229

M
Mr.doob 已提交
3230
					var keys = Object.keys( node.properties );
Y
yamahigashi 已提交
3231

M
Mr.doob 已提交
3232
					for ( var i = 0, il = keys.length; i < il; i ++ ) {
Y
yamahigashi 已提交
3233

M
Mr.doob 已提交
3234 3235
						var key = keys[ i ];
						properties[ key ] = node.properties[ key ];
Y
yamahigashi 已提交
3236

M
Mr.doob 已提交
3237
					}
Y
yamahigashi 已提交
3238

M
Mr.doob 已提交
3239
					continue;
Y
yamahigashi 已提交
3240

M
Mr.doob 已提交
3241
				}
Y
yamahigashi 已提交
3242

L
Lewy Blue 已提交
3243
				// parse 'properties70'
M
Mr.doob 已提交
3244
				if ( name.match( /^Properties\d+$/ ) && node.name === 'P' ) {
Y
yamahigashi 已提交
3245

M
Mr.doob 已提交
3246 3247 3248 3249 3250
					var innerPropName = node.propertyList[ 0 ];
					var innerPropType1 = node.propertyList[ 1 ];
					var innerPropType2 = node.propertyList[ 2 ];
					var innerPropFlag = node.propertyList[ 3 ];
					var innerPropValue;
Y
yamahigashi 已提交
3251

M
Mr.doob 已提交
3252 3253
					if ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );
					if ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );
Y
yamahigashi 已提交
3254

L
Lewy Blue 已提交
3255
					if ( innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' || innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {
Y
yamahigashi 已提交
3256

M
Mr.doob 已提交
3257 3258 3259 3260 3261
						innerPropValue = [
							node.propertyList[ 4 ],
							node.propertyList[ 5 ],
							node.propertyList[ 6 ]
						];
Y
yamahigashi 已提交
3262

M
Mr.doob 已提交
3263
					} else {
Y
yamahigashi 已提交
3264

M
Mr.doob 已提交
3265
						innerPropValue = node.propertyList[ 4 ];
Y
yamahigashi 已提交
3266

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

L
Lewy Blue 已提交
3269
					// this will be copied to parent, see above
M
Mr.doob 已提交
3270
					properties[ innerPropName ] = {
Y
yamahigashi 已提交
3271

M
Mr.doob 已提交
3272 3273 3274 3275
						'type': innerPropType1,
						'type2': innerPropType2,
						'flag': innerPropFlag,
						'value': innerPropValue
Y
yamahigashi 已提交
3276

M
Mr.doob 已提交
3277
					};
Y
yamahigashi 已提交
3278

M
Mr.doob 已提交
3279
					continue;
Y
yamahigashi 已提交
3280

M
Mr.doob 已提交
3281
				}
Y
yamahigashi 已提交
3282

M
Mr.doob 已提交
3283
				if ( subNodes[ node.name ] === undefined ) {
Y
yamahigashi 已提交
3284

M
Mr.doob 已提交
3285
					if ( typeof node.id === 'number' ) {
K
Kyle Larson 已提交
3286

M
Mr.doob 已提交
3287 3288
						subNodes[ node.name ] = {};
						subNodes[ node.name ][ node.id ] = node;
Y
yamahigashi 已提交
3289

M
Mr.doob 已提交
3290
					} else {
Y
yamahigashi 已提交
3291

M
Mr.doob 已提交
3292
						subNodes[ node.name ] = node;
Y
yamahigashi 已提交
3293

M
Mr.doob 已提交
3294
					}
Y
yamahigashi 已提交
3295

M
Mr.doob 已提交
3296
				} else {
Y
yamahigashi 已提交
3297

M
Mr.doob 已提交
3298
					if ( node.id === '' ) {
Y
yamahigashi 已提交
3299

M
Mr.doob 已提交
3300
						if ( ! Array.isArray( subNodes[ node.name ] ) ) {
Y
yamahigashi 已提交
3301

M
Mr.doob 已提交
3302
							subNodes[ node.name ] = [ subNodes[ node.name ] ];
Y
yamahigashi 已提交
3303

M
Mr.doob 已提交
3304
						}
Y
yamahigashi 已提交
3305

M
Mr.doob 已提交
3306
						subNodes[ node.name ].push( node );
Y
yamahigashi 已提交
3307

M
Mr.doob 已提交
3308
					} else {
Y
yamahigashi 已提交
3309

M
Mr.doob 已提交
3310
						if ( subNodes[ node.name ][ node.id ] === undefined ) {
Y
yamahigashi 已提交
3311

M
Mr.doob 已提交
3312
							subNodes[ node.name ][ node.id ] = node;
Y
yamahigashi 已提交
3313

M
Mr.doob 已提交
3314
						} else {
Y
yamahigashi 已提交
3315

M
Mr.doob 已提交
3316 3317
							// conflict id. irregular?
							if ( ! Array.isArray( subNodes[ node.name ][ node.id ] ) ) {
Y
yamahigashi 已提交
3318

M
Mr.doob 已提交
3319
								subNodes[ node.name ][ node.id ] = [ subNodes[ node.name ][ node.id ] ];
Y
yamahigashi 已提交
3320

M
Mr.doob 已提交
3321
							}
Y
yamahigashi 已提交
3322

M
Mr.doob 已提交
3323
							subNodes[ node.name ][ node.id ].push( node );
K
Kyle Larson 已提交
3324

M
Mr.doob 已提交
3325
						}
K
Kyle Larson 已提交
3326

M
Mr.doob 已提交
3327
					}
K
Kyle Larson 已提交
3328

M
Mr.doob 已提交
3329
				}
K
Kyle Larson 已提交
3330

M
Mr.doob 已提交
3331
			}
K
Kyle Larson 已提交
3332

M
Mr.doob 已提交
3333
			return {
K
Kyle Larson 已提交
3334

M
Mr.doob 已提交
3335 3336 3337 3338 3339 3340
				singleProperty: isSingleProperty,
				id: id,
				attrName: attrName,
				attrType: attrType,
				name: name,
				properties: properties,
L
Lewy Blue 已提交
3341
				propertyList: propertyList, // raw property list used by parent
M
Mr.doob 已提交
3342
				subNodes: subNodes
K
Kyle Larson 已提交
3343

M
Mr.doob 已提交
3344
			};
K
Kyle Larson 已提交
3345

M
Mr.doob 已提交
3346
		},
K
Kyle Larson 已提交
3347

M
Mr.doob 已提交
3348
		parseProperty: function ( reader ) {
K
Kyle Larson 已提交
3349

M
Mr.doob 已提交
3350
			var type = reader.getChar();
K
Kyle Larson 已提交
3351

M
Mr.doob 已提交
3352
			switch ( type ) {
K
Kyle Larson 已提交
3353

3354 3355
				case 'C':
					return reader.getBoolean();
K
Kyle Larson 已提交
3356

M
Mr.doob 已提交
3357 3358
				case 'D':
					return reader.getFloat64();
K
Kyle Larson 已提交
3359

3360 3361
				case 'F':
					return reader.getFloat32();
K
Kyle Larson 已提交
3362

M
Mr.doob 已提交
3363 3364
				case 'I':
					return reader.getInt32();
K
Kyle Larson 已提交
3365

3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376
				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 已提交
3377 3378
				case 'Y':
					return reader.getInt16();
K
Kyle Larson 已提交
3379

3380 3381
				case 'b':
				case 'c':
M
Mr.doob 已提交
3382
				case 'd':
3383
				case 'f':
M
Mr.doob 已提交
3384
				case 'i':
3385
				case 'l':
K
Kyle Larson 已提交
3386

M
Mr.doob 已提交
3387 3388 3389
					var arrayLength = reader.getUint32();
					var encoding = reader.getUint32(); // 0: non-compressed, 1: compressed
					var compressedLength = reader.getUint32();
K
Kyle Larson 已提交
3390

M
Mr.doob 已提交
3391
					if ( encoding === 0 ) {
K
Kyle Larson 已提交
3392

M
Mr.doob 已提交
3393
						switch ( type ) {
K
Kyle Larson 已提交
3394

3395 3396 3397
							case 'b':
							case 'c':
								return reader.getBooleanArray( arrayLength );
K
Kyle Larson 已提交
3398

M
Mr.doob 已提交
3399 3400
							case 'd':
								return reader.getFloat64Array( arrayLength );
K
Kyle Larson 已提交
3401

3402 3403
							case 'f':
								return reader.getFloat32Array( arrayLength );
K
Kyle Larson 已提交
3404

M
Mr.doob 已提交
3405 3406
							case 'i':
								return reader.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3407

3408 3409
							case 'l':
								return reader.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3410

M
Mr.doob 已提交
3411
						}
Y
yamahigashi 已提交
3412

M
Mr.doob 已提交
3413
					}
Y
yamahigashi 已提交
3414

M
Mr.doob 已提交
3415
					if ( window.Zlib === undefined ) {
Y
yamahigashi 已提交
3416

M
Mugen87 已提交
3417
						throw new Error( 'THREE.FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
Y
yamahigashi 已提交
3418

M
Mr.doob 已提交
3419
					}
Y
yamahigashi 已提交
3420

L
Lewy Blue 已提交
3421
					var inflate = new Zlib.Inflate( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) ); // eslint-disable-line no-undef
M
Mr.doob 已提交
3422
					var reader2 = new BinaryReader( inflate.decompress().buffer );
Y
yamahigashi 已提交
3423

M
Mr.doob 已提交
3424
					switch ( type ) {
Y
yamahigashi 已提交
3425

3426 3427 3428
						case 'b':
						case 'c':
							return reader2.getBooleanArray( arrayLength );
Y
yamahigashi 已提交
3429

M
Mr.doob 已提交
3430 3431
						case 'd':
							return reader2.getFloat64Array( arrayLength );
Y
yamahigashi 已提交
3432

3433 3434
						case 'f':
							return reader2.getFloat32Array( arrayLength );
Y
yamahigashi 已提交
3435

M
Mr.doob 已提交
3436 3437
						case 'i':
							return reader2.getInt32Array( arrayLength );
Y
yamahigashi 已提交
3438

3439 3440
						case 'l':
							return reader2.getInt64Array( arrayLength );
Y
yamahigashi 已提交
3441

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

M
Mr.doob 已提交
3444
				default:
M
Mugen87 已提交
3445
					throw new Error( 'THREE.FBXLoader: Unknown property type ' + type );
Y
yamahigashi 已提交
3446

M
Mr.doob 已提交
3447
			}
Y
yamahigashi 已提交
3448

M
Mr.doob 已提交
3449
		}
Y
yamahigashi 已提交
3450

M
Mr.doob 已提交
3451
	} );
Y
yamahigashi 已提交
3452 3453


M
Mr.doob 已提交
3454
	function BinaryReader( buffer, littleEndian ) {
Y
yamahigashi 已提交
3455

M
Mr.doob 已提交
3456 3457 3458
		this.dv = new DataView( buffer );
		this.offset = 0;
		this.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;
Y
yamahigashi 已提交
3459

M
Mr.doob 已提交
3460
	}
Y
yamahigashi 已提交
3461

M
Mr.doob 已提交
3462
	Object.assign( BinaryReader.prototype, {
Y
yamahigashi 已提交
3463

M
Mr.doob 已提交
3464
		getOffset: function () {
Y
yamahigashi 已提交
3465

M
Mr.doob 已提交
3466
			return this.offset;
Y
yamahigashi 已提交
3467

M
Mr.doob 已提交
3468
		},
Y
yamahigashi 已提交
3469

M
Mr.doob 已提交
3470
		size: function () {
Y
yamahigashi 已提交
3471

M
Mr.doob 已提交
3472
			return this.dv.buffer.byteLength;
Y
yamahigashi 已提交
3473

M
Mr.doob 已提交
3474
		},
Y
yamahigashi 已提交
3475

M
Mr.doob 已提交
3476
		skip: function ( length ) {
Y
yamahigashi 已提交
3477

M
Mr.doob 已提交
3478
			this.offset += length;
Y
yamahigashi 已提交
3479

M
Mr.doob 已提交
3480
		},
Y
yamahigashi 已提交
3481

M
Mr.doob 已提交
3482
		// seems like true/false representation depends on exporter.
L
Lewy Blue 已提交
3483
		// true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)
M
Mr.doob 已提交
3484 3485
		// then sees LSB.
		getBoolean: function () {
Y
yamahigashi 已提交
3486

M
Mr.doob 已提交
3487
			return ( this.getUint8() & 1 ) === 1;
Y
yamahigashi 已提交
3488

M
Mr.doob 已提交
3489
		},
Y
yamahigashi 已提交
3490

M
Mr.doob 已提交
3491
		getBooleanArray: function ( size ) {
Y
yamahigashi 已提交
3492

M
Mr.doob 已提交
3493
			var a = [];
Y
yamahigashi 已提交
3494

M
Mr.doob 已提交
3495
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3496

M
Mr.doob 已提交
3497
				a.push( this.getBoolean() );
Y
yamahigashi 已提交
3498 3499 3500

			}

M
Mr.doob 已提交
3501
			return a;
Y
yamahigashi 已提交
3502

M
Mr.doob 已提交
3503
		},
Y
yamahigashi 已提交
3504

M
Mr.doob 已提交
3505
		getInt8: function () {
Y
yamahigashi 已提交
3506

M
Mr.doob 已提交
3507 3508 3509
			var value = this.dv.getInt8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
3510

M
Mr.doob 已提交
3511
		},
Y
yamahigashi 已提交
3512

M
Mr.doob 已提交
3513
		getInt8Array: function ( size ) {
Y
yamahigashi 已提交
3514

M
Mr.doob 已提交
3515
			var a = [];
Y
yamahigashi 已提交
3516

M
Mr.doob 已提交
3517
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3518

M
Mr.doob 已提交
3519
				a.push( this.getInt8() );
Y
yamahigashi 已提交
3520

M
Mr.doob 已提交
3521
			}
Y
yamahigashi 已提交
3522

M
Mr.doob 已提交
3523
			return a;
Y
yamahigashi 已提交
3524

M
Mr.doob 已提交
3525
		},
Y
yamahigashi 已提交
3526

M
Mr.doob 已提交
3527
		getUint8: function () {
Y
yamahigashi 已提交
3528

M
Mr.doob 已提交
3529 3530 3531
			var value = this.dv.getUint8( this.offset );
			this.offset += 1;
			return value;
Y
yamahigashi 已提交
3532

M
Mr.doob 已提交
3533
		},
Y
yamahigashi 已提交
3534

M
Mr.doob 已提交
3535
		getUint8Array: function ( size ) {
Y
yamahigashi 已提交
3536

M
Mr.doob 已提交
3537
			var a = [];
Y
yamahigashi 已提交
3538

M
Mr.doob 已提交
3539
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3540

M
Mr.doob 已提交
3541
				a.push( this.getUint8() );
Y
yamahigashi 已提交
3542 3543 3544

			}

M
Mr.doob 已提交
3545
			return a;
Y
yamahigashi 已提交
3546

M
Mr.doob 已提交
3547
		},
Y
yamahigashi 已提交
3548

M
Mr.doob 已提交
3549
		getInt16: function () {
Y
yamahigashi 已提交
3550

M
Mr.doob 已提交
3551 3552 3553
			var value = this.dv.getInt16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
3554

M
Mr.doob 已提交
3555
		},
Y
yamahigashi 已提交
3556

M
Mr.doob 已提交
3557
		getInt16Array: function ( size ) {
Y
yamahigashi 已提交
3558

M
Mr.doob 已提交
3559
			var a = [];
Y
yamahigashi 已提交
3560

M
Mr.doob 已提交
3561
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3562

M
Mr.doob 已提交
3563
				a.push( this.getInt16() );
Y
yamahigashi 已提交
3564

M
Mr.doob 已提交
3565
			}
Y
yamahigashi 已提交
3566

M
Mr.doob 已提交
3567
			return a;
3568

M
Mr.doob 已提交
3569
		},
3570

M
Mr.doob 已提交
3571
		getUint16: function () {
Y
yamahigashi 已提交
3572

M
Mr.doob 已提交
3573 3574 3575
			var value = this.dv.getUint16( this.offset, this.littleEndian );
			this.offset += 2;
			return value;
Y
yamahigashi 已提交
3576

M
Mr.doob 已提交
3577
		},
Y
yamahigashi 已提交
3578

M
Mr.doob 已提交
3579
		getUint16Array: function ( size ) {
Y
yamahigashi 已提交
3580

M
Mr.doob 已提交
3581
			var a = [];
Y
yamahigashi 已提交
3582

M
Mr.doob 已提交
3583
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3584

M
Mr.doob 已提交
3585
				a.push( this.getUint16() );
Y
yamahigashi 已提交
3586 3587 3588

			}

M
Mr.doob 已提交
3589
			return a;
Y
yamahigashi 已提交
3590

M
Mr.doob 已提交
3591
		},
3592

M
Mr.doob 已提交
3593
		getInt32: function () {
3594

M
Mr.doob 已提交
3595 3596 3597
			var value = this.dv.getInt32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
3598

M
Mr.doob 已提交
3599
		},
3600

M
Mr.doob 已提交
3601
		getInt32Array: function ( size ) {
3602

M
Mr.doob 已提交
3603
			var a = [];
3604

M
Mr.doob 已提交
3605
			for ( var i = 0; i < size; i ++ ) {
3606

M
Mr.doob 已提交
3607
				a.push( this.getInt32() );
3608 3609 3610

			}

M
Mr.doob 已提交
3611
			return a;
3612

M
Mr.doob 已提交
3613
		},
3614

M
Mr.doob 已提交
3615
		getUint32: function () {
3616

M
Mr.doob 已提交
3617 3618 3619 3620 3621
			var value = this.dv.getUint32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;

		},
3622

M
Mr.doob 已提交
3623
		getUint32Array: function ( size ) {
3624

M
Mr.doob 已提交
3625
			var a = [];
3626

M
Mr.doob 已提交
3627
			for ( var i = 0; i < size; i ++ ) {
3628

M
Mr.doob 已提交
3629
				a.push( this.getUint32() );
3630

M
Mr.doob 已提交
3631
			}
3632

M
Mr.doob 已提交
3633
			return a;
3634

M
Mr.doob 已提交
3635
		},
3636

L
Lewy Blue 已提交
3637
		// JavaScript doesn't support 64-bit integer so calculate this here
M
Mr.doob 已提交
3638
		// 1 << 32 will return 1 so using multiply operation instead here.
L
Lewy Blue 已提交
3639
		// There's a possibility that this method returns wrong value if the value
M
Mr.doob 已提交
3640 3641 3642
		// is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.
		// TODO: safely handle 64-bit integer
		getInt64: function () {
3643

M
Mr.doob 已提交
3644
			var low, high;
3645

M
Mr.doob 已提交
3646
			if ( this.littleEndian ) {
3647

M
Mr.doob 已提交
3648 3649
				low = this.getUint32();
				high = this.getUint32();
3650

M
Mr.doob 已提交
3651
			} else {
3652

M
Mr.doob 已提交
3653 3654
				high = this.getUint32();
				low = this.getUint32();
3655

M
Mr.doob 已提交
3656
			}
3657

M
Mr.doob 已提交
3658 3659
			// calculate negative value
			if ( high & 0x80000000 ) {
3660

L
Lewy Blue 已提交
3661 3662
				high = ~ high & 0xFFFFFFFF;
				low = ~ low & 0xFFFFFFFF;
3663

M
Mr.doob 已提交
3664
				if ( low === 0xFFFFFFFF ) high = ( high + 1 ) & 0xFFFFFFFF;
3665

M
Mr.doob 已提交
3666
				low = ( low + 1 ) & 0xFFFFFFFF;
3667

M
Mr.doob 已提交
3668
				return - ( high * 0x100000000 + low );
3669

M
Mr.doob 已提交
3670
			}
3671

M
Mr.doob 已提交
3672
			return high * 0x100000000 + low;
3673

M
Mr.doob 已提交
3674
		},
3675

M
Mr.doob 已提交
3676
		getInt64Array: function ( size ) {
3677

M
Mr.doob 已提交
3678
			var a = [];
3679

M
Mr.doob 已提交
3680
			for ( var i = 0; i < size; i ++ ) {
3681

M
Mr.doob 已提交
3682
				a.push( this.getInt64() );
3683 3684 3685

			}

M
Mr.doob 已提交
3686 3687 3688
			return a;

		},
3689

M
Mr.doob 已提交
3690 3691
		// Note: see getInt64() comment
		getUint64: function () {
3692

M
Mr.doob 已提交
3693
			var low, high;
3694

M
Mr.doob 已提交
3695 3696 3697 3698 3699 3700 3701 3702 3703
			if ( this.littleEndian ) {

				low = this.getUint32();
				high = this.getUint32();

			} else {

				high = this.getUint32();
				low = this.getUint32();
3704 3705

			}
3706

M
Mr.doob 已提交
3707
			return high * 0x100000000 + low;
3708

M
Mr.doob 已提交
3709
		},
Y
yamahigashi 已提交
3710

M
Mr.doob 已提交
3711
		getUint64Array: function ( size ) {
Y
yamahigashi 已提交
3712

M
Mr.doob 已提交
3713
			var a = [];
Y
yamahigashi 已提交
3714

M
Mr.doob 已提交
3715
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3716

M
Mr.doob 已提交
3717
				a.push( this.getUint64() );
Y
yamahigashi 已提交
3718

M
Mr.doob 已提交
3719
			}
Y
yamahigashi 已提交
3720

M
Mr.doob 已提交
3721
			return a;
Y
yamahigashi 已提交
3722

M
Mr.doob 已提交
3723
		},
K
Kyle Larson 已提交
3724

M
Mr.doob 已提交
3725
		getFloat32: function () {
Y
yamahigashi 已提交
3726

M
Mr.doob 已提交
3727 3728 3729
			var value = this.dv.getFloat32( this.offset, this.littleEndian );
			this.offset += 4;
			return value;
Y
yamahigashi 已提交
3730

M
Mr.doob 已提交
3731
		},
Y
yamahigashi 已提交
3732

M
Mr.doob 已提交
3733
		getFloat32Array: function ( size ) {
Y
yamahigashi 已提交
3734

M
Mr.doob 已提交
3735
			var a = [];
Y
yamahigashi 已提交
3736

M
Mr.doob 已提交
3737
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3738

M
Mr.doob 已提交
3739
				a.push( this.getFloat32() );
Y
yamahigashi 已提交
3740 3741 3742

			}

M
Mr.doob 已提交
3743
			return a;
Y
yamahigashi 已提交
3744

M
Mr.doob 已提交
3745
		},
Y
yamahigashi 已提交
3746

M
Mr.doob 已提交
3747
		getFloat64: function () {
Y
yamahigashi 已提交
3748

M
Mr.doob 已提交
3749 3750 3751
			var value = this.dv.getFloat64( this.offset, this.littleEndian );
			this.offset += 8;
			return value;
Y
yamahigashi 已提交
3752

M
Mr.doob 已提交
3753
		},
Y
yamahigashi 已提交
3754

M
Mr.doob 已提交
3755
		getFloat64Array: function ( size ) {
Y
yamahigashi 已提交
3756

M
Mr.doob 已提交
3757
			var a = [];
Y
yamahigashi 已提交
3758

M
Mr.doob 已提交
3759
			for ( var i = 0; i < size; i ++ ) {
Y
yamahigashi 已提交
3760

M
Mr.doob 已提交
3761
				a.push( this.getFloat64() );
Y
yamahigashi 已提交
3762

M
Mr.doob 已提交
3763
			}
Y
yamahigashi 已提交
3764

M
Mr.doob 已提交
3765
			return a;
Y
yamahigashi 已提交
3766

M
Mr.doob 已提交
3767
		},
Y
yamahigashi 已提交
3768

M
Mr.doob 已提交
3769
		getArrayBuffer: function ( size ) {
Y
yamahigashi 已提交
3770

M
Mr.doob 已提交
3771 3772 3773
			var value = this.dv.buffer.slice( this.offset, this.offset + size );
			this.offset += size;
			return value;
Y
yamahigashi 已提交
3774

M
Mr.doob 已提交
3775
		},
Y
yamahigashi 已提交
3776

M
Mr.doob 已提交
3777
		getChar: function () {
Y
yamahigashi 已提交
3778

M
Mr.doob 已提交
3779
			return String.fromCharCode( this.getUint8() );
Y
yamahigashi 已提交
3780

M
Mr.doob 已提交
3781
		},
Y
yamahigashi 已提交
3782

M
Mr.doob 已提交
3783
		getString: function ( size ) {
Y
yamahigashi 已提交
3784

M
Mr.doob 已提交
3785
			var s = '';
Y
yamahigashi 已提交
3786

M
Mr.doob 已提交
3787
			while ( size > 0 ) {
Y
yamahigashi 已提交
3788

M
Mr.doob 已提交
3789
				var value = this.getUint8();
L
Lewy Blue 已提交
3790
				size --;
Y
yamahigashi 已提交
3791

M
Mr.doob 已提交
3792
				if ( value === 0 ) break;
Y
yamahigashi 已提交
3793

M
Mr.doob 已提交
3794
				s += String.fromCharCode( value );
Y
yamahigashi 已提交
3795

M
Mr.doob 已提交
3796
			}
Y
yamahigashi 已提交
3797

L
Lewy Blue 已提交
3798 3799 3800
			// Manage UTF8 encoding
			s = decodeURIComponent( escape( s ) );

M
Mr.doob 已提交
3801
			this.skip( size );
Y
yamahigashi 已提交
3802

M
Mr.doob 已提交
3803
			return s;
Y
yamahigashi 已提交
3804

M
Mr.doob 已提交
3805
		}
Y
yamahigashi 已提交
3806

M
Mr.doob 已提交
3807
	} );
Y
yamahigashi 已提交
3808

L
Lewy Blue 已提交
3809 3810
	// FBXTree holds a representation of the FBX data, returned by the TextParser ( FBX ASCII format)
	// and BinaryParser( FBX Binary format)
L
Lewy Blue 已提交
3811
	function FBXTree() {}
Y
yamahigashi 已提交
3812

M
Mr.doob 已提交
3813
	Object.assign( FBXTree.prototype, {
Y
yamahigashi 已提交
3814

M
Mr.doob 已提交
3815
		add: function ( key, val ) {
Y
yamahigashi 已提交
3816

M
Mr.doob 已提交
3817
			this[ key ] = val;
Y
yamahigashi 已提交
3818

M
Mr.doob 已提交
3819
		},
Y
yamahigashi 已提交
3820

M
Mr.doob 已提交
3821
	} );
Y
yamahigashi 已提交
3822

M
Mr.doob 已提交
3823
	function isFbxFormatBinary( buffer ) {
Y
yamahigashi 已提交
3824

M
Mr.doob 已提交
3825
		var CORRECT = 'Kaydara FBX Binary  \0';
Y
yamahigashi 已提交
3826

M
Mr.doob 已提交
3827
		return buffer.byteLength >= CORRECT.length && CORRECT === convertArrayBufferToString( buffer, 0, CORRECT.length );
Y
yamahigashi 已提交
3828

M
Mr.doob 已提交
3829
	}
Y
yamahigashi 已提交
3830

M
Mr.doob 已提交
3831
	function isFbxFormatASCII( text ) {
Y
yamahigashi 已提交
3832

M
Mr.doob 已提交
3833
		var CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\', 'F', 'B', 'X', '\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\', '\\' ];
Y
yamahigashi 已提交
3834

M
Mr.doob 已提交
3835
		var cursor = 0;
Y
yamahigashi 已提交
3836

M
Mr.doob 已提交
3837
		function read( offset ) {
Y
yamahigashi 已提交
3838

M
Mr.doob 已提交
3839 3840 3841 3842
			var result = text[ offset - 1 ];
			text = text.slice( cursor + offset );
			cursor ++;
			return result;
Y
yamahigashi 已提交
3843 3844 3845

		}

M
Mr.doob 已提交
3846
		for ( var i = 0; i < CORRECT.length; ++ i ) {
Y
yamahigashi 已提交
3847

M
Mr.doob 已提交
3848
			var num = read( 1 );
M
Mugen87 已提交
3849
			if ( num === CORRECT[ i ] ) {
Y
yamahigashi 已提交
3850

M
Mr.doob 已提交
3851
				return false;
Y
yamahigashi 已提交
3852 3853 3854

			}

M
Mr.doob 已提交
3855
		}
Y
yamahigashi 已提交
3856

M
Mr.doob 已提交
3857
		return true;
Y
yamahigashi 已提交
3858

M
Mr.doob 已提交
3859
	}
Y
yamahigashi 已提交
3860

M
Mr.doob 已提交
3861
	function getFbxVersion( text ) {
Y
yamahigashi 已提交
3862

M
Mr.doob 已提交
3863 3864 3865 3866 3867 3868
		var versionRegExp = /FBXVersion: (\d+)/;
		var match = text.match( versionRegExp );
		if ( match ) {

			var version = parseInt( match[ 1 ] );
			return version;
Y
yamahigashi 已提交
3869 3870

		}
M
Mugen87 已提交
3871
		throw new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );
Y
yamahigashi 已提交
3872

M
Mr.doob 已提交
3873 3874
	}

L
Lewy Blue 已提交
3875
	// Converts FBX ticks into real time seconds.
M
Mr.doob 已提交
3876 3877 3878
	function convertFBXTimeToSeconds( time ) {

		return time / 46186158000;
Y
yamahigashi 已提交
3879

K
Kyle Larson 已提交
3880
	}
Y
yamahigashi 已提交
3881

L
Lewy Blue 已提交
3882 3883 3884

	// Parses comma separated list of numbers and returns them an array.
	// Used internally by the TextParser
3885
	function parseNumberArray( value ) {
Y
yamahigashi 已提交
3886

3887
		var array = value.split( ',' );
Y
yamahigashi 已提交
3888

M
Mr.doob 已提交
3889
		for ( var i = 0, l = array.length; i < l; i ++ ) {
Y
yamahigashi 已提交
3890

3891
			array[ i ] = parseFloat( array[ i ] );
Y
yamahigashi 已提交
3892 3893 3894

		}

M
Mr.doob 已提交
3895
		return array;
Y
yamahigashi 已提交
3896

M
Mr.doob 已提交
3897
	}
Y
yamahigashi 已提交
3898

M
Mr.doob 已提交
3899
	function parseVector3( property ) {
Y
yamahigashi 已提交
3900

M
Mr.doob 已提交
3901
		return new THREE.Vector3().fromArray( property.value );
Y
yamahigashi 已提交
3902

M
Mr.doob 已提交
3903
	}
Y
yamahigashi 已提交
3904

M
Mr.doob 已提交
3905
	function parseColor( property ) {
Y
yamahigashi 已提交
3906

M
Mr.doob 已提交
3907
		return new THREE.Color().fromArray( property.value );
Y
yamahigashi 已提交
3908 3909 3910

	}

L
Lewy Blue 已提交
3911
	// Converts ArrayBuffer to String.
M
Mr.doob 已提交
3912
	function convertArrayBufferToString( buffer, from, to ) {
Y
yamahigashi 已提交
3913

M
Mr.doob 已提交
3914 3915
		if ( from === undefined ) from = 0;
		if ( to === undefined ) to = buffer.byteLength;
Y
yamahigashi 已提交
3916

M
Mr.doob 已提交
3917
		var array = new Uint8Array( buffer, from, to );
Y
yamahigashi 已提交
3918

3919 3920 3921 3922 3923 3924
		if ( window.TextDecoder !== undefined ) {

			return new TextDecoder().decode( array );

		}

M
Mr.doob 已提交
3925
		var s = '';
Y
yamahigashi 已提交
3926

M
Mr.doob 已提交
3927
		for ( var i = 0, il = array.length; i < il; i ++ ) {
Y
yamahigashi 已提交
3928

M
Mr.doob 已提交
3929
			s += String.fromCharCode( array[ i ] );
Y
yamahigashi 已提交
3930

M
Mr.doob 已提交
3931
		}
Y
yamahigashi 已提交
3932

M
Mr.doob 已提交
3933
		return s;
Y
yamahigashi 已提交
3934

M
Mr.doob 已提交
3935
	}
Y
yamahigashi 已提交
3936

M
Mr.doob 已提交
3937
	function findIndex( array, func ) {
Y
yamahigashi 已提交
3938

M
Mr.doob 已提交
3939 3940 3941 3942 3943 3944
		for ( var i = 0, l = array.length; i < l; i ++ ) {

			if ( func( array[ i ] ) ) return i;

		}

L
Lewy Blue 已提交
3945
		return - 1;
Y
yamahigashi 已提交
3946

3947
	}
Y
yamahigashi 已提交
3948

M
Mr.doob 已提交
3949
	function append( a, b ) {
Y
yamahigashi 已提交
3950

M
Mr.doob 已提交
3951
		for ( var i = 0, j = a.length, l = b.length; i < l; i ++, j ++ ) {
Y
yamahigashi 已提交
3952

M
Mr.doob 已提交
3953
			a[ j ] = b[ i ];
Y
yamahigashi 已提交
3954

M
Mr.doob 已提交
3955
		}
Y
yamahigashi 已提交
3956

3957
	}
Y
yamahigashi 已提交
3958

M
Mr.doob 已提交
3959 3960 3961 3962 3963 3964 3965
	function slice( a, b, from, to ) {

		for ( var i = from, j = 0; i < to; i ++, j ++ ) {

			a[ j ] = b[ i ];

		}
Y
yamahigashi 已提交
3966

M
Mr.doob 已提交
3967
		return a;
Y
yamahigashi 已提交
3968

3969
	}
Y
yamahigashi 已提交
3970 3971

} )();