├── README.md
├── index.html
└── js
├── Detector.js
├── 3d.js
└── ColladaLoader.js
/README.md:
--------------------------------------------------------------------------------
1 | A simple WebGL viewer for Collada files (.dae) based on Three.js.
2 |
3 | This project was started by Herbert Braun and featured in c't Magazin 13/2013. More information about the project: www.woerter.de/textverzeichnis/#filter/id=148 (in German).
4 |
5 | Comments and variable names are in German. I'll gladly translate them if there is demand.
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 3D-Modell-Test
5 |
6 |
7 |
8 |
9 |
29 |
30 |
31 |
32 |
33 | Steuerung der Animation per Tastatur:
34 |
35 | - Leertaste
36 | - Pause
37 | - Pfeil links/rechts
38 | - Objekt an der X-Achse drehen
39 | - Pfeil rauf/runter
40 | - Objekt an der Y-Achse drehen
41 | - Bild rauf/runter
42 | - Objekt an der Z-Achse drehen
43 | - Plus/Minus
44 | - Größer/kleiner
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/js/Detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | * @author mr.doob / http://mrdoob.com/
4 | */
5 |
6 | var Detector = {
7 |
8 | canvas: !! window.CanvasRenderingContext2D,
9 | webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(),
10 | workers: !! window.Worker,
11 | fileapi: window.File && window.FileReader && window.FileList && window.Blob,
12 |
13 | getWebGLErrorMessage: function () {
14 |
15 | var element = document.createElement( 'div' );
16 | element.id = 'webgl-error-message';
17 | element.style.fontFamily = 'monospace';
18 | element.style.fontSize = '13px';
19 | element.style.fontWeight = 'normal';
20 | element.style.textAlign = 'center';
21 | element.style.background = '#fff';
22 | element.style.color = '#000';
23 | element.style.padding = '1.5em';
24 | element.style.width = '400px';
25 | element.style.margin = '5em auto 0';
26 |
27 | if ( ! this.webgl ) {
28 |
29 | element.innerHTML = window.WebGLRenderingContext ? [
30 | 'Your graphics card does not seem to support WebGL.
',
31 | 'Find out how to get it here.'
32 | ].join( '\n' ) : [
33 | 'Your browser does not seem to support WebGL.
',
34 | 'Find out how to get it here.'
35 | ].join( '\n' );
36 |
37 | }
38 |
39 | return element;
40 |
41 | },
42 |
43 | addGetWebGLMessage: function ( parameters ) {
44 |
45 | var parent, id, element;
46 |
47 | parameters = parameters || {};
48 |
49 | parent = parameters.parent !== undefined ? parameters.parent : document.body;
50 | id = parameters.id !== undefined ? parameters.id : 'oldie';
51 |
52 | element = Detector.getWebGLErrorMessage();
53 | element.id = id;
54 |
55 | parent.appendChild( element );
56 |
57 | }
58 |
59 | };
60 |
--------------------------------------------------------------------------------
/js/3d.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var file = './collada/getriebe.dae'; // Pfad zum Collada-Modell
4 | var tilted = true; // Modell um 90 Grad drehen?
5 | var modelScale = 10; // abhängig von der Größe des Modells
6 | var cameraPositionZ = 1500; // Abstand der Kamera
7 | var cameraInitialVector = 30; // je kleiner der Vektor, desto größer erscheint das Modell
8 | var colorLight = [0xffffaa, 0xffffaa]; // Farben der beiden Lichter
9 | var colorBackground = 0x000000; // Hintergrundfarbe
10 | var dimensions = [window.innerWidth, window.innerHeight]; // Größe der Darstellung
11 | var canvasid = '3dmodell'; // Name des Canvas-Containers
12 | var rotate = [0.0005, 0.01, 0.0005]; // Geschwindigkeit der Animation (X-, Y-, Z-Achse)
13 | var rotateManual = 0.1; // manuelle Drehung per Tastatur
14 | var cameraZoom = 50; // manuelle Änderung der Zoomstufe
15 | var play = true; // nach dem Laden sofort animieren?
16 | // ab hier nichts ändern
17 |
18 | var camera, scene, renderer, dae, skin, lastFrame;
19 | window.addEventListener('load', function() {
20 | if (!Detector.webgl) Detector.addGetWebGLMessage(); // Browser kann kein WebGL
21 |
22 | // Collada-Modell
23 | var loader = new THREE.ColladaLoader();
24 | if (tilted) loader.options.upAxis = 'X'; // Drehung um 90 Grad
25 | loader.options.convertUpAxis = true; // an der Y-Achse ausrichten
26 | loader.load(file, function (collada) {
27 | dae = collada.scene;
28 | dae.scale.x = dae.scale.y = dae.scale.z = modelScale;
29 | scene = new THREE.Scene(); // initiiert die Szene
30 | scene.add(dae);
31 |
32 | // Kamera
33 | camera = new THREE.PerspectiveCamera(cameraInitialVector, dimensions[0]/dimensions[1], 1, 10000);
34 | camera.position.z = cameraPositionZ;
35 |
36 | // Lichter
37 | var directionalLight1 = new THREE.DirectionalLight(colorLight[0], 1.0);
38 | directionalLight1.position.set(1, 0, 0);
39 | var directionalLight2 = new THREE.DirectionalLight(colorLight[1], 2.0);
40 | directionalLight2.position.set(-1, 0, 0);
41 | scene.add(directionalLight1);
42 | scene.add(directionalLight2);
43 |
44 | // Renderer
45 | renderer = new THREE.WebGLRenderer({antialias: true});
46 | renderer.setClearColor(colorBackground);
47 | renderer.setSize(dimensions[0], dimensions[1]);
48 | // verankere Darstellung im HTML
49 | document.getElementById(canvasid).appendChild(renderer.domElement);
50 | animate();
51 | });
52 |
53 | var animate = function() {
54 | requestAnimationFrame(animate); // Animationsschleife
55 | if (play) { // Drehen, wenn Play-Status == true
56 | dae.rotation.x += rotate[0];
57 | dae.rotation.y += rotate[1];
58 | dae.rotation.z += rotate[2];
59 | }
60 | renderer.render(scene, camera);
61 | };
62 |
63 | // Tastenkürzel abfragen
64 | window.addEventListener('keydown', function(e) {
65 | var key = e.keyCode;
66 | console.log("Key " + key);
67 | switch (key) {
68 | case 37: // left
69 | dae.rotation.y -= rotateManual;
70 | e.preventDefault();
71 | break;
72 | case 39: // right
73 | dae.rotation.y += rotateManual;
74 | e.preventDefault();
75 | break;
76 | case 38: // up
77 | dae.rotation.x -= rotateManual;
78 | e.preventDefault();
79 | break;
80 | case 40: // down
81 | dae.rotation.x += rotateManual;
82 | e.preventDefault();
83 | break;
84 | case 33: // pageup
85 | dae.rotation.z += rotateManual;
86 | e.preventDefault();
87 | break;
88 | case 34: // pagedown
89 | dae.rotation.z -= rotateManual;
90 | e.preventDefault();
91 | break;
92 | case 32: // space
93 | play = play? false : true;
94 | e.preventDefault();
95 | break;
96 | case 187: // plus
97 | camera.position.z -= cameraZoom;
98 | e.preventDefault();
99 | break;
100 | case 189: // minus
101 | camera.position.z += cameraZoom;
102 | e.preventDefault();
103 | break;
104 | }
105 | renderer.render(scene, camera);
106 | }, false);
107 | }, false);
108 |
--------------------------------------------------------------------------------
/js/ColladaLoader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Tim Knip / http://www.floorplanner.com/ / tim at floorplanner.com
3 | */
4 |
5 | THREE.ColladaLoader = function () {
6 |
7 | var COLLADA = null;
8 | var scene = null;
9 | var daeScene;
10 |
11 | var readyCallbackFunc = null;
12 |
13 | var sources = {};
14 | var images = {};
15 | var animations = {};
16 | var controllers = {};
17 | var geometries = {};
18 | var materials = {};
19 | var effects = {};
20 | var cameras = {};
21 | var lights = {};
22 |
23 | var animData;
24 | var visualScenes;
25 | var baseUrl;
26 | var morphs;
27 | var skins;
28 |
29 | var flip_uv = true;
30 | var preferredShading = THREE.SmoothShading;
31 |
32 | var options = {
33 | // Force Geometry to always be centered at the local origin of the
34 | // containing Mesh.
35 | centerGeometry: false,
36 |
37 | // Axis conversion is done for geometries, animations, and controllers.
38 | // If we ever pull cameras or lights out of the COLLADA file, they'll
39 | // need extra work.
40 | convertUpAxis: false,
41 |
42 | subdivideFaces: true,
43 |
44 | upAxis: 'Y',
45 |
46 | // For reflective or refractive materials we'll use this cubemap
47 | defaultEnvMap: null
48 |
49 | };
50 |
51 | var colladaUnit = 1.0;
52 | var colladaUp = 'Y';
53 | var upConversion = null;
54 |
55 | function load ( url, readyCallback, progressCallback ) {
56 |
57 | var length = 0;
58 |
59 | if ( document.implementation && document.implementation.createDocument ) {
60 |
61 | var request = new XMLHttpRequest();
62 |
63 | request.onreadystatechange = function() {
64 |
65 | if( request.readyState == 4 ) {
66 |
67 | if( request.status == 0 || request.status == 200 ) {
68 |
69 |
70 | if ( request.responseXML ) {
71 |
72 | readyCallbackFunc = readyCallback;
73 | parse( request.responseXML, undefined, url );
74 |
75 | } else if ( request.responseText ) {
76 |
77 | readyCallbackFunc = readyCallback;
78 | var xmlParser = new DOMParser();
79 | var responseXML = xmlParser.parseFromString( request.responseText, "application/xml" );
80 | parse( responseXML, undefined, url );
81 |
82 | } else {
83 |
84 | console.error( "ColladaLoader: Empty or non-existing file (" + url + ")" );
85 |
86 | }
87 |
88 | }
89 |
90 | } else if ( request.readyState == 3 ) {
91 |
92 | if ( progressCallback ) {
93 |
94 | if ( length == 0 ) {
95 |
96 | length = request.getResponseHeader( "Content-Length" );
97 |
98 | }
99 |
100 | progressCallback( { total: length, loaded: request.responseText.length } );
101 |
102 | }
103 |
104 | }
105 |
106 | }
107 |
108 | request.open( "GET", url, true );
109 | request.send( null );
110 |
111 | } else {
112 |
113 | alert( "Don't know how to parse XML!" );
114 |
115 | }
116 |
117 | };
118 |
119 | function parse( doc, callBack, url ) {
120 |
121 | COLLADA = doc;
122 | callBack = callBack || readyCallbackFunc;
123 |
124 | if ( url !== undefined ) {
125 |
126 | var parts = url.split( '/' );
127 | parts.pop();
128 | baseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';
129 |
130 | }
131 |
132 | parseAsset();
133 | setUpConversion();
134 | images = parseLib( "//dae:library_images/dae:image", _Image, "image" );
135 | materials = parseLib( "//dae:library_materials/dae:material", Material, "material" );
136 | effects = parseLib( "//dae:library_effects/dae:effect", Effect, "effect" );
137 | geometries = parseLib( "//dae:library_geometries/dae:geometry", Geometry, "geometry" );
138 | cameras = parseLib( ".//dae:library_cameras/dae:camera", Camera, "camera" );
139 | lights = parseLib( ".//dae:library_lights/dae:light", Light, "light" );
140 | controllers = parseLib( "//dae:library_controllers/dae:controller", Controller, "controller" );
141 | animations = parseLib( "//dae:library_animations/dae:animation", Animation, "animation" );
142 | visualScenes = parseLib( ".//dae:library_visual_scenes/dae:visual_scene", VisualScene, "visual_scene" );
143 |
144 | morphs = [];
145 | skins = [];
146 |
147 | daeScene = parseScene();
148 | scene = new THREE.Object3D();
149 |
150 | for ( var i = 0; i < daeScene.nodes.length; i ++ ) {
151 |
152 | scene.add( createSceneGraph( daeScene.nodes[ i ] ) );
153 |
154 | }
155 |
156 | // unit conversion
157 | scene.scale.multiplyScalar( colladaUnit );
158 |
159 | createAnimations();
160 |
161 | var result = {
162 |
163 | scene: scene,
164 | morphs: morphs,
165 | skins: skins,
166 | animations: animData,
167 | dae: {
168 | images: images,
169 | materials: materials,
170 | cameras: cameras,
171 | lights: lights,
172 | effects: effects,
173 | geometries: geometries,
174 | controllers: controllers,
175 | animations: animations,
176 | visualScenes: visualScenes,
177 | scene: daeScene
178 | }
179 |
180 | };
181 |
182 | if ( callBack ) {
183 |
184 | callBack( result );
185 |
186 | }
187 |
188 | return result;
189 |
190 | };
191 |
192 | function setPreferredShading ( shading ) {
193 |
194 | preferredShading = shading;
195 |
196 | };
197 |
198 | function parseAsset () {
199 |
200 | var elements = COLLADA.evaluate( '//dae:asset', COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
201 |
202 | var element = elements.iterateNext();
203 |
204 | if ( element && element.childNodes ) {
205 |
206 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
207 |
208 | var child = element.childNodes[ i ];
209 |
210 | switch ( child.nodeName ) {
211 |
212 | case 'unit':
213 |
214 | var meter = child.getAttribute( 'meter' );
215 |
216 | if ( meter ) {
217 |
218 | colladaUnit = parseFloat( meter );
219 |
220 | }
221 |
222 | break;
223 |
224 | case 'up_axis':
225 |
226 | colladaUp = child.textContent.charAt(0);
227 | break;
228 |
229 | }
230 |
231 | }
232 |
233 | }
234 |
235 | };
236 |
237 | function parseLib ( q, classSpec, prefix ) {
238 |
239 | var elements = COLLADA.evaluate(q, COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null) ;
240 |
241 | var lib = {};
242 | var element = elements.iterateNext();
243 | var i = 0;
244 |
245 | while ( element ) {
246 |
247 | var daeElement = ( new classSpec() ).parse( element );
248 | if ( !daeElement.id || daeElement.id.length == 0 ) daeElement.id = prefix + ( i ++ );
249 | lib[ daeElement.id ] = daeElement;
250 |
251 | element = elements.iterateNext();
252 |
253 | }
254 |
255 | return lib;
256 |
257 | };
258 |
259 | function parseScene() {
260 |
261 | var sceneElement = COLLADA.evaluate( './/dae:scene/dae:instance_visual_scene', COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ).iterateNext();
262 |
263 | if ( sceneElement ) {
264 |
265 | var url = sceneElement.getAttribute( 'url' ).replace( /^#/, '' );
266 | return visualScenes[ url.length > 0 ? url : 'visual_scene0' ];
267 |
268 | } else {
269 |
270 | return null;
271 |
272 | }
273 |
274 | };
275 |
276 | function createAnimations() {
277 |
278 | animData = [];
279 |
280 | // fill in the keys
281 | recurseHierarchy( scene );
282 |
283 | };
284 |
285 | function recurseHierarchy( node ) {
286 |
287 | var n = daeScene.getChildById( node.name, true ),
288 | newData = null;
289 |
290 | if ( n && n.keys ) {
291 |
292 | newData = {
293 | fps: 60,
294 | hierarchy: [ {
295 | node: n,
296 | keys: n.keys,
297 | sids: n.sids
298 | } ],
299 | node: node,
300 | name: 'animation_' + node.name,
301 | length: 0
302 | };
303 |
304 | animData.push(newData);
305 |
306 | for ( var i = 0, il = n.keys.length; i < il; i++ ) {
307 |
308 | newData.length = Math.max( newData.length, n.keys[i].time );
309 |
310 | }
311 |
312 | } else {
313 |
314 | newData = {
315 | hierarchy: [ {
316 | keys: [],
317 | sids: []
318 | } ]
319 | }
320 |
321 | }
322 |
323 | for ( var i = 0, il = node.children.length; i < il; i++ ) {
324 |
325 | var d = recurseHierarchy( node.children[i] );
326 |
327 | for ( var j = 0, jl = d.hierarchy.length; j < jl; j ++ ) {
328 |
329 | newData.hierarchy.push( {
330 | keys: [],
331 | sids: []
332 | } );
333 |
334 | }
335 |
336 | }
337 |
338 | return newData;
339 |
340 | };
341 |
342 | function calcAnimationBounds () {
343 |
344 | var start = 1000000;
345 | var end = -start;
346 | var frames = 0;
347 |
348 | for ( var id in animations ) {
349 |
350 | var animation = animations[ id ];
351 |
352 | for ( var i = 0; i < animation.sampler.length; i ++ ) {
353 |
354 | var sampler = animation.sampler[ i ];
355 | sampler.create();
356 |
357 | start = Math.min( start, sampler.startTime );
358 | end = Math.max( end, sampler.endTime );
359 | frames = Math.max( frames, sampler.input.length );
360 |
361 | }
362 |
363 | }
364 |
365 | return { start:start, end:end, frames:frames };
366 |
367 | };
368 |
369 | function createMorph ( geometry, ctrl ) {
370 |
371 | var morphCtrl = ctrl instanceof InstanceController ? controllers[ ctrl.url ] : ctrl;
372 |
373 | if ( !morphCtrl || !morphCtrl.morph ) {
374 |
375 | console.log("could not find morph controller!");
376 | return;
377 |
378 | }
379 |
380 | var morph = morphCtrl.morph;
381 |
382 | for ( var i = 0; i < morph.targets.length; i ++ ) {
383 |
384 | var target_id = morph.targets[ i ];
385 | var daeGeometry = geometries[ target_id ];
386 |
387 | if ( !daeGeometry.mesh ||
388 | !daeGeometry.mesh.primitives ||
389 | !daeGeometry.mesh.primitives.length ) {
390 | continue;
391 | }
392 |
393 | var target = daeGeometry.mesh.primitives[ 0 ].geometry;
394 |
395 | if ( target.vertices.length === geometry.vertices.length ) {
396 |
397 | geometry.morphTargets.push( { name: "target_1", vertices: target.vertices } );
398 |
399 | }
400 |
401 | }
402 |
403 | geometry.morphTargets.push( { name: "target_Z", vertices: geometry.vertices } );
404 |
405 | };
406 |
407 | function createSkin ( geometry, ctrl, applyBindShape ) {
408 |
409 | var skinCtrl = controllers[ ctrl.url ];
410 |
411 | if ( !skinCtrl || !skinCtrl.skin ) {
412 |
413 | console.log( "could not find skin controller!" );
414 | return;
415 |
416 | }
417 |
418 | if ( !ctrl.skeleton || !ctrl.skeleton.length ) {
419 |
420 | console.log( "could not find the skeleton for the skin!" );
421 | return;
422 |
423 | }
424 |
425 | var skin = skinCtrl.skin;
426 | var skeleton = daeScene.getChildById( ctrl.skeleton[ 0 ] );
427 | var hierarchy = [];
428 |
429 | applyBindShape = applyBindShape !== undefined ? applyBindShape : true;
430 |
431 | var bones = [];
432 | geometry.skinWeights = [];
433 | geometry.skinIndices = [];
434 |
435 | //createBones( geometry.bones, skin, hierarchy, skeleton, null, -1 );
436 | //createWeights( skin, geometry.bones, geometry.skinIndices, geometry.skinWeights );
437 |
438 | /*
439 | geometry.animation = {
440 | name: 'take_001',
441 | fps: 30,
442 | length: 2,
443 | JIT: true,
444 | hierarchy: hierarchy
445 | };
446 | */
447 |
448 | if ( applyBindShape ) {
449 |
450 | for ( var i = 0; i < geometry.vertices.length; i ++ ) {
451 |
452 | geometry.vertices[ i ].applyMatrix4( skin.bindShapeMatrix );
453 |
454 | }
455 |
456 | }
457 |
458 | };
459 |
460 | function setupSkeleton ( node, bones, frame, parent ) {
461 |
462 | node.world = node.world || new THREE.Matrix4();
463 | node.world.copy( node.matrix );
464 |
465 | if ( node.channels && node.channels.length ) {
466 |
467 | var channel = node.channels[ 0 ];
468 | var m = channel.sampler.output[ frame ];
469 |
470 | if ( m instanceof THREE.Matrix4 ) {
471 |
472 | node.world.copy( m );
473 |
474 | }
475 |
476 | }
477 |
478 | if ( parent ) {
479 |
480 | node.world.multiplyMatrices( parent, node.world );
481 |
482 | }
483 |
484 | bones.push( node );
485 |
486 | for ( var i = 0; i < node.nodes.length; i ++ ) {
487 |
488 | setupSkeleton( node.nodes[ i ], bones, frame, node.world );
489 |
490 | }
491 |
492 | };
493 |
494 | function setupSkinningMatrices ( bones, skin ) {
495 |
496 | // FIXME: this is dumb...
497 |
498 | for ( var i = 0; i < bones.length; i ++ ) {
499 |
500 | var bone = bones[ i ];
501 | var found = -1;
502 |
503 | if ( bone.type != 'JOINT' ) continue;
504 |
505 | for ( var j = 0; j < skin.joints.length; j ++ ) {
506 |
507 | if ( bone.sid == skin.joints[ j ] ) {
508 |
509 | found = j;
510 | break;
511 |
512 | }
513 |
514 | }
515 |
516 | if ( found >= 0 ) {
517 |
518 | var inv = skin.invBindMatrices[ found ];
519 |
520 | bone.invBindMatrix = inv;
521 | bone.skinningMatrix = new THREE.Matrix4();
522 | bone.skinningMatrix.multiplyMatrices(bone.world, inv); // (IBMi * JMi)
523 |
524 | bone.weights = [];
525 |
526 | for ( var j = 0; j < skin.weights.length; j ++ ) {
527 |
528 | for (var k = 0; k < skin.weights[ j ].length; k ++) {
529 |
530 | var w = skin.weights[ j ][ k ];
531 |
532 | if ( w.joint == found ) {
533 |
534 | bone.weights.push( w );
535 |
536 | }
537 |
538 | }
539 |
540 | }
541 |
542 | } else {
543 |
544 | throw 'ColladaLoader: Could not find joint \'' + bone.sid + '\'.';
545 |
546 | }
547 |
548 | }
549 |
550 | };
551 |
552 | function applySkin ( geometry, instanceCtrl, frame ) {
553 |
554 | var skinController = controllers[ instanceCtrl.url ];
555 |
556 | frame = frame !== undefined ? frame : 40;
557 |
558 | if ( !skinController || !skinController.skin ) {
559 |
560 | console.log( 'ColladaLoader: Could not find skin controller.' );
561 | return;
562 |
563 | }
564 |
565 | if ( !instanceCtrl.skeleton || !instanceCtrl.skeleton.length ) {
566 |
567 | console.log( 'ColladaLoader: Could not find the skeleton for the skin. ' );
568 | return;
569 |
570 | }
571 |
572 | var animationBounds = calcAnimationBounds();
573 | var skeleton = daeScene.getChildById( instanceCtrl.skeleton[0], true ) ||
574 | daeScene.getChildBySid( instanceCtrl.skeleton[0], true );
575 |
576 | var i, j, w, vidx, weight;
577 | var v = new THREE.Vector3(), o, s;
578 |
579 | // move vertices to bind shape
580 |
581 | for ( i = 0; i < geometry.vertices.length; i ++ ) {
582 |
583 | geometry.vertices[i].applyMatrix4( skinController.skin.bindShapeMatrix );
584 |
585 | }
586 |
587 | // process animation, or simply pose the rig if no animation
588 |
589 | for ( frame = 0; frame < animationBounds.frames; frame ++ ) {
590 |
591 | var bones = [];
592 | var skinned = [];
593 |
594 | // zero skinned vertices
595 |
596 | for ( i = 0; i < geometry.vertices.length; i++ ) {
597 |
598 | skinned.push( new THREE.Vector3() );
599 |
600 | }
601 |
602 | // process the frame and setup the rig with a fresh
603 | // transform, possibly from the bone's animation channel(s)
604 |
605 | setupSkeleton( skeleton, bones, frame );
606 | setupSkinningMatrices( bones, skinController.skin );
607 |
608 | // skin 'm
609 |
610 | for ( i = 0; i < bones.length; i ++ ) {
611 |
612 | if ( bones[ i ].type != 'JOINT' ) continue;
613 |
614 | for ( j = 0; j < bones[ i ].weights.length; j ++ ) {
615 |
616 | w = bones[ i ].weights[ j ];
617 | vidx = w.index;
618 | weight = w.weight;
619 |
620 | o = geometry.vertices[vidx];
621 | s = skinned[vidx];
622 |
623 | v.x = o.x;
624 | v.y = o.y;
625 | v.z = o.z;
626 |
627 | v.applyMatrix4( bones[i].skinningMatrix );
628 |
629 | s.x += (v.x * weight);
630 | s.y += (v.y * weight);
631 | s.z += (v.z * weight);
632 |
633 | }
634 |
635 | }
636 |
637 | geometry.morphTargets.push( { name: "target_" + frame, vertices: skinned } );
638 |
639 | }
640 |
641 | };
642 |
643 | function createSceneGraph ( node, parent ) {
644 |
645 | var obj = new THREE.Object3D();
646 | var skinned = false;
647 | var skinController;
648 | var morphController;
649 | var i, j;
650 |
651 | // FIXME: controllers
652 |
653 | for ( i = 0; i < node.controllers.length; i ++ ) {
654 |
655 | var controller = controllers[ node.controllers[ i ].url ];
656 |
657 | switch ( controller.type ) {
658 |
659 | case 'skin':
660 |
661 | if ( geometries[ controller.skin.source ] ) {
662 |
663 | var inst_geom = new InstanceGeometry();
664 |
665 | inst_geom.url = controller.skin.source;
666 | inst_geom.instance_material = node.controllers[ i ].instance_material;
667 |
668 | node.geometries.push( inst_geom );
669 | skinned = true;
670 | skinController = node.controllers[ i ];
671 |
672 | } else if ( controllers[ controller.skin.source ] ) {
673 |
674 | // urgh: controller can be chained
675 | // handle the most basic case...
676 |
677 | var second = controllers[ controller.skin.source ];
678 | morphController = second;
679 | // skinController = node.controllers[i];
680 |
681 | if ( second.morph && geometries[ second.morph.source ] ) {
682 |
683 | var inst_geom = new InstanceGeometry();
684 |
685 | inst_geom.url = second.morph.source;
686 | inst_geom.instance_material = node.controllers[ i ].instance_material;
687 |
688 | node.geometries.push( inst_geom );
689 |
690 | }
691 |
692 | }
693 |
694 | break;
695 |
696 | case 'morph':
697 |
698 | if ( geometries[ controller.morph.source ] ) {
699 |
700 | var inst_geom = new InstanceGeometry();
701 |
702 | inst_geom.url = controller.morph.source;
703 | inst_geom.instance_material = node.controllers[ i ].instance_material;
704 |
705 | node.geometries.push( inst_geom );
706 | morphController = node.controllers[ i ];
707 |
708 | }
709 |
710 | console.log( 'ColladaLoader: Morph-controller partially supported.' );
711 |
712 | default:
713 | break;
714 |
715 | }
716 |
717 | }
718 |
719 | // FIXME: multi-material mesh?
720 | // geometries
721 |
722 | var double_sided_materials = {};
723 |
724 | for ( i = 0; i < node.geometries.length; i ++ ) {
725 |
726 | var instance_geometry = node.geometries[i];
727 | var instance_materials = instance_geometry.instance_material;
728 | var geometry = geometries[ instance_geometry.url ];
729 | var used_materials = {};
730 | var used_materials_array = [];
731 | var num_materials = 0;
732 | var first_material;
733 |
734 | if ( geometry ) {
735 |
736 | if ( !geometry.mesh || !geometry.mesh.primitives )
737 | continue;
738 |
739 | if ( obj.name.length == 0 ) {
740 |
741 | obj.name = geometry.id;
742 |
743 | }
744 |
745 | // collect used fx for this geometry-instance
746 |
747 | if ( instance_materials ) {
748 |
749 | for ( j = 0; j < instance_materials.length; j ++ ) {
750 |
751 | var instance_material = instance_materials[ j ];
752 | var mat = materials[ instance_material.target ];
753 | var effect_id = mat.instance_effect.url;
754 | var shader = effects[ effect_id ].shader;
755 | var material3js = shader.material;
756 |
757 | if ( geometry.doubleSided ) {
758 |
759 | if ( !( material3js in double_sided_materials ) ) {
760 |
761 | var _copied_material = material3js.clone();
762 | _copied_material.side = THREE.DoubleSide;
763 | double_sided_materials[ material3js ] = _copied_material;
764 |
765 | }
766 |
767 | material3js = double_sided_materials[ material3js ];
768 |
769 | }
770 |
771 | material3js.opacity = !material3js.opacity ? 1 : material3js.opacity;
772 | used_materials[ instance_material.symbol ] = num_materials;
773 | used_materials_array.push( material3js );
774 | first_material = material3js;
775 | first_material.name = mat.name == null || mat.name === '' ? mat.id : mat.name;
776 | num_materials ++;
777 |
778 | }
779 |
780 | }
781 |
782 | var mesh;
783 | var material = first_material || new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.FlatShading, side: geometry.doubleSided ? THREE.DoubleSide : THREE.FrontSide } );
784 | var geom = geometry.mesh.geometry3js;
785 |
786 | if ( num_materials > 1 ) {
787 |
788 | material = new THREE.MeshFaceMaterial( used_materials_array );
789 |
790 | for ( j = 0; j < geom.faces.length; j ++ ) {
791 |
792 | var face = geom.faces[ j ];
793 | face.materialIndex = used_materials[ face.daeMaterial ]
794 |
795 | }
796 |
797 | }
798 |
799 | if ( skinController !== undefined ) {
800 |
801 | applySkin( geom, skinController );
802 |
803 | material.morphTargets = true;
804 |
805 | mesh = new THREE.SkinnedMesh( geom, material, false );
806 | mesh.skeleton = skinController.skeleton;
807 | mesh.skinController = controllers[ skinController.url ];
808 | mesh.skinInstanceController = skinController;
809 | mesh.name = 'skin_' + skins.length;
810 |
811 | skins.push( mesh );
812 |
813 | } else if ( morphController !== undefined ) {
814 |
815 | createMorph( geom, morphController );
816 |
817 | material.morphTargets = true;
818 |
819 | mesh = new THREE.Mesh( geom, material );
820 | mesh.name = 'morph_' + morphs.length;
821 |
822 | morphs.push( mesh );
823 |
824 | } else {
825 |
826 | mesh = new THREE.Mesh( geom, material );
827 | // mesh.geom.name = geometry.id;
828 |
829 | }
830 |
831 | node.geometries.length > 1 ? obj.add( mesh ) : obj = mesh;
832 |
833 | }
834 |
835 | }
836 |
837 | for ( i = 0; i < node.cameras.length; i ++ ) {
838 |
839 | var params = cameras[node.cameras[i].url];
840 | obj = new THREE.PerspectiveCamera(params.fov, params.aspect_ratio, params.znear, params.zfar);
841 |
842 | }
843 |
844 | for ( i = 0; i < node.lights.length; i ++ ) {
845 |
846 | var params = lights[node.lights[i].url];
847 |
848 | switch ( params.technique ) {
849 |
850 | case 'ambient':
851 | obj = new THREE.AmbientLight(params.color);
852 | break;
853 |
854 | case 'point':
855 | obj = new THREE.PointLight(params.color);
856 | break;
857 |
858 | case 'directional':
859 | obj = new THREE.DirectionalLight(params.color);
860 | break;
861 |
862 | }
863 |
864 | }
865 |
866 | obj.name = node.name || node.id || "";
867 | obj.matrix = node.matrix;
868 |
869 | var props = node.matrix.decompose();
870 | obj.position = props[ 0 ];
871 | obj.quaternion = props[ 1 ];
872 | obj.useQuaternion = true;
873 | obj.scale = props[ 2 ];
874 |
875 | if ( options.centerGeometry && obj.geometry ) {
876 |
877 | var delta = THREE.GeometryUtils.center( obj.geometry );
878 | delta.multiply( obj.scale );
879 | delta.applyQuaternion( obj.quaternion );
880 |
881 | obj.position.sub( delta );
882 |
883 | }
884 |
885 | for ( i = 0; i < node.nodes.length; i ++ ) {
886 |
887 | obj.add( createSceneGraph( node.nodes[i], node ) );
888 |
889 | }
890 |
891 | return obj;
892 |
893 | };
894 |
895 | function getJointId( skin, id ) {
896 |
897 | for ( var i = 0; i < skin.joints.length; i ++ ) {
898 |
899 | if ( skin.joints[ i ] == id ) {
900 |
901 | return i;
902 |
903 | }
904 |
905 | }
906 |
907 | };
908 |
909 | function getLibraryNode( id ) {
910 |
911 | return COLLADA.evaluate( './/dae:library_nodes//dae:node[@id=\'' + id + '\']', COLLADA, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ).iterateNext();
912 |
913 | };
914 |
915 | function getChannelsForNode (node ) {
916 |
917 | var channels = [];
918 | var startTime = 1000000;
919 | var endTime = -1000000;
920 |
921 | for ( var id in animations ) {
922 |
923 | var animation = animations[id];
924 |
925 | for ( var i = 0; i < animation.channel.length; i ++ ) {
926 |
927 | var channel = animation.channel[i];
928 | var sampler = animation.sampler[i];
929 | var id = channel.target.split('/')[0];
930 |
931 | if ( id == node.id ) {
932 |
933 | sampler.create();
934 | channel.sampler = sampler;
935 | startTime = Math.min(startTime, sampler.startTime);
936 | endTime = Math.max(endTime, sampler.endTime);
937 | channels.push(channel);
938 |
939 | }
940 |
941 | }
942 |
943 | }
944 |
945 | if ( channels.length ) {
946 |
947 | node.startTime = startTime;
948 | node.endTime = endTime;
949 |
950 | }
951 |
952 | return channels;
953 |
954 | };
955 |
956 | function calcFrameDuration( node ) {
957 |
958 | var minT = 10000000;
959 |
960 | for ( var i = 0; i < node.channels.length; i ++ ) {
961 |
962 | var sampler = node.channels[i].sampler;
963 |
964 | for ( var j = 0; j < sampler.input.length - 1; j ++ ) {
965 |
966 | var t0 = sampler.input[ j ];
967 | var t1 = sampler.input[ j + 1 ];
968 | minT = Math.min( minT, t1 - t0 );
969 |
970 | }
971 | }
972 |
973 | return minT;
974 |
975 | };
976 |
977 | function calcMatrixAt( node, t ) {
978 |
979 | var animated = {};
980 |
981 | var i, j;
982 |
983 | for ( i = 0; i < node.channels.length; i ++ ) {
984 |
985 | var channel = node.channels[ i ];
986 | animated[ channel.sid ] = channel;
987 |
988 | }
989 |
990 | var matrix = new THREE.Matrix4();
991 |
992 | for ( i = 0; i < node.transforms.length; i ++ ) {
993 |
994 | var transform = node.transforms[ i ];
995 | var channel = animated[ transform.sid ];
996 |
997 | if ( channel !== undefined ) {
998 |
999 | var sampler = channel.sampler;
1000 | var value;
1001 |
1002 | for ( j = 0; j < sampler.input.length - 1; j ++ ) {
1003 |
1004 | if ( sampler.input[ j + 1 ] > t ) {
1005 |
1006 | value = sampler.output[ j ];
1007 | //console.log(value.flatten)
1008 | break;
1009 |
1010 | }
1011 |
1012 | }
1013 |
1014 | if ( value !== undefined ) {
1015 |
1016 | if ( value instanceof THREE.Matrix4 ) {
1017 |
1018 | matrix.multiplyMatrices( matrix, value );
1019 |
1020 | } else {
1021 |
1022 | // FIXME: handle other types
1023 |
1024 | matrix.multiplyMatrices( matrix, transform.matrix );
1025 |
1026 | }
1027 |
1028 | } else {
1029 |
1030 | matrix.multiplyMatrices( matrix, transform.matrix );
1031 |
1032 | }
1033 |
1034 | } else {
1035 |
1036 | matrix.multiplyMatrices( matrix, transform.matrix );
1037 |
1038 | }
1039 |
1040 | }
1041 |
1042 | return matrix;
1043 |
1044 | };
1045 |
1046 | function bakeAnimations ( node ) {
1047 |
1048 | if ( node.channels && node.channels.length ) {
1049 |
1050 | var keys = [],
1051 | sids = [];
1052 |
1053 | for ( var i = 0, il = node.channels.length; i < il; i++ ) {
1054 |
1055 | var channel = node.channels[i],
1056 | fullSid = channel.fullSid,
1057 | sampler = channel.sampler,
1058 | input = sampler.input,
1059 | transform = node.getTransformBySid( channel.sid ),
1060 | member;
1061 |
1062 | if ( channel.arrIndices ) {
1063 |
1064 | member = [];
1065 |
1066 | for ( var j = 0, jl = channel.arrIndices.length; j < jl; j++ ) {
1067 |
1068 | member[ j ] = getConvertedIndex( channel.arrIndices[ j ] );
1069 |
1070 | }
1071 |
1072 | } else {
1073 |
1074 | member = getConvertedMember( channel.member );
1075 |
1076 | }
1077 |
1078 | if ( transform ) {
1079 |
1080 | if ( sids.indexOf( fullSid ) === -1 ) {
1081 |
1082 | sids.push( fullSid );
1083 |
1084 | }
1085 |
1086 | for ( var j = 0, jl = input.length; j < jl; j++ ) {
1087 |
1088 | var time = input[j],
1089 | data = sampler.getData( transform.type, j ),
1090 | key = findKey( keys, time );
1091 |
1092 | if ( !key ) {
1093 |
1094 | key = new Key( time );
1095 | var timeNdx = findTimeNdx( keys, time );
1096 | keys.splice( timeNdx == -1 ? keys.length : timeNdx, 0, key );
1097 |
1098 | }
1099 |
1100 | key.addTarget( fullSid, transform, member, data );
1101 |
1102 | }
1103 |
1104 | } else {
1105 |
1106 | console.log( 'Could not find transform "' + channel.sid + '" in node ' + node.id );
1107 |
1108 | }
1109 |
1110 | }
1111 |
1112 | // post process
1113 | for ( var i = 0; i < sids.length; i++ ) {
1114 |
1115 | var sid = sids[ i ];
1116 |
1117 | for ( var j = 0; j < keys.length; j++ ) {
1118 |
1119 | var key = keys[ j ];
1120 |
1121 | if ( !key.hasTarget( sid ) ) {
1122 |
1123 | interpolateKeys( keys, key, j, sid );
1124 |
1125 | }
1126 |
1127 | }
1128 |
1129 | }
1130 |
1131 | node.keys = keys;
1132 | node.sids = sids;
1133 |
1134 | }
1135 |
1136 | };
1137 |
1138 | function findKey ( keys, time) {
1139 |
1140 | var retVal = null;
1141 |
1142 | for ( var i = 0, il = keys.length; i < il && retVal == null; i++ ) {
1143 |
1144 | var key = keys[i];
1145 |
1146 | if ( key.time === time ) {
1147 |
1148 | retVal = key;
1149 |
1150 | } else if ( key.time > time ) {
1151 |
1152 | break;
1153 |
1154 | }
1155 |
1156 | }
1157 |
1158 | return retVal;
1159 |
1160 | };
1161 |
1162 | function findTimeNdx ( keys, time) {
1163 |
1164 | var ndx = -1;
1165 |
1166 | for ( var i = 0, il = keys.length; i < il && ndx == -1; i++ ) {
1167 |
1168 | var key = keys[i];
1169 |
1170 | if ( key.time >= time ) {
1171 |
1172 | ndx = i;
1173 |
1174 | }
1175 |
1176 | }
1177 |
1178 | return ndx;
1179 |
1180 | };
1181 |
1182 | function interpolateKeys ( keys, key, ndx, fullSid ) {
1183 |
1184 | var prevKey = getPrevKeyWith( keys, fullSid, ndx ? ndx-1 : 0 ),
1185 | nextKey = getNextKeyWith( keys, fullSid, ndx+1 );
1186 |
1187 | if ( prevKey && nextKey ) {
1188 |
1189 | var scale = (key.time - prevKey.time) / (nextKey.time - prevKey.time),
1190 | prevTarget = prevKey.getTarget( fullSid ),
1191 | nextData = nextKey.getTarget( fullSid ).data,
1192 | prevData = prevTarget.data,
1193 | data;
1194 |
1195 | if ( prevTarget.type === 'matrix' ) {
1196 |
1197 | data = prevData;
1198 |
1199 | } else if ( prevData.length ) {
1200 |
1201 | data = [];
1202 |
1203 | for ( var i = 0; i < prevData.length; ++i ) {
1204 |
1205 | data[ i ] = prevData[ i ] + ( nextData[ i ] - prevData[ i ] ) * scale;
1206 |
1207 | }
1208 |
1209 | } else {
1210 |
1211 | data = prevData + ( nextData - prevData ) * scale;
1212 |
1213 | }
1214 |
1215 | key.addTarget( fullSid, prevTarget.transform, prevTarget.member, data );
1216 |
1217 | }
1218 |
1219 | };
1220 |
1221 | // Get next key with given sid
1222 |
1223 | function getNextKeyWith( keys, fullSid, ndx ) {
1224 |
1225 | for ( ; ndx < keys.length; ndx++ ) {
1226 |
1227 | var key = keys[ ndx ];
1228 |
1229 | if ( key.hasTarget( fullSid ) ) {
1230 |
1231 | return key;
1232 |
1233 | }
1234 |
1235 | }
1236 |
1237 | return null;
1238 |
1239 | };
1240 |
1241 | // Get previous key with given sid
1242 |
1243 | function getPrevKeyWith( keys, fullSid, ndx ) {
1244 |
1245 | ndx = ndx >= 0 ? ndx : ndx + keys.length;
1246 |
1247 | for ( ; ndx >= 0; ndx-- ) {
1248 |
1249 | var key = keys[ ndx ];
1250 |
1251 | if ( key.hasTarget( fullSid ) ) {
1252 |
1253 | return key;
1254 |
1255 | }
1256 |
1257 | }
1258 |
1259 | return null;
1260 |
1261 | };
1262 |
1263 | function _Image() {
1264 |
1265 | this.id = "";
1266 | this.init_from = "";
1267 |
1268 | };
1269 |
1270 | _Image.prototype.parse = function(element) {
1271 |
1272 | this.id = element.getAttribute('id');
1273 |
1274 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1275 |
1276 | var child = element.childNodes[ i ];
1277 |
1278 | if ( child.nodeName == 'init_from' ) {
1279 |
1280 | this.init_from = child.textContent;
1281 |
1282 | }
1283 |
1284 | }
1285 |
1286 | return this;
1287 |
1288 | };
1289 |
1290 | function Controller() {
1291 |
1292 | this.id = "";
1293 | this.name = "";
1294 | this.type = "";
1295 | this.skin = null;
1296 | this.morph = null;
1297 |
1298 | };
1299 |
1300 | Controller.prototype.parse = function( element ) {
1301 |
1302 | this.id = element.getAttribute('id');
1303 | this.name = element.getAttribute('name');
1304 | this.type = "none";
1305 |
1306 | for ( var i = 0; i < element.childNodes.length; i++ ) {
1307 |
1308 | var child = element.childNodes[ i ];
1309 |
1310 | switch ( child.nodeName ) {
1311 |
1312 | case 'skin':
1313 |
1314 | this.skin = (new Skin()).parse(child);
1315 | this.type = child.nodeName;
1316 | break;
1317 |
1318 | case 'morph':
1319 |
1320 | this.morph = (new Morph()).parse(child);
1321 | this.type = child.nodeName;
1322 | break;
1323 |
1324 | default:
1325 | break;
1326 |
1327 | }
1328 | }
1329 |
1330 | return this;
1331 |
1332 | };
1333 |
1334 | function Morph() {
1335 |
1336 | this.method = null;
1337 | this.source = null;
1338 | this.targets = null;
1339 | this.weights = null;
1340 |
1341 | };
1342 |
1343 | Morph.prototype.parse = function( element ) {
1344 |
1345 | var sources = {};
1346 | var inputs = [];
1347 | var i;
1348 |
1349 | this.method = element.getAttribute( 'method' );
1350 | this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
1351 |
1352 | for ( i = 0; i < element.childNodes.length; i ++ ) {
1353 |
1354 | var child = element.childNodes[ i ];
1355 | if ( child.nodeType != 1 ) continue;
1356 |
1357 | switch ( child.nodeName ) {
1358 |
1359 | case 'source':
1360 |
1361 | var source = ( new Source() ).parse( child );
1362 | sources[ source.id ] = source;
1363 | break;
1364 |
1365 | case 'targets':
1366 |
1367 | inputs = this.parseInputs( child );
1368 | break;
1369 |
1370 | default:
1371 |
1372 | console.log( child.nodeName );
1373 | break;
1374 |
1375 | }
1376 |
1377 | }
1378 |
1379 | for ( i = 0; i < inputs.length; i ++ ) {
1380 |
1381 | var input = inputs[ i ];
1382 | var source = sources[ input.source ];
1383 |
1384 | switch ( input.semantic ) {
1385 |
1386 | case 'MORPH_TARGET':
1387 |
1388 | this.targets = source.read();
1389 | break;
1390 |
1391 | case 'MORPH_WEIGHT':
1392 |
1393 | this.weights = source.read();
1394 | break;
1395 |
1396 | default:
1397 | break;
1398 |
1399 | }
1400 | }
1401 |
1402 | return this;
1403 |
1404 | };
1405 |
1406 | Morph.prototype.parseInputs = function(element) {
1407 |
1408 | var inputs = [];
1409 |
1410 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1411 |
1412 | var child = element.childNodes[i];
1413 | if ( child.nodeType != 1) continue;
1414 |
1415 | switch ( child.nodeName ) {
1416 |
1417 | case 'input':
1418 |
1419 | inputs.push( (new Input()).parse(child) );
1420 | break;
1421 |
1422 | default:
1423 | break;
1424 | }
1425 | }
1426 |
1427 | return inputs;
1428 |
1429 | };
1430 |
1431 | function Skin() {
1432 |
1433 | this.source = "";
1434 | this.bindShapeMatrix = null;
1435 | this.invBindMatrices = [];
1436 | this.joints = [];
1437 | this.weights = [];
1438 |
1439 | };
1440 |
1441 | Skin.prototype.parse = function( element ) {
1442 |
1443 | var sources = {};
1444 | var joints, weights;
1445 |
1446 | this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
1447 | this.invBindMatrices = [];
1448 | this.joints = [];
1449 | this.weights = [];
1450 |
1451 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1452 |
1453 | var child = element.childNodes[i];
1454 | if ( child.nodeType != 1 ) continue;
1455 |
1456 | switch ( child.nodeName ) {
1457 |
1458 | case 'bind_shape_matrix':
1459 |
1460 | var f = _floats(child.textContent);
1461 | this.bindShapeMatrix = getConvertedMat4( f );
1462 | break;
1463 |
1464 | case 'source':
1465 |
1466 | var src = new Source().parse(child);
1467 | sources[ src.id ] = src;
1468 | break;
1469 |
1470 | case 'joints':
1471 |
1472 | joints = child;
1473 | break;
1474 |
1475 | case 'vertex_weights':
1476 |
1477 | weights = child;
1478 | break;
1479 |
1480 | default:
1481 |
1482 | console.log( child.nodeName );
1483 | break;
1484 |
1485 | }
1486 | }
1487 |
1488 | this.parseJoints( joints, sources );
1489 | this.parseWeights( weights, sources );
1490 |
1491 | return this;
1492 |
1493 | };
1494 |
1495 | Skin.prototype.parseJoints = function ( element, sources ) {
1496 |
1497 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1498 |
1499 | var child = element.childNodes[ i ];
1500 | if ( child.nodeType != 1 ) continue;
1501 |
1502 | switch ( child.nodeName ) {
1503 |
1504 | case 'input':
1505 |
1506 | var input = ( new Input() ).parse( child );
1507 | var source = sources[ input.source ];
1508 |
1509 | if ( input.semantic == 'JOINT' ) {
1510 |
1511 | this.joints = source.read();
1512 |
1513 | } else if ( input.semantic == 'INV_BIND_MATRIX' ) {
1514 |
1515 | this.invBindMatrices = source.read();
1516 |
1517 | }
1518 |
1519 | break;
1520 |
1521 | default:
1522 | break;
1523 | }
1524 |
1525 | }
1526 |
1527 | };
1528 |
1529 | Skin.prototype.parseWeights = function ( element, sources ) {
1530 |
1531 | var v, vcount, inputs = [];
1532 |
1533 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1534 |
1535 | var child = element.childNodes[ i ];
1536 | if ( child.nodeType != 1 ) continue;
1537 |
1538 | switch ( child.nodeName ) {
1539 |
1540 | case 'input':
1541 |
1542 | inputs.push( ( new Input() ).parse( child ) );
1543 | break;
1544 |
1545 | case 'v':
1546 |
1547 | v = _ints( child.textContent );
1548 | break;
1549 |
1550 | case 'vcount':
1551 |
1552 | vcount = _ints( child.textContent );
1553 | break;
1554 |
1555 | default:
1556 | break;
1557 |
1558 | }
1559 |
1560 | }
1561 |
1562 | var index = 0;
1563 |
1564 | for ( var i = 0; i < vcount.length; i ++ ) {
1565 |
1566 | var numBones = vcount[i];
1567 | var vertex_weights = [];
1568 |
1569 | for ( var j = 0; j < numBones; j++ ) {
1570 |
1571 | var influence = {};
1572 |
1573 | for ( var k = 0; k < inputs.length; k ++ ) {
1574 |
1575 | var input = inputs[ k ];
1576 | var value = v[ index + input.offset ];
1577 |
1578 | switch ( input.semantic ) {
1579 |
1580 | case 'JOINT':
1581 |
1582 | influence.joint = value;//this.joints[value];
1583 | break;
1584 |
1585 | case 'WEIGHT':
1586 |
1587 | influence.weight = sources[ input.source ].data[ value ];
1588 | break;
1589 |
1590 | default:
1591 | break;
1592 |
1593 | }
1594 |
1595 | }
1596 |
1597 | vertex_weights.push( influence );
1598 | index += inputs.length;
1599 | }
1600 |
1601 | for ( var j = 0; j < vertex_weights.length; j ++ ) {
1602 |
1603 | vertex_weights[ j ].index = i;
1604 |
1605 | }
1606 |
1607 | this.weights.push( vertex_weights );
1608 |
1609 | }
1610 |
1611 | };
1612 |
1613 | function VisualScene () {
1614 |
1615 | this.id = "";
1616 | this.name = "";
1617 | this.nodes = [];
1618 | this.scene = new THREE.Object3D();
1619 |
1620 | };
1621 |
1622 | VisualScene.prototype.getChildById = function( id, recursive ) {
1623 |
1624 | for ( var i = 0; i < this.nodes.length; i ++ ) {
1625 |
1626 | var node = this.nodes[ i ].getChildById( id, recursive );
1627 |
1628 | if ( node ) {
1629 |
1630 | return node;
1631 |
1632 | }
1633 |
1634 | }
1635 |
1636 | return null;
1637 |
1638 | };
1639 |
1640 | VisualScene.prototype.getChildBySid = function( sid, recursive ) {
1641 |
1642 | for ( var i = 0; i < this.nodes.length; i ++ ) {
1643 |
1644 | var node = this.nodes[ i ].getChildBySid( sid, recursive );
1645 |
1646 | if ( node ) {
1647 |
1648 | return node;
1649 |
1650 | }
1651 |
1652 | }
1653 |
1654 | return null;
1655 |
1656 | };
1657 |
1658 | VisualScene.prototype.parse = function( element ) {
1659 |
1660 | this.id = element.getAttribute( 'id' );
1661 | this.name = element.getAttribute( 'name' );
1662 | this.nodes = [];
1663 |
1664 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1665 |
1666 | var child = element.childNodes[ i ];
1667 | if ( child.nodeType != 1 ) continue;
1668 |
1669 | switch ( child.nodeName ) {
1670 |
1671 | case 'node':
1672 |
1673 | this.nodes.push( ( new Node() ).parse( child ) );
1674 | break;
1675 |
1676 | default:
1677 | break;
1678 |
1679 | }
1680 |
1681 | }
1682 |
1683 | return this;
1684 |
1685 | };
1686 |
1687 | function Node() {
1688 |
1689 | this.id = "";
1690 | this.name = "";
1691 | this.sid = "";
1692 | this.nodes = [];
1693 | this.controllers = [];
1694 | this.transforms = [];
1695 | this.geometries = [];
1696 | this.channels = [];
1697 | this.matrix = new THREE.Matrix4();
1698 |
1699 | };
1700 |
1701 | Node.prototype.getChannelForTransform = function( transformSid ) {
1702 |
1703 | for ( var i = 0; i < this.channels.length; i ++ ) {
1704 |
1705 | var channel = this.channels[i];
1706 | var parts = channel.target.split('/');
1707 | var id = parts.shift();
1708 | var sid = parts.shift();
1709 | var dotSyntax = (sid.indexOf(".") >= 0);
1710 | var arrSyntax = (sid.indexOf("(") >= 0);
1711 | var arrIndices;
1712 | var member;
1713 |
1714 | if ( dotSyntax ) {
1715 |
1716 | parts = sid.split(".");
1717 | sid = parts.shift();
1718 | member = parts.shift();
1719 |
1720 | } else if ( arrSyntax ) {
1721 |
1722 | arrIndices = sid.split("(");
1723 | sid = arrIndices.shift();
1724 |
1725 | for ( var j = 0; j < arrIndices.length; j ++ ) {
1726 |
1727 | arrIndices[ j ] = parseInt( arrIndices[ j ].replace( /\)/, '' ) );
1728 |
1729 | }
1730 |
1731 | }
1732 |
1733 | if ( sid == transformSid ) {
1734 |
1735 | channel.info = { sid: sid, dotSyntax: dotSyntax, arrSyntax: arrSyntax, arrIndices: arrIndices };
1736 | return channel;
1737 |
1738 | }
1739 |
1740 | }
1741 |
1742 | return null;
1743 |
1744 | };
1745 |
1746 | Node.prototype.getChildById = function ( id, recursive ) {
1747 |
1748 | if ( this.id == id ) {
1749 |
1750 | return this;
1751 |
1752 | }
1753 |
1754 | if ( recursive ) {
1755 |
1756 | for ( var i = 0; i < this.nodes.length; i ++ ) {
1757 |
1758 | var n = this.nodes[ i ].getChildById( id, recursive );
1759 |
1760 | if ( n ) {
1761 |
1762 | return n;
1763 |
1764 | }
1765 |
1766 | }
1767 |
1768 | }
1769 |
1770 | return null;
1771 |
1772 | };
1773 |
1774 | Node.prototype.getChildBySid = function ( sid, recursive ) {
1775 |
1776 | if ( this.sid == sid ) {
1777 |
1778 | return this;
1779 |
1780 | }
1781 |
1782 | if ( recursive ) {
1783 |
1784 | for ( var i = 0; i < this.nodes.length; i ++ ) {
1785 |
1786 | var n = this.nodes[ i ].getChildBySid( sid, recursive );
1787 |
1788 | if ( n ) {
1789 |
1790 | return n;
1791 |
1792 | }
1793 |
1794 | }
1795 | }
1796 |
1797 | return null;
1798 |
1799 | };
1800 |
1801 | Node.prototype.getTransformBySid = function ( sid ) {
1802 |
1803 | for ( var i = 0; i < this.transforms.length; i ++ ) {
1804 |
1805 | if ( this.transforms[ i ].sid == sid ) return this.transforms[ i ];
1806 |
1807 | }
1808 |
1809 | return null;
1810 |
1811 | };
1812 |
1813 | Node.prototype.parse = function( element ) {
1814 |
1815 | var url;
1816 |
1817 | this.id = element.getAttribute('id');
1818 | this.sid = element.getAttribute('sid');
1819 | this.name = element.getAttribute('name');
1820 | this.type = element.getAttribute('type');
1821 |
1822 | this.type = this.type == 'JOINT' ? this.type : 'NODE';
1823 |
1824 | this.nodes = [];
1825 | this.transforms = [];
1826 | this.geometries = [];
1827 | this.cameras = [];
1828 | this.lights = [];
1829 | this.controllers = [];
1830 | this.matrix = new THREE.Matrix4();
1831 |
1832 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1833 |
1834 | var child = element.childNodes[ i ];
1835 | if ( child.nodeType != 1 ) continue;
1836 |
1837 | switch ( child.nodeName ) {
1838 |
1839 | case 'node':
1840 |
1841 | this.nodes.push( ( new Node() ).parse( child ) );
1842 | break;
1843 |
1844 | case 'instance_camera':
1845 |
1846 | this.cameras.push( ( new InstanceCamera() ).parse( child ) );
1847 | break;
1848 |
1849 | case 'instance_light':
1850 |
1851 | this.lights.push( ( new InstanceLight() ).parse( child ) );
1852 | break;
1853 |
1854 | case 'instance_controller':
1855 |
1856 | this.controllers.push( ( new InstanceController() ).parse( child ) );
1857 | break;
1858 |
1859 | case 'instance_geometry':
1860 |
1861 | this.geometries.push( ( new InstanceGeometry() ).parse( child ) );
1862 | break;
1863 |
1864 | case 'instance_node':
1865 |
1866 | url = child.getAttribute( 'url' ).replace( /^#/, '' );
1867 | var iNode = getLibraryNode( url );
1868 |
1869 | if ( iNode ) {
1870 |
1871 | this.nodes.push( ( new Node() ).parse( iNode )) ;
1872 |
1873 | }
1874 |
1875 | break;
1876 |
1877 | case 'rotate':
1878 | case 'translate':
1879 | case 'scale':
1880 | case 'matrix':
1881 | case 'lookat':
1882 | case 'skew':
1883 |
1884 | this.transforms.push( ( new Transform() ).parse( child ) );
1885 | break;
1886 |
1887 | case 'extra':
1888 | break;
1889 |
1890 | default:
1891 |
1892 | console.log( child.nodeName );
1893 | break;
1894 |
1895 | }
1896 |
1897 | }
1898 |
1899 | this.channels = getChannelsForNode( this );
1900 | bakeAnimations( this );
1901 |
1902 | this.updateMatrix();
1903 |
1904 | return this;
1905 |
1906 | };
1907 |
1908 | Node.prototype.updateMatrix = function () {
1909 |
1910 | this.matrix.identity();
1911 |
1912 | for ( var i = 0; i < this.transforms.length; i ++ ) {
1913 |
1914 | this.transforms[ i ].apply( this.matrix );
1915 |
1916 | }
1917 |
1918 | };
1919 |
1920 | function Transform () {
1921 |
1922 | this.sid = "";
1923 | this.type = "";
1924 | this.data = [];
1925 | this.obj = null;
1926 |
1927 | };
1928 |
1929 | Transform.prototype.parse = function ( element ) {
1930 |
1931 | this.sid = element.getAttribute( 'sid' );
1932 | this.type = element.nodeName;
1933 | this.data = _floats( element.textContent );
1934 | this.convert();
1935 |
1936 | return this;
1937 |
1938 | };
1939 |
1940 | Transform.prototype.convert = function () {
1941 |
1942 | switch ( this.type ) {
1943 |
1944 | case 'matrix':
1945 |
1946 | this.obj = getConvertedMat4( this.data );
1947 | break;
1948 |
1949 | case 'rotate':
1950 |
1951 | this.angle = THREE.Math.degToRad( this.data[3] );
1952 |
1953 | case 'translate':
1954 |
1955 | fixCoords( this.data, -1 );
1956 | this.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );
1957 | break;
1958 |
1959 | case 'scale':
1960 |
1961 | fixCoords( this.data, 1 );
1962 | this.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );
1963 | break;
1964 |
1965 | default:
1966 | console.log( 'Can not convert Transform of type ' + this.type );
1967 | break;
1968 |
1969 | }
1970 |
1971 | };
1972 |
1973 | Transform.prototype.apply = function () {
1974 |
1975 | var m1 = new THREE.Matrix4();
1976 |
1977 | return function ( matrix ) {
1978 |
1979 | switch ( this.type ) {
1980 |
1981 | case 'matrix':
1982 |
1983 | matrix.multiply( this.obj );
1984 |
1985 | break;
1986 |
1987 | case 'translate':
1988 |
1989 | matrix.multiply( m1.makeTranslation( this.obj.x, this.obj.y, this.obj.z ) );
1990 |
1991 | break;
1992 |
1993 | case 'rotate':
1994 |
1995 | matrix.multiply( m1.makeRotationAxis( this.obj, this.angle ) );
1996 |
1997 | break;
1998 |
1999 | case 'scale':
2000 |
2001 | matrix.scale( this.obj );
2002 |
2003 | break;
2004 |
2005 | }
2006 |
2007 | };
2008 |
2009 | }();
2010 |
2011 | Transform.prototype.update = function ( data, member ) {
2012 |
2013 | var members = [ 'X', 'Y', 'Z', 'ANGLE' ];
2014 |
2015 | switch ( this.type ) {
2016 |
2017 | case 'matrix':
2018 |
2019 | if ( ! member ) {
2020 |
2021 | this.obj.copy( data );
2022 |
2023 | } else if ( member.length === 1 ) {
2024 |
2025 | switch ( member[ 0 ] ) {
2026 |
2027 | case 0:
2028 |
2029 | this.obj.n11 = data[ 0 ];
2030 | this.obj.n21 = data[ 1 ];
2031 | this.obj.n31 = data[ 2 ];
2032 | this.obj.n41 = data[ 3 ];
2033 |
2034 | break;
2035 |
2036 | case 1:
2037 |
2038 | this.obj.n12 = data[ 0 ];
2039 | this.obj.n22 = data[ 1 ];
2040 | this.obj.n32 = data[ 2 ];
2041 | this.obj.n42 = data[ 3 ];
2042 |
2043 | break;
2044 |
2045 | case 2:
2046 |
2047 | this.obj.n13 = data[ 0 ];
2048 | this.obj.n23 = data[ 1 ];
2049 | this.obj.n33 = data[ 2 ];
2050 | this.obj.n43 = data[ 3 ];
2051 |
2052 | break;
2053 |
2054 | case 3:
2055 |
2056 | this.obj.n14 = data[ 0 ];
2057 | this.obj.n24 = data[ 1 ];
2058 | this.obj.n34 = data[ 2 ];
2059 | this.obj.n44 = data[ 3 ];
2060 |
2061 | break;
2062 |
2063 | }
2064 |
2065 | } else if ( member.length === 2 ) {
2066 |
2067 | var propName = 'n' + ( member[ 0 ] + 1 ) + ( member[ 1 ] + 1 );
2068 | this.obj[ propName ] = data;
2069 |
2070 | } else {
2071 |
2072 | console.log('Incorrect addressing of matrix in transform.');
2073 |
2074 | }
2075 |
2076 | break;
2077 |
2078 | case 'translate':
2079 | case 'scale':
2080 |
2081 | if ( Object.prototype.toString.call( member ) === '[object Array]' ) {
2082 |
2083 | member = members[ member[ 0 ] ];
2084 |
2085 | }
2086 |
2087 | switch ( member ) {
2088 |
2089 | case 'X':
2090 |
2091 | this.obj.x = data;
2092 | break;
2093 |
2094 | case 'Y':
2095 |
2096 | this.obj.y = data;
2097 | break;
2098 |
2099 | case 'Z':
2100 |
2101 | this.obj.z = data;
2102 | break;
2103 |
2104 | default:
2105 |
2106 | this.obj.x = data[ 0 ];
2107 | this.obj.y = data[ 1 ];
2108 | this.obj.z = data[ 2 ];
2109 | break;
2110 |
2111 | }
2112 |
2113 | break;
2114 |
2115 | case 'rotate':
2116 |
2117 | if ( Object.prototype.toString.call( member ) === '[object Array]' ) {
2118 |
2119 | member = members[ member[ 0 ] ];
2120 |
2121 | }
2122 |
2123 | switch ( member ) {
2124 |
2125 | case 'X':
2126 |
2127 | this.obj.x = data;
2128 | break;
2129 |
2130 | case 'Y':
2131 |
2132 | this.obj.y = data;
2133 | break;
2134 |
2135 | case 'Z':
2136 |
2137 | this.obj.z = data;
2138 | break;
2139 |
2140 | case 'ANGLE':
2141 |
2142 | this.angle = THREE.Math.degToRad( data );
2143 | break;
2144 |
2145 | default:
2146 |
2147 | this.obj.x = data[ 0 ];
2148 | this.obj.y = data[ 1 ];
2149 | this.obj.z = data[ 2 ];
2150 | this.angle = THREE.Math.degToRad( data[ 3 ] );
2151 | break;
2152 |
2153 | }
2154 | break;
2155 |
2156 | }
2157 |
2158 | };
2159 |
2160 | function InstanceController() {
2161 |
2162 | this.url = "";
2163 | this.skeleton = [];
2164 | this.instance_material = [];
2165 |
2166 | };
2167 |
2168 | InstanceController.prototype.parse = function ( element ) {
2169 |
2170 | this.url = element.getAttribute('url').replace(/^#/, '');
2171 | this.skeleton = [];
2172 | this.instance_material = [];
2173 |
2174 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2175 |
2176 | var child = element.childNodes[ i ];
2177 | if ( child.nodeType !== 1 ) continue;
2178 |
2179 | switch ( child.nodeName ) {
2180 |
2181 | case 'skeleton':
2182 |
2183 | this.skeleton.push( child.textContent.replace(/^#/, '') );
2184 | break;
2185 |
2186 | case 'bind_material':
2187 |
2188 | var instances = COLLADA.evaluate( './/dae:instance_material', child, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
2189 |
2190 | if ( instances ) {
2191 |
2192 | var instance = instances.iterateNext();
2193 |
2194 | while ( instance ) {
2195 |
2196 | this.instance_material.push( (new InstanceMaterial()).parse(instance) );
2197 | instance = instances.iterateNext();
2198 |
2199 | }
2200 |
2201 | }
2202 |
2203 | break;
2204 |
2205 | case 'extra':
2206 | break;
2207 |
2208 | default:
2209 | break;
2210 |
2211 | }
2212 | }
2213 |
2214 | return this;
2215 |
2216 | };
2217 |
2218 | function InstanceMaterial () {
2219 |
2220 | this.symbol = "";
2221 | this.target = "";
2222 |
2223 | };
2224 |
2225 | InstanceMaterial.prototype.parse = function ( element ) {
2226 |
2227 | this.symbol = element.getAttribute('symbol');
2228 | this.target = element.getAttribute('target').replace(/^#/, '');
2229 | return this;
2230 |
2231 | };
2232 |
2233 | function InstanceGeometry() {
2234 |
2235 | this.url = "";
2236 | this.instance_material = [];
2237 |
2238 | };
2239 |
2240 | InstanceGeometry.prototype.parse = function ( element ) {
2241 |
2242 | this.url = element.getAttribute('url').replace(/^#/, '');
2243 | this.instance_material = [];
2244 |
2245 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2246 |
2247 | var child = element.childNodes[i];
2248 | if ( child.nodeType != 1 ) continue;
2249 |
2250 | if ( child.nodeName == 'bind_material' ) {
2251 |
2252 | var instances = COLLADA.evaluate( './/dae:instance_material', child, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
2253 |
2254 | if ( instances ) {
2255 |
2256 | var instance = instances.iterateNext();
2257 |
2258 | while ( instance ) {
2259 |
2260 | this.instance_material.push( (new InstanceMaterial()).parse(instance) );
2261 | instance = instances.iterateNext();
2262 |
2263 | }
2264 |
2265 | }
2266 |
2267 | break;
2268 |
2269 | }
2270 |
2271 | }
2272 |
2273 | return this;
2274 |
2275 | };
2276 |
2277 | function Geometry() {
2278 |
2279 | this.id = "";
2280 | this.mesh = null;
2281 |
2282 | };
2283 |
2284 | Geometry.prototype.parse = function ( element ) {
2285 |
2286 | this.id = element.getAttribute('id');
2287 |
2288 | extractDoubleSided( this, element );
2289 |
2290 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2291 |
2292 | var child = element.childNodes[i];
2293 |
2294 | switch ( child.nodeName ) {
2295 |
2296 | case 'mesh':
2297 |
2298 | this.mesh = (new Mesh(this)).parse(child);
2299 | break;
2300 |
2301 | case 'extra':
2302 |
2303 | // console.log( child );
2304 | break;
2305 |
2306 | default:
2307 | break;
2308 | }
2309 | }
2310 |
2311 | return this;
2312 |
2313 | };
2314 |
2315 | function Mesh( geometry ) {
2316 |
2317 | this.geometry = geometry.id;
2318 | this.primitives = [];
2319 | this.vertices = null;
2320 | this.geometry3js = null;
2321 |
2322 | };
2323 |
2324 | Mesh.prototype.parse = function( element ) {
2325 |
2326 | this.primitives = [];
2327 |
2328 | var i, j;
2329 |
2330 | for ( i = 0; i < element.childNodes.length; i ++ ) {
2331 |
2332 | var child = element.childNodes[ i ];
2333 |
2334 | switch ( child.nodeName ) {
2335 |
2336 | case 'source':
2337 |
2338 | _source( child );
2339 | break;
2340 |
2341 | case 'vertices':
2342 |
2343 | this.vertices = ( new Vertices() ).parse( child );
2344 | break;
2345 |
2346 | case 'triangles':
2347 |
2348 | this.primitives.push( ( new Triangles().parse( child ) ) );
2349 | break;
2350 |
2351 | case 'polygons':
2352 |
2353 | this.primitives.push( ( new Polygons().parse( child ) ) );
2354 | break;
2355 |
2356 | case 'polylist':
2357 |
2358 | this.primitives.push( ( new Polylist().parse( child ) ) );
2359 | break;
2360 |
2361 | default:
2362 | break;
2363 |
2364 | }
2365 |
2366 | }
2367 |
2368 | this.geometry3js = new THREE.Geometry();
2369 |
2370 | var vertexData = sources[ this.vertices.input['POSITION'].source ].data;
2371 |
2372 | for ( i = 0; i < vertexData.length; i += 3 ) {
2373 |
2374 | this.geometry3js.vertices.push( getConvertedVec3( vertexData, i ).clone() );
2375 |
2376 | }
2377 |
2378 | for ( i = 0; i < this.primitives.length; i ++ ) {
2379 |
2380 | var primitive = this.primitives[ i ];
2381 | primitive.setVertices( this.vertices );
2382 | this.handlePrimitive( primitive, this.geometry3js );
2383 |
2384 | }
2385 |
2386 | this.geometry3js.computeCentroids();
2387 | this.geometry3js.computeFaceNormals();
2388 |
2389 | if ( this.geometry3js.calcNormals ) {
2390 |
2391 | this.geometry3js.computeVertexNormals();
2392 | delete this.geometry3js.calcNormals;
2393 |
2394 | }
2395 |
2396 | this.geometry3js.computeBoundingBox();
2397 |
2398 | return this;
2399 |
2400 | };
2401 |
2402 | Mesh.prototype.handlePrimitive = function( primitive, geom ) {
2403 |
2404 | var j, k, pList = primitive.p, inputs = primitive.inputs;
2405 | var input, index, idx32;
2406 | var source, numParams;
2407 | var vcIndex = 0, vcount = 3, maxOffset = 0;
2408 | var texture_sets = [];
2409 |
2410 | for ( j = 0; j < inputs.length; j ++ ) {
2411 |
2412 | input = inputs[ j ];
2413 | var offset = input.offset + 1;
2414 | maxOffset = (maxOffset < offset)? offset : maxOffset;
2415 |
2416 | switch ( input.semantic ) {
2417 |
2418 | case 'TEXCOORD':
2419 | texture_sets.push( input.set );
2420 | break;
2421 |
2422 | }
2423 |
2424 | }
2425 |
2426 | for ( var pCount = 0; pCount < pList.length; ++pCount ) {
2427 |
2428 | var p = pList[ pCount ], i = 0;
2429 |
2430 | while ( i < p.length ) {
2431 |
2432 | var vs = [];
2433 | var ns = [];
2434 | var ts = null;
2435 | var cs = [];
2436 |
2437 | if ( primitive.vcount ) {
2438 |
2439 | vcount = primitive.vcount.length ? primitive.vcount[ vcIndex ++ ] : primitive.vcount;
2440 |
2441 | } else {
2442 |
2443 | vcount = p.length / maxOffset;
2444 |
2445 | }
2446 |
2447 |
2448 | for ( j = 0; j < vcount; j ++ ) {
2449 |
2450 | for ( k = 0; k < inputs.length; k ++ ) {
2451 |
2452 | input = inputs[ k ];
2453 | source = sources[ input.source ];
2454 |
2455 | index = p[ i + ( j * maxOffset ) + input.offset ];
2456 | numParams = source.accessor.params.length;
2457 | idx32 = index * numParams;
2458 |
2459 | switch ( input.semantic ) {
2460 |
2461 | case 'VERTEX':
2462 |
2463 | vs.push( index );
2464 |
2465 | break;
2466 |
2467 | case 'NORMAL':
2468 |
2469 | ns.push( getConvertedVec3( source.data, idx32 ) );
2470 |
2471 | break;
2472 |
2473 | case 'TEXCOORD':
2474 |
2475 | ts = ts || { };
2476 | if ( ts[ input.set ] === undefined ) ts[ input.set ] = [];
2477 | // invert the V
2478 | ts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], source.data[ idx32 + 1 ] ) );
2479 |
2480 | break;
2481 |
2482 | case 'COLOR':
2483 |
2484 | cs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );
2485 |
2486 | break;
2487 |
2488 | default:
2489 |
2490 | break;
2491 |
2492 | }
2493 |
2494 | }
2495 |
2496 | }
2497 |
2498 | if ( ns.length == 0 ) {
2499 |
2500 | // check the vertices inputs
2501 | input = this.vertices.input.NORMAL;
2502 |
2503 | if ( input ) {
2504 |
2505 | source = sources[ input.source ];
2506 | numParams = source.accessor.params.length;
2507 |
2508 | for ( var ndx = 0, len = vs.length; ndx < len; ndx++ ) {
2509 |
2510 | ns.push( getConvertedVec3( source.data, vs[ ndx ] * numParams ) );
2511 |
2512 | }
2513 |
2514 | } else {
2515 |
2516 | geom.calcNormals = true;
2517 |
2518 | }
2519 |
2520 | }
2521 |
2522 | if ( !ts ) {
2523 |
2524 | ts = { };
2525 | // check the vertices inputs
2526 | input = this.vertices.input.TEXCOORD;
2527 |
2528 | if ( input ) {
2529 |
2530 | texture_sets.push( input.set );
2531 | source = sources[ input.source ];
2532 | numParams = source.accessor.params.length;
2533 |
2534 | for ( var ndx = 0, len = vs.length; ndx < len; ndx++ ) {
2535 |
2536 | idx32 = vs[ ndx ] * numParams;
2537 | if ( ts[ input.set ] === undefined ) ts[ input.set ] = [ ];
2538 | // invert the V
2539 | ts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], 1.0 - source.data[ idx32 + 1 ] ) );
2540 |
2541 | }
2542 |
2543 | }
2544 |
2545 | }
2546 |
2547 | if ( cs.length == 0 ) {
2548 |
2549 | // check the vertices inputs
2550 | input = this.vertices.input.COLOR;
2551 |
2552 | if ( input ) {
2553 |
2554 | source = sources[ input.source ];
2555 | numParams = source.accessor.params.length;
2556 |
2557 | for ( var ndx = 0, len = vs.length; ndx < len; ndx++ ) {
2558 |
2559 | idx32 = vs[ ndx ] * numParams;
2560 | cs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );
2561 |
2562 | }
2563 |
2564 | }
2565 |
2566 | }
2567 |
2568 | var face = null, faces = [], uv, uvArr;
2569 |
2570 | if ( vcount === 3 ) {
2571 |
2572 | faces.push( new THREE.Face3( vs[0], vs[1], vs[2], ns, cs.length ? cs : new THREE.Color() ) );
2573 |
2574 | } else if ( vcount === 4 ) {
2575 | faces.push( new THREE.Face4( vs[0], vs[1], vs[2], vs[3], ns, cs.length ? cs : new THREE.Color() ) );
2576 |
2577 | } else if ( vcount > 4 && options.subdivideFaces ) {
2578 |
2579 | var clr = cs.length ? cs : new THREE.Color(),
2580 | vec1, vec2, vec3, v1, v2, norm;
2581 |
2582 | // subdivide into multiple Face3s
2583 |
2584 | for ( k = 1; k < vcount - 1; ) {
2585 |
2586 | // FIXME: normals don't seem to be quite right
2587 |
2588 | faces.push( new THREE.Face3( vs[0], vs[k], vs[k+1], [ ns[0], ns[k++], ns[k] ], clr ) );
2589 |
2590 | }
2591 |
2592 | }
2593 |
2594 | if ( faces.length ) {
2595 |
2596 | for ( var ndx = 0, len = faces.length; ndx < len; ndx ++ ) {
2597 |
2598 | face = faces[ndx];
2599 | face.daeMaterial = primitive.material;
2600 | geom.faces.push( face );
2601 |
2602 | for ( k = 0; k < texture_sets.length; k++ ) {
2603 |
2604 | uv = ts[ texture_sets[k] ];
2605 |
2606 | if ( vcount > 4 ) {
2607 |
2608 | // Grab the right UVs for the vertices in this face
2609 | uvArr = [ uv[0], uv[ndx+1], uv[ndx+2] ];
2610 |
2611 | } else if ( vcount === 4 ) {
2612 |
2613 | uvArr = [ uv[0], uv[1], uv[2], uv[3] ];
2614 |
2615 | } else {
2616 |
2617 | uvArr = [ uv[0], uv[1], uv[2] ];
2618 |
2619 | }
2620 |
2621 | if ( !geom.faceVertexUvs[k] ) {
2622 |
2623 | geom.faceVertexUvs[k] = [];
2624 |
2625 | }
2626 |
2627 | geom.faceVertexUvs[k].push( uvArr );
2628 |
2629 | }
2630 |
2631 | }
2632 |
2633 | } else {
2634 |
2635 | console.log( 'dropped face with vcount ' + vcount + ' for geometry with id: ' + geom.id );
2636 |
2637 | }
2638 |
2639 | i += maxOffset * vcount;
2640 |
2641 | }
2642 | }
2643 |
2644 | };
2645 |
2646 | function Polygons () {
2647 |
2648 | this.material = "";
2649 | this.count = 0;
2650 | this.inputs = [];
2651 | this.vcount = null;
2652 | this.p = [];
2653 | this.geometry = new THREE.Geometry();
2654 |
2655 | };
2656 |
2657 | Polygons.prototype.setVertices = function ( vertices ) {
2658 |
2659 | for ( var i = 0; i < this.inputs.length; i ++ ) {
2660 |
2661 | if ( this.inputs[ i ].source == vertices.id ) {
2662 |
2663 | this.inputs[ i ].source = vertices.input[ 'POSITION' ].source;
2664 |
2665 | }
2666 |
2667 | }
2668 |
2669 | };
2670 |
2671 | Polygons.prototype.parse = function ( element ) {
2672 |
2673 | this.material = element.getAttribute( 'material' );
2674 | this.count = _attr_as_int( element, 'count', 0 );
2675 |
2676 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2677 |
2678 | var child = element.childNodes[ i ];
2679 |
2680 | switch ( child.nodeName ) {
2681 |
2682 | case 'input':
2683 |
2684 | this.inputs.push( ( new Input() ).parse( element.childNodes[ i ] ) );
2685 | break;
2686 |
2687 | case 'vcount':
2688 |
2689 | this.vcount = _ints( child.textContent );
2690 | break;
2691 |
2692 | case 'p':
2693 |
2694 | this.p.push( _ints( child.textContent ) );
2695 | break;
2696 |
2697 | case 'ph':
2698 |
2699 | console.warn( 'polygon holes not yet supported!' );
2700 | break;
2701 |
2702 | default:
2703 | break;
2704 |
2705 | }
2706 |
2707 | }
2708 |
2709 | return this;
2710 |
2711 | };
2712 |
2713 | function Polylist () {
2714 |
2715 | Polygons.call( this );
2716 |
2717 | this.vcount = [];
2718 |
2719 | };
2720 |
2721 | Polylist.prototype = Object.create( Polygons.prototype );
2722 |
2723 | function Triangles () {
2724 |
2725 | Polygons.call( this );
2726 |
2727 | this.vcount = 3;
2728 |
2729 | };
2730 |
2731 | Triangles.prototype = Object.create( Polygons.prototype );
2732 |
2733 | function Accessor() {
2734 |
2735 | this.source = "";
2736 | this.count = 0;
2737 | this.stride = 0;
2738 | this.params = [];
2739 |
2740 | };
2741 |
2742 | Accessor.prototype.parse = function ( element ) {
2743 |
2744 | this.params = [];
2745 | this.source = element.getAttribute( 'source' );
2746 | this.count = _attr_as_int( element, 'count', 0 );
2747 | this.stride = _attr_as_int( element, 'stride', 0 );
2748 |
2749 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2750 |
2751 | var child = element.childNodes[ i ];
2752 |
2753 | if ( child.nodeName == 'param' ) {
2754 |
2755 | var param = {};
2756 | param[ 'name' ] = child.getAttribute( 'name' );
2757 | param[ 'type' ] = child.getAttribute( 'type' );
2758 | this.params.push( param );
2759 |
2760 | }
2761 |
2762 | }
2763 |
2764 | return this;
2765 |
2766 | };
2767 |
2768 | function Vertices() {
2769 |
2770 | this.input = {};
2771 |
2772 | };
2773 |
2774 | Vertices.prototype.parse = function ( element ) {
2775 |
2776 | this.id = element.getAttribute('id');
2777 |
2778 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2779 |
2780 | if ( element.childNodes[i].nodeName == 'input' ) {
2781 |
2782 | var input = ( new Input() ).parse( element.childNodes[ i ] );
2783 | this.input[ input.semantic ] = input;
2784 |
2785 | }
2786 |
2787 | }
2788 |
2789 | return this;
2790 |
2791 | };
2792 |
2793 | function Input () {
2794 |
2795 | this.semantic = "";
2796 | this.offset = 0;
2797 | this.source = "";
2798 | this.set = 0;
2799 |
2800 | };
2801 |
2802 | Input.prototype.parse = function ( element ) {
2803 |
2804 | this.semantic = element.getAttribute('semantic');
2805 | this.source = element.getAttribute('source').replace(/^#/, '');
2806 | this.set = _attr_as_int(element, 'set', -1);
2807 | this.offset = _attr_as_int(element, 'offset', 0);
2808 |
2809 | if ( this.semantic == 'TEXCOORD' && this.set < 0 ) {
2810 |
2811 | this.set = 0;
2812 |
2813 | }
2814 |
2815 | return this;
2816 |
2817 | };
2818 |
2819 | function Source ( id ) {
2820 |
2821 | this.id = id;
2822 | this.type = null;
2823 |
2824 | };
2825 |
2826 | Source.prototype.parse = function ( element ) {
2827 |
2828 | this.id = element.getAttribute( 'id' );
2829 |
2830 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2831 |
2832 | var child = element.childNodes[i];
2833 |
2834 | switch ( child.nodeName ) {
2835 |
2836 | case 'bool_array':
2837 |
2838 | this.data = _bools( child.textContent );
2839 | this.type = child.nodeName;
2840 | break;
2841 |
2842 | case 'float_array':
2843 |
2844 | this.data = _floats( child.textContent );
2845 | this.type = child.nodeName;
2846 | break;
2847 |
2848 | case 'int_array':
2849 |
2850 | this.data = _ints( child.textContent );
2851 | this.type = child.nodeName;
2852 | break;
2853 |
2854 | case 'IDREF_array':
2855 | case 'Name_array':
2856 |
2857 | this.data = _strings( child.textContent );
2858 | this.type = child.nodeName;
2859 | break;
2860 |
2861 | case 'technique_common':
2862 |
2863 | for ( var j = 0; j < child.childNodes.length; j ++ ) {
2864 |
2865 | if ( child.childNodes[ j ].nodeName == 'accessor' ) {
2866 |
2867 | this.accessor = ( new Accessor() ).parse( child.childNodes[ j ] );
2868 | break;
2869 |
2870 | }
2871 | }
2872 | break;
2873 |
2874 | default:
2875 | // console.log(child.nodeName);
2876 | break;
2877 |
2878 | }
2879 |
2880 | }
2881 |
2882 | return this;
2883 |
2884 | };
2885 |
2886 | Source.prototype.read = function () {
2887 |
2888 | var result = [];
2889 |
2890 | //for (var i = 0; i < this.accessor.params.length; i++) {
2891 |
2892 | var param = this.accessor.params[ 0 ];
2893 |
2894 | //console.log(param.name + " " + param.type);
2895 |
2896 | switch ( param.type ) {
2897 |
2898 | case 'IDREF':
2899 | case 'Name': case 'name':
2900 | case 'float':
2901 |
2902 | return this.data;
2903 |
2904 | case 'float4x4':
2905 |
2906 | for ( var j = 0; j < this.data.length; j += 16 ) {
2907 |
2908 | var s = this.data.slice( j, j + 16 );
2909 | var m = getConvertedMat4( s );
2910 | result.push( m );
2911 | }
2912 |
2913 | break;
2914 |
2915 | default:
2916 |
2917 | console.log( 'ColladaLoader: Source: Read dont know how to read ' + param.type + '.' );
2918 | break;
2919 |
2920 | }
2921 |
2922 | //}
2923 |
2924 | return result;
2925 |
2926 | };
2927 |
2928 | function Material () {
2929 |
2930 | this.id = "";
2931 | this.name = "";
2932 | this.instance_effect = null;
2933 |
2934 | };
2935 |
2936 | Material.prototype.parse = function ( element ) {
2937 |
2938 | this.id = element.getAttribute( 'id' );
2939 | this.name = element.getAttribute( 'name' );
2940 |
2941 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2942 |
2943 | if ( element.childNodes[ i ].nodeName == 'instance_effect' ) {
2944 |
2945 | this.instance_effect = ( new InstanceEffect() ).parse( element.childNodes[ i ] );
2946 | break;
2947 |
2948 | }
2949 |
2950 | }
2951 |
2952 | return this;
2953 |
2954 | };
2955 |
2956 | function ColorOrTexture () {
2957 |
2958 | this.color = new THREE.Color();
2959 | this.color.setRGB( Math.random(), Math.random(), Math.random() );
2960 | this.color.a = 1.0;
2961 |
2962 | this.texture = null;
2963 | this.texcoord = null;
2964 | this.texOpts = null;
2965 |
2966 | };
2967 |
2968 | ColorOrTexture.prototype.isColor = function () {
2969 |
2970 | return ( this.texture == null );
2971 |
2972 | };
2973 |
2974 | ColorOrTexture.prototype.isTexture = function () {
2975 |
2976 | return ( this.texture != null );
2977 |
2978 | };
2979 |
2980 | ColorOrTexture.prototype.parse = function ( element ) {
2981 |
2982 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2983 |
2984 | var child = element.childNodes[ i ];
2985 | if ( child.nodeType != 1 ) continue;
2986 |
2987 | switch ( child.nodeName ) {
2988 |
2989 | case 'color':
2990 |
2991 | var rgba = _floats( child.textContent );
2992 | this.color = new THREE.Color();
2993 | this.color.setRGB( rgba[0], rgba[1], rgba[2] );
2994 | this.color.a = rgba[3];
2995 | break;
2996 |
2997 | case 'texture':
2998 |
2999 | this.texture = child.getAttribute('texture');
3000 | this.texcoord = child.getAttribute('texcoord');
3001 | // Defaults from:
3002 | // https://collada.org/mediawiki/index.php/Maya_texture_placement_MAYA_extension
3003 | this.texOpts = {
3004 | offsetU: 0,
3005 | offsetV: 0,
3006 | repeatU: 1,
3007 | repeatV: 1,
3008 | wrapU: 1,
3009 | wrapV: 1,
3010 | };
3011 | this.parseTexture( child );
3012 | break;
3013 |
3014 | default:
3015 | break;
3016 |
3017 | }
3018 |
3019 | }
3020 |
3021 | return this;
3022 |
3023 | };
3024 |
3025 | ColorOrTexture.prototype.parseTexture = function ( element ) {
3026 |
3027 | if ( ! element.childNodes ) return this;
3028 |
3029 | // This should be supported by Maya, 3dsMax, and MotionBuilder
3030 |
3031 | if ( element.childNodes[1] && element.childNodes[1].nodeName === 'extra' ) {
3032 |
3033 | element = element.childNodes[1];
3034 |
3035 | if ( element.childNodes[1] && element.childNodes[1].nodeName === 'technique' ) {
3036 |
3037 | element = element.childNodes[1];
3038 |
3039 | }
3040 |
3041 | }
3042 |
3043 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3044 |
3045 | var child = element.childNodes[ i ];
3046 |
3047 | switch ( child.nodeName ) {
3048 |
3049 | case 'offsetU':
3050 | case 'offsetV':
3051 | case 'repeatU':
3052 | case 'repeatV':
3053 |
3054 | this.texOpts[ child.nodeName ] = parseFloat( child.textContent );
3055 | break;
3056 |
3057 | case 'wrapU':
3058 | case 'wrapV':
3059 |
3060 | this.texOpts[ child.nodeName ] = parseInt( child.textContent );
3061 | break;
3062 |
3063 | default:
3064 | this.texOpts[ child.nodeName ] = child.textContent;
3065 | break;
3066 |
3067 | }
3068 |
3069 | }
3070 |
3071 | return this;
3072 |
3073 | };
3074 |
3075 | function Shader ( type, effect ) {
3076 |
3077 | this.type = type;
3078 | this.effect = effect;
3079 | this.material = null;
3080 |
3081 | };
3082 |
3083 | Shader.prototype.parse = function ( element ) {
3084 |
3085 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3086 |
3087 | var child = element.childNodes[ i ];
3088 | if ( child.nodeType != 1 ) continue;
3089 |
3090 | switch ( child.nodeName ) {
3091 |
3092 | case 'ambient':
3093 | case 'emission':
3094 | case 'diffuse':
3095 | case 'specular':
3096 | case 'transparent':
3097 |
3098 | this[ child.nodeName ] = ( new ColorOrTexture() ).parse( child );
3099 | break;
3100 |
3101 | case 'shininess':
3102 | case 'reflectivity':
3103 | case 'index_of_refraction':
3104 | case 'transparency':
3105 |
3106 | var f = evaluateXPath( child, './/dae:float' );
3107 |
3108 | if ( f.length > 0 )
3109 | this[ child.nodeName ] = parseFloat( f[ 0 ].textContent );
3110 |
3111 | break;
3112 |
3113 | default:
3114 | break;
3115 |
3116 | }
3117 |
3118 | }
3119 |
3120 | this.create();
3121 | return this;
3122 |
3123 | };
3124 |
3125 | Shader.prototype.create = function() {
3126 |
3127 | var props = {};
3128 | var transparent = ( this['transparency'] !== undefined && this['transparency'] < 1.0 );
3129 |
3130 | for ( var prop in this ) {
3131 |
3132 | switch ( prop ) {
3133 |
3134 | case 'ambient':
3135 | case 'emission':
3136 | case 'diffuse':
3137 | case 'specular':
3138 |
3139 | var cot = this[ prop ];
3140 |
3141 | if ( cot instanceof ColorOrTexture ) {
3142 |
3143 | if ( cot.isTexture() ) {
3144 |
3145 | var samplerId = cot.texture;
3146 | var surfaceId = this.effect.sampler[samplerId].source;
3147 |
3148 | if ( surfaceId ) {
3149 |
3150 | var surface = this.effect.surface[surfaceId];
3151 | var image = images[surface.init_from];
3152 |
3153 | if (image) {
3154 |
3155 | var texture = THREE.ImageUtils.loadTexture(baseUrl + image.init_from);
3156 | texture.wrapS = cot.texOpts.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
3157 | texture.wrapT = cot.texOpts.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
3158 | texture.offset.x = cot.texOpts.offsetU;
3159 | texture.offset.y = cot.texOpts.offsetV;
3160 | texture.repeat.x = cot.texOpts.repeatU;
3161 | texture.repeat.y = cot.texOpts.repeatV;
3162 | props['map'] = texture;
3163 |
3164 | // Texture with baked lighting?
3165 | if (prop === 'emission') props['emissive'] = 0xffffff;
3166 |
3167 | }
3168 |
3169 | }
3170 |
3171 | } else if ( prop === 'diffuse' || !transparent ) {
3172 |
3173 | if ( prop === 'emission' ) {
3174 |
3175 | props[ 'emissive' ] = cot.color.getHex();
3176 |
3177 | } else {
3178 |
3179 | props[ prop ] = cot.color.getHex();
3180 |
3181 | }
3182 |
3183 | }
3184 |
3185 | }
3186 |
3187 | break;
3188 |
3189 | case 'shininess':
3190 |
3191 | props[ prop ] = this[ prop ];
3192 | break;
3193 |
3194 | case 'reflectivity':
3195 |
3196 | props[ prop ] = this[ prop ];
3197 | if( props[ prop ] > 0.0 ) props['envMap'] = options.defaultEnvMap;
3198 | props['combine'] = THREE.MixOperation; //mix regular shading with reflective component
3199 | break;
3200 |
3201 | case 'index_of_refraction':
3202 |
3203 | props[ 'refractionRatio' ] = this[ prop ]; //TODO: "index_of_refraction" becomes "refractionRatio" in shader, but I'm not sure if the two are actually comparable
3204 | if ( this[ prop ] !== 1.0 ) props['envMap'] = options.defaultEnvMap;
3205 | break;
3206 |
3207 | case 'transparency':
3208 |
3209 | if ( transparent ) {
3210 |
3211 | props[ 'transparent' ] = true;
3212 | props[ 'opacity' ] = this[ prop ];
3213 | transparent = true;
3214 |
3215 | }
3216 |
3217 | break;
3218 |
3219 | default:
3220 | break;
3221 |
3222 | }
3223 |
3224 | }
3225 |
3226 | props[ 'shading' ] = preferredShading;
3227 | props[ 'side' ] = this.effect.doubleSided ? THREE.DoubleSide : THREE.FrontSide;
3228 |
3229 | switch ( this.type ) {
3230 |
3231 | case 'constant':
3232 |
3233 | if (props.emissive != undefined) props.color = props.emissive;
3234 | this.material = new THREE.MeshBasicMaterial( props );
3235 | break;
3236 |
3237 | case 'phong':
3238 | case 'blinn':
3239 |
3240 | if (props.diffuse != undefined) props.color = props.diffuse;
3241 | this.material = new THREE.MeshPhongMaterial( props );
3242 | break;
3243 |
3244 | case 'lambert':
3245 | default:
3246 |
3247 | if (props.diffuse != undefined) props.color = props.diffuse;
3248 | this.material = new THREE.MeshLambertMaterial( props );
3249 | break;
3250 |
3251 | }
3252 |
3253 | return this.material;
3254 |
3255 | };
3256 |
3257 | function Surface ( effect ) {
3258 |
3259 | this.effect = effect;
3260 | this.init_from = null;
3261 | this.format = null;
3262 |
3263 | };
3264 |
3265 | Surface.prototype.parse = function ( element ) {
3266 |
3267 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3268 |
3269 | var child = element.childNodes[ i ];
3270 | if ( child.nodeType != 1 ) continue;
3271 |
3272 | switch ( child.nodeName ) {
3273 |
3274 | case 'init_from':
3275 |
3276 | this.init_from = child.textContent;
3277 | break;
3278 |
3279 | case 'format':
3280 |
3281 | this.format = child.textContent;
3282 | break;
3283 |
3284 | default:
3285 |
3286 | console.log( "unhandled Surface prop: " + child.nodeName );
3287 | break;
3288 |
3289 | }
3290 |
3291 | }
3292 |
3293 | return this;
3294 |
3295 | };
3296 |
3297 | function Sampler2D ( effect ) {
3298 |
3299 | this.effect = effect;
3300 | this.source = null;
3301 | this.wrap_s = null;
3302 | this.wrap_t = null;
3303 | this.minfilter = null;
3304 | this.magfilter = null;
3305 | this.mipfilter = null;
3306 |
3307 | };
3308 |
3309 | Sampler2D.prototype.parse = function ( element ) {
3310 |
3311 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3312 |
3313 | var child = element.childNodes[ i ];
3314 | if ( child.nodeType != 1 ) continue;
3315 |
3316 | switch ( child.nodeName ) {
3317 |
3318 | case 'source':
3319 |
3320 | this.source = child.textContent;
3321 | break;
3322 |
3323 | case 'minfilter':
3324 |
3325 | this.minfilter = child.textContent;
3326 | break;
3327 |
3328 | case 'magfilter':
3329 |
3330 | this.magfilter = child.textContent;
3331 | break;
3332 |
3333 | case 'mipfilter':
3334 |
3335 | this.mipfilter = child.textContent;
3336 | break;
3337 |
3338 | case 'wrap_s':
3339 |
3340 | this.wrap_s = child.textContent;
3341 | break;
3342 |
3343 | case 'wrap_t':
3344 |
3345 | this.wrap_t = child.textContent;
3346 | break;
3347 |
3348 | default:
3349 |
3350 | console.log( "unhandled Sampler2D prop: " + child.nodeName );
3351 | break;
3352 |
3353 | }
3354 |
3355 | }
3356 |
3357 | return this;
3358 |
3359 | };
3360 |
3361 | function Effect () {
3362 |
3363 | this.id = "";
3364 | this.name = "";
3365 | this.shader = null;
3366 | this.surface = {};
3367 | this.sampler = {};
3368 |
3369 | };
3370 |
3371 | Effect.prototype.create = function () {
3372 |
3373 | if ( this.shader == null ) {
3374 |
3375 | return null;
3376 |
3377 | }
3378 |
3379 | };
3380 |
3381 | Effect.prototype.parse = function ( element ) {
3382 |
3383 | this.id = element.getAttribute( 'id' );
3384 | this.name = element.getAttribute( 'name' );
3385 |
3386 | extractDoubleSided( this, element );
3387 |
3388 | this.shader = null;
3389 |
3390 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3391 |
3392 | var child = element.childNodes[ i ];
3393 | if ( child.nodeType != 1 ) continue;
3394 |
3395 | switch ( child.nodeName ) {
3396 |
3397 | case 'profile_COMMON':
3398 |
3399 | this.parseTechnique( this.parseProfileCOMMON( child ) );
3400 | break;
3401 |
3402 | default:
3403 | break;
3404 |
3405 | }
3406 |
3407 | }
3408 |
3409 | return this;
3410 |
3411 | };
3412 |
3413 | Effect.prototype.parseNewparam = function ( element ) {
3414 |
3415 | var sid = element.getAttribute( 'sid' );
3416 |
3417 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3418 |
3419 | var child = element.childNodes[ i ];
3420 | if ( child.nodeType != 1 ) continue;
3421 |
3422 | switch ( child.nodeName ) {
3423 |
3424 | case 'surface':
3425 |
3426 | this.surface[sid] = ( new Surface( this ) ).parse( child );
3427 | break;
3428 |
3429 | case 'sampler2D':
3430 |
3431 | this.sampler[sid] = ( new Sampler2D( this ) ).parse( child );
3432 | break;
3433 |
3434 | case 'extra':
3435 |
3436 | break;
3437 |
3438 | default:
3439 |
3440 | console.log( child.nodeName );
3441 | break;
3442 |
3443 | }
3444 |
3445 | }
3446 |
3447 | };
3448 |
3449 | Effect.prototype.parseProfileCOMMON = function ( element ) {
3450 |
3451 | var technique;
3452 |
3453 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3454 |
3455 | var child = element.childNodes[ i ];
3456 |
3457 | if ( child.nodeType != 1 ) continue;
3458 |
3459 | switch ( child.nodeName ) {
3460 |
3461 | case 'profile_COMMON':
3462 |
3463 | this.parseProfileCOMMON( child );
3464 | break;
3465 |
3466 | case 'technique':
3467 |
3468 | technique = child;
3469 | break;
3470 |
3471 | case 'newparam':
3472 |
3473 | this.parseNewparam( child );
3474 | break;
3475 |
3476 | case 'image':
3477 |
3478 | var _image = ( new _Image() ).parse( child );
3479 | images[ _image.id ] = _image;
3480 | break;
3481 |
3482 | case 'extra':
3483 | break;
3484 |
3485 | default:
3486 |
3487 | console.log( child.nodeName );
3488 | break;
3489 |
3490 | }
3491 |
3492 | }
3493 |
3494 | return technique;
3495 |
3496 | };
3497 |
3498 | Effect.prototype.parseTechnique= function ( element ) {
3499 |
3500 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3501 |
3502 | var child = element.childNodes[i];
3503 | if ( child.nodeType != 1 ) continue;
3504 |
3505 | switch ( child.nodeName ) {
3506 |
3507 | case 'constant':
3508 | case 'lambert':
3509 | case 'blinn':
3510 | case 'phong':
3511 |
3512 | this.shader = ( new Shader( child.nodeName, this ) ).parse( child );
3513 | break;
3514 |
3515 | default:
3516 | break;
3517 |
3518 | }
3519 |
3520 | }
3521 |
3522 | };
3523 |
3524 | function InstanceEffect () {
3525 |
3526 | this.url = "";
3527 |
3528 | };
3529 |
3530 | InstanceEffect.prototype.parse = function ( element ) {
3531 |
3532 | this.url = element.getAttribute( 'url' ).replace( /^#/, '' );
3533 | return this;
3534 |
3535 | };
3536 |
3537 | function Animation() {
3538 |
3539 | this.id = "";
3540 | this.name = "";
3541 | this.source = {};
3542 | this.sampler = [];
3543 | this.channel = [];
3544 |
3545 | };
3546 |
3547 | Animation.prototype.parse = function ( element ) {
3548 |
3549 | this.id = element.getAttribute( 'id' );
3550 | this.name = element.getAttribute( 'name' );
3551 | this.source = {};
3552 |
3553 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3554 |
3555 | var child = element.childNodes[ i ];
3556 |
3557 | if ( child.nodeType != 1 ) continue;
3558 |
3559 | switch ( child.nodeName ) {
3560 |
3561 | case 'animation':
3562 |
3563 | var anim = ( new Animation() ).parse( child );
3564 |
3565 | for ( var src in anim.source ) {
3566 |
3567 | this.source[ src ] = anim.source[ src ];
3568 |
3569 | }
3570 |
3571 | for ( var j = 0; j < anim.channel.length; j ++ ) {
3572 |
3573 | this.channel.push( anim.channel[ j ] );
3574 | this.sampler.push( anim.sampler[ j ] );
3575 |
3576 | }
3577 |
3578 | break;
3579 |
3580 | case 'source':
3581 |
3582 | var src = ( new Source() ).parse( child );
3583 | this.source[ src.id ] = src;
3584 | break;
3585 |
3586 | case 'sampler':
3587 |
3588 | this.sampler.push( ( new Sampler( this ) ).parse( child ) );
3589 | break;
3590 |
3591 | case 'channel':
3592 |
3593 | this.channel.push( ( new Channel( this ) ).parse( child ) );
3594 | break;
3595 |
3596 | default:
3597 | break;
3598 |
3599 | }
3600 |
3601 | }
3602 |
3603 | return this;
3604 |
3605 | };
3606 |
3607 | function Channel( animation ) {
3608 |
3609 | this.animation = animation;
3610 | this.source = "";
3611 | this.target = "";
3612 | this.fullSid = null;
3613 | this.sid = null;
3614 | this.dotSyntax = null;
3615 | this.arrSyntax = null;
3616 | this.arrIndices = null;
3617 | this.member = null;
3618 |
3619 | };
3620 |
3621 | Channel.prototype.parse = function ( element ) {
3622 |
3623 | this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
3624 | this.target = element.getAttribute( 'target' );
3625 |
3626 | var parts = this.target.split( '/' );
3627 |
3628 | var id = parts.shift();
3629 | var sid = parts.shift();
3630 |
3631 | var dotSyntax = ( sid.indexOf(".") >= 0 );
3632 | var arrSyntax = ( sid.indexOf("(") >= 0 );
3633 |
3634 | if ( dotSyntax ) {
3635 |
3636 | parts = sid.split(".");
3637 | this.sid = parts.shift();
3638 | this.member = parts.shift();
3639 |
3640 | } else if ( arrSyntax ) {
3641 |
3642 | var arrIndices = sid.split("(");
3643 | this.sid = arrIndices.shift();
3644 |
3645 | for (var j = 0; j < arrIndices.length; j ++ ) {
3646 |
3647 | arrIndices[j] = parseInt( arrIndices[j].replace(/\)/, '') );
3648 |
3649 | }
3650 |
3651 | this.arrIndices = arrIndices;
3652 |
3653 | } else {
3654 |
3655 | this.sid = sid;
3656 |
3657 | }
3658 |
3659 | this.fullSid = sid;
3660 | this.dotSyntax = dotSyntax;
3661 | this.arrSyntax = arrSyntax;
3662 |
3663 | return this;
3664 |
3665 | };
3666 |
3667 | function Sampler ( animation ) {
3668 |
3669 | this.id = "";
3670 | this.animation = animation;
3671 | this.inputs = [];
3672 | this.input = null;
3673 | this.output = null;
3674 | this.strideOut = null;
3675 | this.interpolation = null;
3676 | this.startTime = null;
3677 | this.endTime = null;
3678 | this.duration = 0;
3679 |
3680 | };
3681 |
3682 | Sampler.prototype.parse = function ( element ) {
3683 |
3684 | this.id = element.getAttribute( 'id' );
3685 | this.inputs = [];
3686 |
3687 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3688 |
3689 | var child = element.childNodes[ i ];
3690 | if ( child.nodeType != 1 ) continue;
3691 |
3692 | switch ( child.nodeName ) {
3693 |
3694 | case 'input':
3695 |
3696 | this.inputs.push( (new Input()).parse( child ) );
3697 | break;
3698 |
3699 | default:
3700 | break;
3701 |
3702 | }
3703 |
3704 | }
3705 |
3706 | return this;
3707 |
3708 | };
3709 |
3710 | Sampler.prototype.create = function () {
3711 |
3712 | for ( var i = 0; i < this.inputs.length; i ++ ) {
3713 |
3714 | var input = this.inputs[ i ];
3715 | var source = this.animation.source[ input.source ];
3716 |
3717 | switch ( input.semantic ) {
3718 |
3719 | case 'INPUT':
3720 |
3721 | this.input = source.read();
3722 | break;
3723 |
3724 | case 'OUTPUT':
3725 |
3726 | this.output = source.read();
3727 | this.strideOut = source.accessor.stride;
3728 | break;
3729 |
3730 | case 'INTERPOLATION':
3731 |
3732 | this.interpolation = source.read();
3733 | break;
3734 |
3735 | case 'IN_TANGENT':
3736 |
3737 | break;
3738 |
3739 | case 'OUT_TANGENT':
3740 |
3741 | break;
3742 |
3743 | default:
3744 |
3745 | console.log(input.semantic);
3746 | break;
3747 |
3748 | }
3749 |
3750 | }
3751 |
3752 | this.startTime = 0;
3753 | this.endTime = 0;
3754 | this.duration = 0;
3755 |
3756 | if ( this.input.length ) {
3757 |
3758 | this.startTime = 100000000;
3759 | this.endTime = -100000000;
3760 |
3761 | for ( var i = 0; i < this.input.length; i ++ ) {
3762 |
3763 | this.startTime = Math.min( this.startTime, this.input[ i ] );
3764 | this.endTime = Math.max( this.endTime, this.input[ i ] );
3765 |
3766 | }
3767 |
3768 | this.duration = this.endTime - this.startTime;
3769 |
3770 | }
3771 |
3772 | };
3773 |
3774 | Sampler.prototype.getData = function ( type, ndx ) {
3775 |
3776 | var data;
3777 |
3778 | if ( type === 'matrix' && this.strideOut === 16 ) {
3779 |
3780 | data = this.output[ ndx ];
3781 |
3782 | } else if ( this.strideOut > 1 ) {
3783 |
3784 | data = [];
3785 | ndx *= this.strideOut;
3786 |
3787 | for ( var i = 0; i < this.strideOut; ++i ) {
3788 |
3789 | data[ i ] = this.output[ ndx + i ];
3790 |
3791 | }
3792 |
3793 | if ( this.strideOut === 3 ) {
3794 |
3795 | switch ( type ) {
3796 |
3797 | case 'rotate':
3798 | case 'translate':
3799 |
3800 | fixCoords( data, -1 );
3801 | break;
3802 |
3803 | case 'scale':
3804 |
3805 | fixCoords( data, 1 );
3806 | break;
3807 |
3808 | }
3809 |
3810 | } else if ( this.strideOut === 4 && type === 'matrix' ) {
3811 |
3812 | fixCoords( data, -1 );
3813 |
3814 | }
3815 |
3816 | } else {
3817 |
3818 | data = this.output[ ndx ];
3819 |
3820 | }
3821 |
3822 | return data;
3823 |
3824 | };
3825 |
3826 | function Key ( time ) {
3827 |
3828 | this.targets = [];
3829 | this.time = time;
3830 |
3831 | };
3832 |
3833 | Key.prototype.addTarget = function ( fullSid, transform, member, data ) {
3834 |
3835 | this.targets.push( {
3836 | sid: fullSid,
3837 | member: member,
3838 | transform: transform,
3839 | data: data
3840 | } );
3841 |
3842 | };
3843 |
3844 | Key.prototype.apply = function ( opt_sid ) {
3845 |
3846 | for ( var i = 0; i < this.targets.length; ++i ) {
3847 |
3848 | var target = this.targets[ i ];
3849 |
3850 | if ( !opt_sid || target.sid === opt_sid ) {
3851 |
3852 | target.transform.update( target.data, target.member );
3853 |
3854 | }
3855 |
3856 | }
3857 |
3858 | };
3859 |
3860 | Key.prototype.getTarget = function ( fullSid ) {
3861 |
3862 | for ( var i = 0; i < this.targets.length; ++i ) {
3863 |
3864 | if ( this.targets[ i ].sid === fullSid ) {
3865 |
3866 | return this.targets[ i ];
3867 |
3868 | }
3869 |
3870 | }
3871 |
3872 | return null;
3873 |
3874 | };
3875 |
3876 | Key.prototype.hasTarget = function ( fullSid ) {
3877 |
3878 | for ( var i = 0; i < this.targets.length; ++i ) {
3879 |
3880 | if ( this.targets[ i ].sid === fullSid ) {
3881 |
3882 | return true;
3883 |
3884 | }
3885 |
3886 | }
3887 |
3888 | return false;
3889 |
3890 | };
3891 |
3892 | // TODO: Currently only doing linear interpolation. Should support full COLLADA spec.
3893 | Key.prototype.interpolate = function ( nextKey, time ) {
3894 |
3895 | for ( var i = 0; i < this.targets.length; ++i ) {
3896 |
3897 | var target = this.targets[ i ],
3898 | nextTarget = nextKey.getTarget( target.sid ),
3899 | data;
3900 |
3901 | if ( target.transform.type !== 'matrix' && nextTarget ) {
3902 |
3903 | var scale = ( time - this.time ) / ( nextKey.time - this.time ),
3904 | nextData = nextTarget.data,
3905 | prevData = target.data;
3906 |
3907 | // check scale error
3908 |
3909 | if ( scale < 0 || scale > 1 ) {
3910 |
3911 | console.log( "Key.interpolate: Warning! Scale out of bounds:" + scale );
3912 | scale = scale < 0 ? 0 : 1;
3913 |
3914 | }
3915 |
3916 | if ( prevData.length ) {
3917 |
3918 | data = [];
3919 |
3920 | for ( var j = 0; j < prevData.length; ++j ) {
3921 |
3922 | data[ j ] = prevData[ j ] + ( nextData[ j ] - prevData[ j ] ) * scale;
3923 |
3924 | }
3925 |
3926 | } else {
3927 |
3928 | data = prevData + ( nextData - prevData ) * scale;
3929 |
3930 | }
3931 |
3932 | } else {
3933 |
3934 | data = target.data;
3935 |
3936 | }
3937 |
3938 | target.transform.update( data, target.member );
3939 |
3940 | }
3941 |
3942 | };
3943 |
3944 | // Camera
3945 |
3946 | function Camera() {
3947 |
3948 | this.id = "";
3949 | this.name = "";
3950 | this.technique = "";
3951 |
3952 | };
3953 |
3954 | Camera.prototype.parse = function ( element ) {
3955 |
3956 | this.id = element.getAttribute( 'id' );
3957 | this.name = element.getAttribute( 'name' );
3958 |
3959 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3960 |
3961 | var child = element.childNodes[ i ];
3962 | if ( child.nodeType != 1 ) continue;
3963 |
3964 | switch ( child.nodeName ) {
3965 |
3966 | case 'optics':
3967 | this.parseOptics( child );
3968 | break;
3969 |
3970 | }
3971 |
3972 | }
3973 |
3974 | return this;
3975 |
3976 | };
3977 |
3978 | Camera.prototype.parseOptics = function ( element ) {
3979 |
3980 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3981 |
3982 | if ( element.childNodes[ i ].nodeName == 'technique_common' ) {
3983 |
3984 | var technique = element.childNodes[ i ];
3985 |
3986 | for ( var j = 0; j < technique.childNodes.length; j ++ ) {
3987 |
3988 | this.technique = technique.childNodes[ j ].nodeName;
3989 |
3990 | if ( this.technique == 'perspective' ) {
3991 |
3992 | var perspective = technique.childNodes[ j ];
3993 |
3994 | for ( var k = 0; k < perspective.childNodes.length; k ++ ) {
3995 |
3996 | var param = perspective.childNodes[ k ];
3997 |
3998 | switch ( param.nodeName ) {
3999 |
4000 | case 'yfov':
4001 | this.yfov = param.textContent;
4002 | break;
4003 | case 'xfov':
4004 | this.xfov = param.textContent;
4005 | break;
4006 | case 'znear':
4007 | this.znear = param.textContent;
4008 | break;
4009 | case 'zfar':
4010 | this.zfar = param.textContent;
4011 | break;
4012 | case 'aspect_ratio':
4013 | this.aspect_ratio = param.textContent;
4014 | break;
4015 |
4016 | }
4017 |
4018 | }
4019 |
4020 | } else if ( this.technique == 'orthographic' ) {
4021 |
4022 | var orthographic = technique.childNodes[ j ];
4023 |
4024 | for ( var k = 0; k < orthographic.childNodes.length; k ++ ) {
4025 |
4026 | var param = orthographic.childNodes[ k ];
4027 |
4028 | switch ( param.nodeName ) {
4029 |
4030 | case 'xmag':
4031 | this.xmag = param.textContent;
4032 | break;
4033 | case 'ymag':
4034 | this.ymag = param.textContent;
4035 | break;
4036 | case 'znear':
4037 | this.znear = param.textContent;
4038 | break;
4039 | case 'zfar':
4040 | this.zfar = param.textContent;
4041 | break;
4042 | case 'aspect_ratio':
4043 | this.aspect_ratio = param.textContent;
4044 | break;
4045 |
4046 | }
4047 |
4048 | }
4049 |
4050 | }
4051 |
4052 | }
4053 |
4054 | }
4055 |
4056 | }
4057 |
4058 | return this;
4059 |
4060 | };
4061 |
4062 | function InstanceCamera() {
4063 |
4064 | this.url = "";
4065 |
4066 | };
4067 |
4068 | InstanceCamera.prototype.parse = function ( element ) {
4069 |
4070 | this.url = element.getAttribute('url').replace(/^#/, '');
4071 |
4072 | return this;
4073 |
4074 | };
4075 |
4076 | // Light
4077 |
4078 | function Light() {
4079 |
4080 | this.id = "";
4081 | this.name = "";
4082 | this.technique = "";
4083 |
4084 | };
4085 |
4086 | Light.prototype.parse = function ( element ) {
4087 |
4088 | this.id = element.getAttribute( 'id' );
4089 | this.name = element.getAttribute( 'name' );
4090 |
4091 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4092 |
4093 | var child = element.childNodes[ i ];
4094 | if ( child.nodeType != 1 ) continue;
4095 |
4096 | switch ( child.nodeName ) {
4097 |
4098 | case 'technique_common':
4099 | this.parseTechnique( child );
4100 | break;
4101 |
4102 | }
4103 |
4104 | }
4105 |
4106 | return this;
4107 |
4108 | };
4109 |
4110 | Light.prototype.parseTechnique = function ( element ) {
4111 |
4112 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4113 |
4114 | var child = element.childNodes[ i ];
4115 |
4116 | switch ( child.nodeName ) {
4117 |
4118 | case 'ambient':
4119 | case 'point':
4120 | case 'directional':
4121 |
4122 | this.technique = child.nodeName;
4123 |
4124 | for ( var k = 0; k < child.childNodes.length; k ++ ) {
4125 |
4126 | var param = child.childNodes[ k ];
4127 |
4128 | switch ( param.nodeName ) {
4129 |
4130 | case 'color':
4131 | var vector = new THREE.Vector3().fromArray( _floats( param.textContent ) );
4132 | this.color = new THREE.Color().setRGB( vector.x, vector.y, vector.z );
4133 | break;
4134 |
4135 | }
4136 |
4137 | }
4138 |
4139 | break;
4140 |
4141 | }
4142 |
4143 | }
4144 |
4145 | };
4146 |
4147 | function InstanceLight() {
4148 |
4149 | this.url = "";
4150 |
4151 | };
4152 |
4153 | InstanceLight.prototype.parse = function ( element ) {
4154 |
4155 | this.url = element.getAttribute('url').replace(/^#/, '');
4156 |
4157 | return this;
4158 |
4159 | };
4160 |
4161 | function _source( element ) {
4162 |
4163 | var id = element.getAttribute( 'id' );
4164 |
4165 | if ( sources[ id ] != undefined ) {
4166 |
4167 | return sources[ id ];
4168 |
4169 | }
4170 |
4171 | sources[ id ] = ( new Source(id )).parse( element );
4172 | return sources[ id ];
4173 |
4174 | };
4175 |
4176 | function _nsResolver( nsPrefix ) {
4177 |
4178 | if ( nsPrefix == "dae" ) {
4179 |
4180 | return "http://www.collada.org/2005/11/COLLADASchema";
4181 |
4182 | }
4183 |
4184 | return null;
4185 |
4186 | };
4187 |
4188 | function _bools( str ) {
4189 |
4190 | var raw = _strings( str );
4191 | var data = [];
4192 |
4193 | for ( var i = 0, l = raw.length; i < l; i ++ ) {
4194 |
4195 | data.push( (raw[i] == 'true' || raw[i] == '1') ? true : false );
4196 |
4197 | }
4198 |
4199 | return data;
4200 |
4201 | };
4202 |
4203 | function _floats( str ) {
4204 |
4205 | var raw = _strings(str);
4206 | var data = [];
4207 |
4208 | for ( var i = 0, l = raw.length; i < l; i ++ ) {
4209 |
4210 | data.push( parseFloat( raw[ i ] ) );
4211 |
4212 | }
4213 |
4214 | return data;
4215 |
4216 | };
4217 |
4218 | function _ints( str ) {
4219 |
4220 | var raw = _strings( str );
4221 | var data = [];
4222 |
4223 | for ( var i = 0, l = raw.length; i < l; i ++ ) {
4224 |
4225 | data.push( parseInt( raw[ i ], 10 ) );
4226 |
4227 | }
4228 |
4229 | return data;
4230 |
4231 | };
4232 |
4233 | function _strings( str ) {
4234 |
4235 | return ( str.length > 0 ) ? _trimString( str ).split( /\s+/ ) : [];
4236 |
4237 | };
4238 |
4239 | function _trimString( str ) {
4240 |
4241 | return str.replace( /^\s+/, "" ).replace( /\s+$/, "" );
4242 |
4243 | };
4244 |
4245 | function _attr_as_float( element, name, defaultValue ) {
4246 |
4247 | if ( element.hasAttribute( name ) ) {
4248 |
4249 | return parseFloat( element.getAttribute( name ) );
4250 |
4251 | } else {
4252 |
4253 | return defaultValue;
4254 |
4255 | }
4256 |
4257 | };
4258 |
4259 | function _attr_as_int( element, name, defaultValue ) {
4260 |
4261 | if ( element.hasAttribute( name ) ) {
4262 |
4263 | return parseInt( element.getAttribute( name ), 10) ;
4264 |
4265 | } else {
4266 |
4267 | return defaultValue;
4268 |
4269 | }
4270 |
4271 | };
4272 |
4273 | function _attr_as_string( element, name, defaultValue ) {
4274 |
4275 | if ( element.hasAttribute( name ) ) {
4276 |
4277 | return element.getAttribute( name );
4278 |
4279 | } else {
4280 |
4281 | return defaultValue;
4282 |
4283 | }
4284 |
4285 | };
4286 |
4287 | function _format_float( f, num ) {
4288 |
4289 | if ( f === undefined ) {
4290 |
4291 | var s = '0.';
4292 |
4293 | while ( s.length < num + 2 ) {
4294 |
4295 | s += '0';
4296 |
4297 | }
4298 |
4299 | return s;
4300 |
4301 | }
4302 |
4303 | num = num || 2;
4304 |
4305 | var parts = f.toString().split( '.' );
4306 | parts[ 1 ] = parts.length > 1 ? parts[ 1 ].substr( 0, num ) : "0";
4307 |
4308 | while( parts[ 1 ].length < num ) {
4309 |
4310 | parts[ 1 ] += '0';
4311 |
4312 | }
4313 |
4314 | return parts.join( '.' );
4315 |
4316 | };
4317 |
4318 | function evaluateXPath( node, query ) {
4319 |
4320 | var instances = COLLADA.evaluate( query, node, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
4321 |
4322 | var inst = instances.iterateNext();
4323 | var result = [];
4324 |
4325 | while ( inst ) {
4326 |
4327 | result.push( inst );
4328 | inst = instances.iterateNext();
4329 |
4330 | }
4331 |
4332 | return result;
4333 |
4334 | };
4335 |
4336 | function extractDoubleSided( obj, element ) {
4337 |
4338 | obj.doubleSided = false;
4339 |
4340 | var node = COLLADA.evaluate( './/dae:extra//dae:double_sided', element, _nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
4341 |
4342 | if ( node ) {
4343 |
4344 | node = node.iterateNext();
4345 |
4346 | if ( node && parseInt( node.textContent, 10 ) === 1 ) {
4347 |
4348 | obj.doubleSided = true;
4349 |
4350 | }
4351 |
4352 | }
4353 |
4354 | };
4355 |
4356 | // Up axis conversion
4357 |
4358 | function setUpConversion() {
4359 |
4360 | if ( !options.convertUpAxis || colladaUp === options.upAxis ) {
4361 |
4362 | upConversion = null;
4363 |
4364 | } else {
4365 |
4366 | switch ( colladaUp ) {
4367 |
4368 | case 'X':
4369 |
4370 | upConversion = options.upAxis === 'Y' ? 'XtoY' : 'XtoZ';
4371 | break;
4372 |
4373 | case 'Y':
4374 |
4375 | upConversion = options.upAxis === 'X' ? 'YtoX' : 'YtoZ';
4376 | break;
4377 |
4378 | case 'Z':
4379 |
4380 | upConversion = options.upAxis === 'X' ? 'ZtoX' : 'ZtoY';
4381 | break;
4382 |
4383 | }
4384 |
4385 | }
4386 |
4387 | };
4388 |
4389 | function fixCoords( data, sign ) {
4390 |
4391 | if ( !options.convertUpAxis || colladaUp === options.upAxis ) {
4392 |
4393 | return;
4394 |
4395 | }
4396 |
4397 | switch ( upConversion ) {
4398 |
4399 | case 'XtoY':
4400 |
4401 | var tmp = data[ 0 ];
4402 | data[ 0 ] = sign * data[ 1 ];
4403 | data[ 1 ] = tmp;
4404 | break;
4405 |
4406 | case 'XtoZ':
4407 |
4408 | var tmp = data[ 2 ];
4409 | data[ 2 ] = data[ 1 ];
4410 | data[ 1 ] = data[ 0 ];
4411 | data[ 0 ] = tmp;
4412 | break;
4413 |
4414 | case 'YtoX':
4415 |
4416 | var tmp = data[ 0 ];
4417 | data[ 0 ] = data[ 1 ];
4418 | data[ 1 ] = sign * tmp;
4419 | break;
4420 |
4421 | case 'YtoZ':
4422 |
4423 | var tmp = data[ 1 ];
4424 | data[ 1 ] = sign * data[ 2 ];
4425 | data[ 2 ] = tmp;
4426 | break;
4427 |
4428 | case 'ZtoX':
4429 |
4430 | var tmp = data[ 0 ];
4431 | data[ 0 ] = data[ 1 ];
4432 | data[ 1 ] = data[ 2 ];
4433 | data[ 2 ] = tmp;
4434 | break;
4435 |
4436 | case 'ZtoY':
4437 |
4438 | var tmp = data[ 1 ];
4439 | data[ 1 ] = data[ 2 ];
4440 | data[ 2 ] = sign * tmp;
4441 | break;
4442 |
4443 | }
4444 |
4445 | };
4446 |
4447 | function getConvertedVec3( data, offset ) {
4448 |
4449 | var arr = [ data[ offset ], data[ offset + 1 ], data[ offset + 2 ] ];
4450 | fixCoords( arr, -1 );
4451 | return new THREE.Vector3( arr[ 0 ], arr[ 1 ], arr[ 2 ] );
4452 |
4453 | };
4454 |
4455 | function getConvertedMat4( data ) {
4456 |
4457 | if ( options.convertUpAxis ) {
4458 |
4459 | // First fix rotation and scale
4460 |
4461 | // Columns first
4462 | var arr = [ data[ 0 ], data[ 4 ], data[ 8 ] ];
4463 | fixCoords( arr, -1 );
4464 | data[ 0 ] = arr[ 0 ];
4465 | data[ 4 ] = arr[ 1 ];
4466 | data[ 8 ] = arr[ 2 ];
4467 | arr = [ data[ 1 ], data[ 5 ], data[ 9 ] ];
4468 | fixCoords( arr, -1 );
4469 | data[ 1 ] = arr[ 0 ];
4470 | data[ 5 ] = arr[ 1 ];
4471 | data[ 9 ] = arr[ 2 ];
4472 | arr = [ data[ 2 ], data[ 6 ], data[ 10 ] ];
4473 | fixCoords( arr, -1 );
4474 | data[ 2 ] = arr[ 0 ];
4475 | data[ 6 ] = arr[ 1 ];
4476 | data[ 10 ] = arr[ 2 ];
4477 | // Rows second
4478 | arr = [ data[ 0 ], data[ 1 ], data[ 2 ] ];
4479 | fixCoords( arr, -1 );
4480 | data[ 0 ] = arr[ 0 ];
4481 | data[ 1 ] = arr[ 1 ];
4482 | data[ 2 ] = arr[ 2 ];
4483 | arr = [ data[ 4 ], data[ 5 ], data[ 6 ] ];
4484 | fixCoords( arr, -1 );
4485 | data[ 4 ] = arr[ 0 ];
4486 | data[ 5 ] = arr[ 1 ];
4487 | data[ 6 ] = arr[ 2 ];
4488 | arr = [ data[ 8 ], data[ 9 ], data[ 10 ] ];
4489 | fixCoords( arr, -1 );
4490 | data[ 8 ] = arr[ 0 ];
4491 | data[ 9 ] = arr[ 1 ];
4492 | data[ 10 ] = arr[ 2 ];
4493 |
4494 | // Now fix translation
4495 | arr = [ data[ 3 ], data[ 7 ], data[ 11 ] ];
4496 | fixCoords( arr, -1 );
4497 | data[ 3 ] = arr[ 0 ];
4498 | data[ 7 ] = arr[ 1 ];
4499 | data[ 11 ] = arr[ 2 ];
4500 |
4501 | }
4502 |
4503 | return new THREE.Matrix4(
4504 | data[0], data[1], data[2], data[3],
4505 | data[4], data[5], data[6], data[7],
4506 | data[8], data[9], data[10], data[11],
4507 | data[12], data[13], data[14], data[15]
4508 | );
4509 |
4510 | };
4511 |
4512 | function getConvertedIndex( index ) {
4513 |
4514 | if ( index > -1 && index < 3 ) {
4515 |
4516 | var members = ['X', 'Y', 'Z'],
4517 | indices = { X: 0, Y: 1, Z: 2 };
4518 |
4519 | index = getConvertedMember( members[ index ] );
4520 | index = indices[ index ];
4521 |
4522 | }
4523 |
4524 | return index;
4525 |
4526 | };
4527 |
4528 | function getConvertedMember( member ) {
4529 |
4530 | if ( options.convertUpAxis ) {
4531 |
4532 | switch ( member ) {
4533 |
4534 | case 'X':
4535 |
4536 | switch ( upConversion ) {
4537 |
4538 | case 'XtoY':
4539 | case 'XtoZ':
4540 | case 'YtoX':
4541 |
4542 | member = 'Y';
4543 | break;
4544 |
4545 | case 'ZtoX':
4546 |
4547 | member = 'Z';
4548 | break;
4549 |
4550 | }
4551 |
4552 | break;
4553 |
4554 | case 'Y':
4555 |
4556 | switch ( upConversion ) {
4557 |
4558 | case 'XtoY':
4559 | case 'YtoX':
4560 | case 'ZtoX':
4561 |
4562 | member = 'X';
4563 | break;
4564 |
4565 | case 'XtoZ':
4566 | case 'YtoZ':
4567 | case 'ZtoY':
4568 |
4569 | member = 'Z';
4570 | break;
4571 |
4572 | }
4573 |
4574 | break;
4575 |
4576 | case 'Z':
4577 |
4578 | switch ( upConversion ) {
4579 |
4580 | case 'XtoZ':
4581 |
4582 | member = 'X';
4583 | break;
4584 |
4585 | case 'YtoZ':
4586 | case 'ZtoX':
4587 | case 'ZtoY':
4588 |
4589 | member = 'Y';
4590 | break;
4591 |
4592 | }
4593 |
4594 | break;
4595 |
4596 | }
4597 |
4598 | }
4599 |
4600 | return member;
4601 |
4602 | };
4603 |
4604 | return {
4605 |
4606 | load: load,
4607 | parse: parse,
4608 | setPreferredShading: setPreferredShading,
4609 | applySkin: applySkin,
4610 | geometries : geometries,
4611 | options: options
4612 |
4613 | };
4614 |
4615 | };
4616 |
--------------------------------------------------------------------------------