source: other-projects/nz-flag-design/trunk/render-3d/Flag_files/ColladaLoader.js@ 29721

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