1 /**
  2  * @fileOverview
  3  * collada.gl.enchant.js
  4  * @version v0.4.1
  5  * @require enchant.js v0.6.3+
  6  * @require gl.enchant.js v0.3.5+
  7  * @author UEI Corporation
  8  * gl-matrix.js:
  9  * https://github.com/toji/gl-matrix/
 10  */
 11 if (enchant.gl !== undefined) {
 12     enchant.Core._loadFuncs['dae'] = function(src, ext, callback, onerror) {
 13         var s = enchant.gl.Sprite3D.loadCollada(src, callback, onerror);
 14         return s;
 15     };
 16     (function() {
 17         /**
 18         */
 19         enchant.gl.Sprite3D.loadCollada = function(url, onload, onerror) {
 20             if (typeof onload !== 'function') {
 21                 return;
 22             }
 23 
 24             var rootSprite = new enchant.gl.collada.RootColladaSprite3D();
 25             rootSprite.addEventListener('load', onload);
 26             rootSprite.addEventListener('error', onerror);
 27             var e = new enchant.Event(enchant.Event.ERROR);
 28 
 29             var req = new XMLHttpRequest();
 30             req.open('GET', url, true);
 31             req.onerror = function() {
 32                 e.message = 'Cannot load an asset: ' + url;
 33                 enchant.Core.instance.dispatchEvent(e);
 34                 rootSprite.dispatchEvent(e);
 35             };
 36             req.onload = function() {
 37                 try {
 38                     var maxbonenum = 6;
 39                     var lib = {};
 40                     var collada = req.responseXML.getElementsByTagName('COLLADA')[0];
 41                     for (var i = 0, l = availableLibraryFeatures.length; i < l; i++) {
 42                         lib[availableLibraryFeatures[i].libraryName] = availableLibraryFeatures[i].loadLibraryFromXML(collada, url);
 43                     }
 44                     var scene = new Scene(collada.getElementsByTagName('scene')[0]);
 45                     var rootColladaSprite3D = new enchant.gl.collada.ColladaSprite3D(lib);
 46                     var rootColladaSkeletonSprite3D = new enchant.gl.collada.ColladaSkeletonSprite3D(lib);
 47                     if (scene.visualSceneUrl) {
 48                         var visualScene = lib['visual_scenes'][scene.visualSceneUrl];
 49                         for (var nk in visualScene.nodes) {
 50                             visualScene.nodes[nk].resolveChildNodes(lib);
 51                         }
 52                         for (var k in visualScene.nodes) {
 53                             if (visualScene.nodes[k].controllerUrl) {
 54                                 var skeletonContainer = new Node(visualScene.nodes[k].xml);
 55                                 skeletonContainer.nodes = [];
 56                                 var skin = lib['controllers'][visualScene.nodes[k].controllerUrl].skin.getProcessedSkinData();
 57                                 if (visualScene.nodes[k].skeletons.length === 0) {
 58                                     for (var sk in skin.ids) {
 59                                         visualScene.nodes[k].skeletons.push(lib['nodes'][sk]);
 60                                         break;
 61                                     }
 62                                 }
 63                                 for (var key in visualScene.nodes[k].skeletons) {
 64                                     skeletonContainer.nodes[visualScene.nodes[k].skeletons[key].id] = (visualScene.nodes[k].skeletons[key]);
 65                                 }
 66                                 var bone = new enchant.gl.collada.ColladaBone(skeletonContainer, [0, 0, 0]);
 67                                 var skeleton = new enchant.gl.collada.ColladaSkeleton();
 68                                 skeleton.addChild(bone);
 69                                 skeleton.solveFKs();
 70                                 rootColladaSkeletonSprite3D.skeleton = skeleton;
 71                                 skeleton.calculateTableForIds(skin.ids);
 72                                 rootColladaSkeletonSprite3D.addColladaSkeletonSprite3DFromNode(skeletonContainer, skin, skeleton, maxbonenum);
 73                             } else {
 74                                 rootColladaSprite3D.addColladaSprite3DFromNode(visualScene.nodes[k]);
 75                             }
 76                         }
 77                     }
 78                     rootSprite.addChild(rootColladaSprite3D);
 79                     rootSprite.addChild(rootColladaSkeletonSprite3D);
 80                     rootSprite.dispatchEvent(new enchant.Event(enchant.Event.LOAD));
 81                 } catch (err) {
 82                     e.message = err.message;
 83                     rootSprite.dispatchEvent(e);
 84                 }
 85             };
 86             req.send(null);
 87             return rootSprite;
 88         };
 89         var Unit = enchant.Class.create({
 90             initialize: function(xml) {
 91                 this.xml = xml;
 92                 this._datas = {};
 93                 this.loadParams();
 94             },
 95             loadParams: function() {
 96                 for (var i = 0, l = this._childable.length; i < l; i++) {
 97                     var nodes = [];
 98                     var param = this._childable[i];
 99                     if (this.xml !== undefined) {
100                         for (var j = 0, k = this.xml.childNodes.length; j < k; j++) {
101                             if (this.xml.childNodes[j].nodeName === param) {
102                                 nodes.push(this.xml.childNodes[j]);
103                             }
104                         }
105                     }
106                     this._datas[param] = nodes;
107                 }
108             },
109             parseFloatArray: function(element) {
110                 var array = [];
111                 var floatStrings = (element.textContent).split(/\s+/);
112                 for (var k = 0; k < floatStrings.length; k++) {
113                     var value = parseFloat(floatStrings[k]);
114                     if (!isNaN(value)) {
115                         array.push(value);
116                     }
117                 }
118                 return array;
119             },
120             getParentDirectory: function(path) {
121                 return path.substring(0, path.lastIndexOf('/') + 1);
122             },
123             getReferenceAttribute: function(element, attribute) {
124                 return element.getAttribute(attribute).replace('#', '');
125             },
126             getReferenceTextContent: function(element) {
127                 return element.textContent.replace('#', '');
128             }
129         });
130         Unit.prototype._childable = [];
131         var Scene = enchant.Class.create(Unit, {
132             initialize: function(xml) {
133                 Unit.call(this, xml);
134                 if (this._datas['instance_visual_scene']) {
135                     this.visualSceneUrl = this.getReferenceAttribute(this._datas['instance_visual_scene'][0], 'url');
136                 }
137             }
138         });
139         Scene.prototype._childable = ['instance_visual_scene'];
140         var Image = enchant.Class.create(Unit, {
141             initialize: function(xml, url) {
142                 Unit.call(this, xml);
143                 this.initFrom = '';
144                 if (this._datas['init_from']) {
145                     this.initFrom = this._datas['init_from'][0].textContent;
146                     if (this.initFrom.substr(0, 4) ==='file') {
147                         var spl=this.initFrom.split('/');
148                         this.initFrom=spl[spl.length-1];
149                     }
150                     if (this.initFrom.substr(0, 4) !== 'http') {
151                         if (this.initFrom.substr(0, 2) === './') {
152                             this.initFrom = this.initFrom.substr(2, this.initFrom.length - 2);
153                         }
154                         this.initFrom = this.getParentDirectory(url) + this.initFrom;
155                     }
156                 }
157             }
158         });
159         Image.prototype._childable = ['renderable', 'init_from', 'create_2d', 'create_3d', 'create_map'];
160         var Geometry = enchant.Class.create(Unit, {
161             initialize: function(xml) {
162                 Unit.call(this, xml);
163                 if (this._datas['mesh']) {
164                     this.Mesh = new GeometryMesh(this._datas['mesh'][0]);
165                 }
166             }
167         });
168         Geometry.prototype._childable = ['asset', 'convex_mesh', 'mesh', 'spline', 'extra'];
169         var GeometryMesh = enchant.Class.create(Unit, {
170             initialize: function(xml) {
171                 Unit.call(this, xml);
172                 this.srcs = [];
173                 this.srcs.offset = null;
174                 this.vertices = [];
175                 this.triangles = [];
176                 if (this._datas['source']) {
177                     for (var i = 0, l = this._datas['source'].length; i < l; i++) {
178                         this.srcs[this._datas['source'][i].getAttribute('id')] = this.parseFloatArray(this._datas['source'][i].getElementsByTagName('float_array')[0]);
179                     }
180                 }
181                 if (this._datas['vertices']) {
182                     this.vertices = new Vertices(this._datas['vertices'][0]);
183                 }
184                 if (this._datas['triangles'].length > 0) {
185                     this.triangles = [];
186                     for (var ti = 0; ti < this._datas['triangles'].length; ti++) {
187                         this.triangles[ti] = new Triangle(this._datas['triangles'][ti], this.srcs, this.vertices);
188                     }
189                 }
190                 if (this._datas['polylist'].length > 0) {
191                     this.triangles = [];
192                     for (var pi = 0; pi < this._datas['polylist'].length; pi++) {
193                         this.triangles[pi] = new Polylist(this._datas['polylist'][pi], this.srcs, this.vertices);
194                     }
195                 }
196             }
197         });
198         GeometryMesh.prototype._childable = ['source', 'vertices', 'lines', 'linestripes', 'polygons', 'polylist', 'triangles', 'trifans', 'tristrips', 'extra'];
199         var Vertices = enchant.Class.create(Unit, {
200             initialize: function(xml) {
201                 Unit.call(this, xml);
202                 this.source = {};
203                 for (var i = 0; i < this._datas['input'].length; i++) {
204                     var input = this._datas['input'][i];
205                     this.source[input.getAttribute('semantic')] = this.getReferenceAttribute(input, 'source');
206                 }
207                 this.id = xml.getAttribute('id');
208                 this.position = this.source['POSITION'];
209             }
210         });
211         Vertices.prototype._childable = ['input', 'extras'];
212         var AbstractGeometryMeshTriangleData = enchant.Class.create(Unit, {
213             initialize: function(xml, srcs, vertices) {
214                 Unit.call(this, xml);
215                 this.inputs = [];
216                 this.primitives = [];
217                 this.stride = 0;
218                 this.material = this.xml.getAttribute('material');
219                 if (this._datas['input']) {
220                     for (var i = 0, l = this._datas['input'].length; i < l; i++) {
221                         var sourceId = this.getReferenceAttribute(this._datas['input'][i], 'source');
222                         var offset = parseInt(this._datas['input'][i].getAttribute('offset'), 10);
223                         var set = parseInt(this._datas['input'][i].getAttribute('set'), 10);
224                         if (srcs[sourceId]) {
225                             this._addSource(srcs, sourceId, this._datas['input'][i].getAttribute('semantic'));
226                             this.inputs[this._datas['input'][i].getAttribute('semantic') + 'offset'] = offset;
227                             if (!isNaN(set)) {
228                                 this.inputs[this._datas['input'][i].getAttribute('semantic') + 'set'] = set;
229                             } else {
230                                 this.inputs[this._datas['input'][i].getAttribute('semantic') + 'set'] =0;
231                             }
232                         } else if (vertices.id === sourceId) {
233                             for (var key in vertices.source) {
234                                 if (srcs[vertices.source[key]]) {
235                                     this._addSource(srcs, vertices.source[key], key);
236                                     this.inputs[key + 'offset'] = offset;
237                                 }
238                             }
239                         }
240                         this.stride = Math.max(this.stride, (offset + 1));
241                     }
242                 }
243                 if (this._datas['p']) {
244                     if (this._datas['p'][0]) {
245                         this._calculatePrimitives(this.parseFloatArray(this._datas['p'][0]));
246                     }
247                 }
248             },
249             _calculatePrimitives: function(pointArray) {},
250             _addSource: function(sources, sourceId, inputId) {
251                 var source = sources[sourceId];
252                 this.inputs[inputId] = source;
253                 if (inputId === 'TEXCOORD') {
254                     for (var sj = 1; sj < source.length; sj += 2) {
255                         this.inputs[inputId][sj] = source[sj];
256                     }
257                 }
258             }
259         });
260         var Triangle = enchant.Class.create(AbstractGeometryMeshTriangleData, {
261             _calculatePrimitives: function(pointArray) {
262                 this.primitives = pointArray;
263             }
264         });
265         Triangle.prototype._childable = ['input', 'p'];
266         var Polylist = enchant.Class.create(AbstractGeometryMeshTriangleData, {
267             _calculatePrimitives: function(primitives) {
268                 var vcount = this.parseFloatArray(this._datas['vcount'][0]);
269                 var num = 0;
270                 var last = 0;
271                 var triangles = [];
272                 var first = true;
273                 for (var i = 0, l = primitives.length / this.stride; i < l; i++) {
274                     if (first) {
275                         for (var j = 0; j < this.stride; j++) {
276                             triangles.push(primitives[i * this.stride + j]);
277                         }
278                     } else {
279                         for (var lj = 0; lj < this.stride; lj++) {
280                             triangles.push(primitives[last * this.stride + lj]);
281                         }
282                         for (var prej = 0; prej < this.stride; prej++) {
283                             triangles.push(primitives[(i - 1) * this.stride + prej]);
284                         }
285                         for (var cj = 0; cj < this.stride; cj++) {
286                             triangles.push(primitives[i * this.stride + cj]);
287                         }
288                     }
289                     if (i - last === 2) {
290                         first = false;
291                     }
292                     if (vcount[num] - 1 === i - last) {
293                         this.primitives = this.primitives.concat(triangles);
294                         last += vcount[num];
295                         num += 1;
296                         triangles = [];
297                         first = true;
298                     }
299                 }
300             }
301         });
302         Polylist.prototype._childable = ['input', 'p', 'vcount'];
303         var VisualScene = enchant.Class.create(Unit, {
304             initialize: function(xml) {
305                 Unit.call(this, xml);
306                 this.nodes = [];
307                 for (var i = 0, l = this._datas['node'].length; i < l; i++) {
308                     this.nodes[this._datas['node'][i].getAttribute('id')] = new Node(this._datas['node'][i]);
309                 }
310             }
311         });
312         VisualScene.prototype._childable = ['asset', 'node', 'evaluate_scene', 'extra'];
313         var Node = enchant.Class.create(Unit, {
314             initialize: function(xml) {
315                 this.nodes = [];
316                 this.childNodeIds = [];
317                 this.skeletons = [];
318                 this.poses = [];
319                 this.skeletonChildNodeIds = [];
320                 this.translate = [0, 0, 0];
321                 this.rotate = [];
322                 this.nMatrix = [];
323                 Unit.call(this, xml);
324                 if (xml) {
325                     if (xml.getAttribute('sid')) {
326                         this.sid = xml.getAttribute('sid');
327                     } else {
328                         this.sid = xml.getAttribute('id');
329                     }
330                     this.id = xml.getAttribute('id');
331                     this.type = xml.getAttribute('type');
332                     for (var i = 0, l = this._datas['node'].length; i < l; i++) {
333                         this.nodes[this._datas['node'][i].getAttribute('id')] = new Node(this._datas['node'][i]);
334                     }
335                     if (this._datas['translate'].length > 0) {
336                         this.translate = this.parseFloatArray(this._datas['translate'][0]);
337                     }
338                     for (var ri = 0, rl = this._datas['rotate'].length; ri < rl; ri++) {
339                         this.rotate[this._datas['rotate'][ri].getAttribute('sid')] = this.parseFloatArray(this._datas['rotate'][ri]);
340                     }
341                     for (var mi = 0, ml = this._datas['matrix'].length; mi < ml; mi++) {
342                         this.nMatrix[this._datas['matrix'][mi].getAttribute('sid')] = mat4.transpose(this.parseFloatArray(this._datas['matrix'][0]));
343                     }
344                     var materialNode = null;
345                     if (this._datas['instance_geometry'].length > 0) {
346                         materialNode = this._datas['instance_geometry'][0];
347                         this.geometryUrl = this.getReferenceAttribute(materialNode, 'url');
348                     } else if (this._datas['instance_controller'].length > 0) {
349                         materialNode = this._datas['instance_controller'][0];
350                         this.controllerUrl = this.getReferenceAttribute(materialNode, 'url');
351                         var skels = this._datas['instance_controller'][0].getElementsByTagName('skeleton');
352                         for (i = 0, l = skels.length; i < l; i++) {
353                             this.skeletonChildNodeIds[i] = this.getReferenceTextContent(skels[i]);
354                         }
355                     }
356                     if (this._datas['instance_node']) {
357                         for (i = 0, l = this._datas['instance_node'].length; i < l; i++) {
358                             this.childNodeIds[i] = this.getReferenceAttribute(this._datas['instance_node'][i], 'url');
359                         }
360                     }
361                     if (materialNode != null) {
362                         var material = materialNode.getElementsByTagName('instance_material');
363                         if (material) {
364                             this.materialTarget = {};
365                             for (i = 0; i < material.length; i++) {
366                                 this.materialTarget[material[i].getAttribute('symbol')] = this.getReferenceAttribute(material[i], 'target');
367                             }
368                         }
369                     }
370                 }
371             },
372             resolveChildNodes: function(lib) {
373                 this.__resolveChildNodes(lib, this.childNodeIds, this.nodes);
374                 var libNodes = lib['nodes'];
375                 var libVisualScene = lib['visual_scenes'];
376                 for (var key in this.skeletonChildNodeIds) {
377                     var element = null;
378                     for (var nodeKey in libNodes) {
379                         if (libNodes[nodeKey]._getNodeInHirachy(this.skeletonChildNodeIds[key])) {
380                             element = libNodes[nodeKey];
381                         }
382                         if (element != null) {break;}
383                     }
384                     for (nodeKey in libVisualScene) {
385                         if (element != null) {break;}
386                         if (libVisualScene[nodeKey]._getNodeInHirachy(this.skeletonChildNodeIds[key])) {
387                             element = libNodes[nodeKey];
388                         }
389                     }
390                     if (element != null) {
391                         element.resolveChildNodes(lib);
392                         this.skeletons.push(element);
393                     }
394                 }
395                 for (var i = 0; i < this.skeletons.length; i++) {
396                     for (var j = i + 1; j < this.skeletons.length; j++) {
397                         if (this.skeletons[i]._getNodeInHirachy(this.skeletons[j].id)) {
398                             this.skeletons.splice(j, 1);
399                             j--;
400                         } else if (this.skeletons[j]._getNodeInHirachy(this.skeletons[i].id)) {
401                             this.skeletons.splice(i, 1);
402                             i--;
403                             break;
404                         }
405                     }
406                 }
407             },
408             __resolveChildNodes: function(lib, childNodeIds, childArray) {
409                 for (var key in childArray) {
410                     childArray[key].resolveChildNodes(lib);
411                 }
412                 var libNodes = lib['nodes'];
413                 var libVisualScene = lib['visual_scenes'];
414                 for (var i = 0; i < childNodeIds.length;) {
415                     var element = null;
416                     for (key in libNodes) {
417                         element = libNodes[key]._getNodeInHirachy(childNodeIds[i]);
418                         if (element != null) {break;}
419                     }
420                     for (key in libVisualScene) {
421                         if (element != null) {break;}
422                         var nodes = libVisualScene[key].nodes;
423                         for (var nodeKey in nodes) {
424                             element = nodes[nodeKey]._getNodeInHirachy(childNodeIds[i]);
425                             if (element != null) {break;}
426                         }
427                     }
428                     if (element != null) {
429                         childArray[element.id] = new Node(element.xml);
430                         childArray[element.id].resolveChildNodes(lib);
431                         childNodeIds.splice(i, 1);
432                     } else {
433                         i++;
434                     }
435                 }
436             },
437             _getNodeInHirachy: function(id) {
438                 if (this.id === id) {return this;}
439                 var child = null;
440                 for (var k in this.nodes) {
441                     child = this.nodes[k]._getNodeInHirachy(id);
442                     if (child != null) {break;}
443                 }
444                 return child;
445             },
446             getRotationMatrix: function() {
447                 var rotation = mat4.create();
448                 mat4.identity(rotation);
449                 for (var rotationSid in this.rotate) {
450                     var rotationVec = this.rotate[rotationSid];
451                     var mat = new enchant.gl.Quat(rotationVec[0], rotationVec[1], rotationVec[2], rotationVec[3] * Math.PI / 180);
452                     mat4.multiply(rotation, mat.toMat4(mat4.create()));
453                 }
454                 return rotation;
455             },
456             getTranslationMatrix: function() {
457                 var translation = mat4.create();
458                 mat4.identity(translation);
459                 var position = this.translate;
460                 mat4.translate(translation, [position[0], position[1], position[2]]);
461                 return translation;
462             },
463             getnMatrix: function() {
464                 var matrix = mat4.create();
465                 mat4.identity(matrix);
466                 for (var matrixSid in this.nMatrix) {
467                     mat4.multiply(matrix, this.nMatrix[matrixSid]);
468                 }
469                 return matrix;
470             },
471             getNode: function() {
472                 var table = this.nodes;
473                 var child = [];
474                 for (var key in table){
475                     child[key] = [];
476                     child[key] = table[key].getNode();
477                     for(var ckey in child[key]){
478                         table[ckey] = child[key][ckey];
479                     }
480                 }
481                 return table;
482             },
483             getAnimationMatrixFromOneAnimationNode: function(Animation, libAnimationClips, flag) {
484                 var core = enchant.Core.instance;
485                 var rotation = this.getRotationMatrix();
486                 var translation = this.getTranslationMatrix();
487                 var matrix = this.getnMatrix();
488                 var animationMatrixes = [];
489                 var sid = this.sid;
490                 animationMatrixes[sid] = [];
491                 animationMatrixes[sid][0] = mat4.multiply(translation, rotation, mat4.create());
492                 mat4.multiply(animationMatrixes[sid][0], matrix);
493                 var output = [];
494                 var input = [];
495                 var length = 0;
496                 for (var ci = 0, cl = Animation.channels.length; ci < cl; ci++) {
497                     if (this.id === Animation.channels[ci].target.split('/')[0]) {
498                         var currentLength = Animation.samplers[Animation.channels[ci].samplerId].lerpedinput.length;
499                         length = Math.max(currentLength, length);
500                         if (Animation.samplers[Animation.channels[ci].samplerId].lerpedinput.length === length) {
501                             input = Animation.samplers[Animation.channels[ci].samplerId].lerpedinput;
502                         }
503                         output[Animation.channels[ci].target.split('/')[1].split('.')[0]] = Animation.samplers[Animation.channels[ci].samplerId].lerpedoutput;
504                     }
505                 }
506                 for (var i = 0, l = length; i < l; i++) {
507                     var rot = mat4.create();
508                     var trans = mat4.create();
509                     var nMat = mat4.create();
510                     mat4.identity(rot);
511                     mat4.identity(trans);
512                     mat4.identity(nMat);
513                     mat4.translate(trans, this.translate);
514                     for (var rkey in this.rotate) {
515                         var tmpf = false;
516                         var mat;
517                         for (var okey in output) {
518                             if (rkey === okey) {
519                                 mat = new enchant.gl.Quat(this.rotate[rkey][0], this.rotate[rkey][1], this.rotate[rkey][2], output[okey][i] * Math.PI / 180);
520                                 mat4.multiply(rot, mat.toMat4(mat4.create()));
521                                 tmpf = true;
522                             }
523                         }
524                         if (!tmpf) {
525                             mat = new enchant.gl.Quat(this.rotate[rkey][0], this.rotate[rkey][1], this.rotate[rkey][2], this.rotate[rkey][3] * Math.PI / 180);
526                             mat4.multiply(rot, mat.toMat4(mat4.create()));
527                         }
528                     }
529                     for (var okey2 in output) {
530                         if (okey2 === 'translation') {
531                             mat4.identity(trans);
532                             mat4.translate(trans, [output[okey2][i * 3], output[okey2][i * 3 + 1], output[okey2][i * 3 + 2]]);
533                         } else if (okey2 === 'scale') {
534                             //TODO !
535                         } else if (okey2 === 'matrix') {
536                             var tmpMat = [];
537                             for (var j = 0; j < 16; j++) {
538                                 tmpMat.push(output[okey2][i*16+j]);
539                             }
540                             mat4.transpose(tmpMat);
541                             mat4.multiply(nMat,tmpMat);
542                         } else {
543                             for (var mkey in this.nMatrix) {
544                                 if (okey2.indexOf('(')!==-1) {
545                                     if (mkey === okey2.split('(')[0]) {
546                                         if (!isNaN(output[okey2][i])) {
547                                             nMat[parseInt(okey2.split('(')[1].split(')')[0], 10) * 4 + parseInt(okey2.split(')(')[1].split(')')[0], 10)] = output[okey2][i];
548                                         } else {
549                                             nMat[parseInt(okey2.split('(')[1].split(')')[0], 10) * 4 + parseInt(okey2.split(')(')[1].split(')')[0], 10)] = output[okey2][0];
550                                         }
551                                     }
552                                 } else {
553                                     var tmpMatrix = [];
554                                     for (var oj = 0; oj < 16; oj++) {
555                                         tmpMatrix.push(output[okey2][i * 16 + oj]);
556                                     }
557                                     mat4.transpose(tmpMatrix);
558                                     mat4.multiply(nMat, tmpMatrix);
559                                 }
560                             }
561                         }
562                     }
563                     animationMatrixes[sid][Math.round(core.fps * input[i])] = mat4.multiply(trans, rot, mat4.create());
564                     mat4.multiply(animationMatrixes[sid][Math.round(core.fps * input[i])],nMat);
565                 }
566                 if (Animation.animations.length > 0) {
567                     var child = this.getAnimationMatrixesLocal(Animation.animations, libAnimationClips, true);
568                     for (var ccl in child) {
569                         animationMatrixes[ccl] = child[ccl];
570                     }
571                 }
572                 return animationMatrixes;
573             },
574             getAnimationMatrixesLocal: function(libAnimations, libAnimationClips, flag) {
575                 var core = enchant.Core.instance;
576                 var rotation = this.getRotationMatrix();
577                 var translation = this.getTranslationMatrix();
578                 var matrix = this.getnMatrix();
579                 var animationMatrixes = [];
580                 animationMatrixes[this.sid] = [];
581                 animationMatrixes[this.sid][0] = mat4.multiply(translation, rotation, mat4.create());
582                 mat4.multiply(animationMatrixes[this.sid][0], matrix);
583                 var output = [];
584                 var input = [];
585                 var length = 0;
586                 for (var key in libAnimations) {
587                     for (var ci = 0, cl = libAnimations[key].channels.length; ci < cl; ci++) {
588                         if (this.id === libAnimations[key].channels[ci].target.split('/')[0]) {
589                             var currentLength = libAnimations[key].samplers[libAnimations[key].channels[ci].samplerId].lerpedinput.length;
590                             length = Math.max(currentLength, length);
591                             if (libAnimations[key].samplers[libAnimations[key].channels[ci].samplerId].lerpedinput.length === length) {
592                                 input = libAnimations[key].samplers[libAnimations[key].channels[ci].samplerId].lerpedinput;
593                             }
594                             output[libAnimations[key].channels[ci].target.split('/')[1].split('.')[0]] = libAnimations[key].samplers[libAnimations[key].channels[ci].samplerId].lerpedoutput;
595                         }
596                     }
597                     for (var ackey in libAnimationClips) {
598                         if (libAnimationClips[ackey].urls.indexOf(key) > -1 && flag) {
599                             length = 0;
600                         } 
601                     }
602                     if (libAnimations[key].animations.length > 0 && length > 0) {
603                         var child = this.getAnimationMatrixesLocal(libAnimations[key].animations, libAnimationClips, true);
604                         for (var ckey in child) {
605                             animationMatrixes[ckey] = child[ckey];
606                         }
607                     }
608                 }
609                 for (var i = 0, l = length; i < l; i++) {
610                     var rot = mat4.create();
611                     var trans = mat4.create();
612                     var nMat = mat4.create();
613                     mat4.identity(rot);
614                     mat4.identity(trans);
615                     mat4.identity(nMat);
616                     mat4.translate(trans, this.translate);
617                     for (var rkey in this.rotate) {
618                         var tmpf = false;
619                         var mat;
620                         for (var okey in output) {
621                             if (rkey === okey) {
622                                 mat = new enchant.gl.Quat(this.rotate[rkey][0], this.rotate[rkey][1], this.rotate[rkey][2], output[okey][i] * Math.PI / 180);
623                                 mat4.multiply(rot, mat.toMat4(mat4.create()));
624                                 tmpf = true;
625                             }
626                         }
627                         if (!tmpf) {
628                             mat = new enchant.gl.Quat(this.rotate[rkey][0], this.rotate[rkey][1], this.rotate[rkey][2], this.rotate[rkey][3] * Math.PI / 180);
629                             mat4.multiply(rot, mat.toMat4(mat4.create()));
630                         }
631                     }
632                     for (var okey2 in output) {
633                         if (okey2 === 'translation') {
634                             mat4.identity(trans);
635                             mat4.translate(trans, [output[okey2][i * 3], output[okey2][i * 3 + 1], output[okey2][i * 3 + 2]]);
636                         } else if (okey2 === 'scale') {
637                             //TODO !
638                         } else if (okey2 === 'matrix') {
639                             var tmpMat = [];
640                             for (var j = 0; j < 16; j++) {
641                                 tmpMat.push(output[okey2][i*16+j]);
642                             }
643                             mat4.transpose(tmpMat);
644                             mat4.multiply(nMat,tmpMat);
645                         } else {
646                             for (var mkey in this.nMatrix) {
647                                 if (okey2.indexOf('(')!==-1) {
648                                     if (mkey === okey2.split('(')[0]) {
649                                         if (!isNaN(output[okey2][i])) {
650                                             nMat[parseInt(okey2.split('(')[1].split(')')[0], 10) * 4 + parseInt(okey2.split(')(')[1].split(')')[0], 10)] = output[okey2][i];
651                                         } else {
652                                             nMat[parseInt(okey2.split('(')[1].split(')')[0], 10) * 4 + parseInt(okey2.split(')(')[1].split(')')[0], 10)] = output[okey2][0];
653                                         }
654                                     }
655                                 } else {
656                                     var tmpMatrix = [];
657                                     for (var oj = 0; oj < 16; oj++) {
658                                         tmpMatrix.push(output[okey2][i * 16 + oj]);
659                                     }
660                                     mat4.transpose(tmpMatrix);
661                                     mat4.multiply(nMat, tmpMatrix); 
662                                 }
663                             }
664                         }
665                     }
666                     animationMatrixes[this.sid][Math.round(core.fps * input[i])] = mat4.multiply(trans, rot, mat4.create());
667                     mat4.multiply(animationMatrixes[this.sid][Math.round(core.fps * input[i])],nMat);
668                 }
669                 for (var k in this.nodes) {
670                     var childmat = this.nodes[k].getAnimationMatrixesLocal(libAnimations, libAnimationClips, true);
671                     for (l in childmat) {
672                         animationMatrixes[l] = childmat[l];
673                     }
674                 }
675                 return animationMatrixes;
676             },
677             getAnimationMatrixesLocalFromAnimationClips: function(libAnimations, libAnimationClips) {
678                 var animationMatrixClips = [];
679                 for (var ackey in libAnimationClips) {
680                     var urls = libAnimationClips[ackey].urls;
681                     animationMatrixClips[ackey] = [];
682                     for (var ui = 0, ul = urls.length; ui < ul; ui++) {
683                         var child = [];
684                         if (libAnimations[urls[ui]].channels[0]) {
685                             child = this.getNode()[libAnimations[urls[ui]].channels[0].target.split('/')[0]].getAnimationMatrixFromOneAnimationNode(libAnimations[urls[ui]], libAnimationClips, true);
686                         }
687                         var child2 = [];
688                         if (libAnimations[urls[ui]].animations[0]) {
689                             child2 = this.getAnimationMatrixesLocal(libAnimations[urls[ui]].animations, libAnimationClips, true);
690                         }
691                         for (var l in child) {
692                             animationMatrixClips[ackey][l] = child[l];
693                         }
694                         for (l in child2) {
695                             animationMatrixClips[ackey][l] = child2[l];
696                         }
697                     }
698                 }
699                 return animationMatrixClips;
700             }
701         });
702         Node.prototype._childable = ['node', 'Lookat', 'matrix', 'rotate', 'scale', 'skew', 'translate', 'instance_camera', 'instance_controller', 'instance_geometry', 'instance_light', 'instance_node', 'extra'];
703         var Material = enchant.Class.create(Unit, {
704             initialize: function(xml) {
705                 Unit.call(this, xml);
706                 this.effectUrl = this.getReferenceAttribute(this._datas['instance_effect'][0], 'url');
707             }
708         });
709         Material.prototype._childable = ['asset', 'instance_effect', 'extra'];
710         var Animation = enchant.Class.create(Unit, {
711             initialize: function(xml) {
712                 Unit.call(this, xml);
713                 this.srcs = [];
714                 this.channels = [];
715                 this.samplers = [];
716                 this.animations = [];
717                 for (var ai = 0, al = this._datas['animation'].length; ai < al; ai++) {
718                     this.animations[ai] = new Animation(this._datas['animation'][ai]);
719                 }
720                 for (var ci = 0, cl = this._datas['channel'].length; ci < cl; ci++) {
721                     this.channels[ci]={};
722                     this.channels[ci].target = this.getReferenceAttribute(this._datas['channel'][ci], 'target');
723                     this.channels[ci].samplerId = this.getReferenceAttribute(this._datas['channel'][ci], 'source');
724                 }
725                 for (var i = 0, l = this._datas['source'].length; i < l; i++) {
726                     if (this._datas['source'][i].getElementsByTagName('float_array')[0]) {
727                         this.srcs[this._datas['source'][i].getAttribute('id')] = this.parseFloatArray(this._datas['source'][i].getElementsByTagName('float_array')[0]);
728                     }
729                 }
730                 for (var si = 0, sl = this._datas['sampler'].length; si < sl; si++) {
731                     this.samplers[this._datas['sampler'][si].getAttribute('id')] = new Sampler(this._datas['sampler'][si], this.srcs);
732                 }
733                 if (this._datas['sampler'].length > 0) {
734                     this.sampler = new Sampler(this._datas['sampler'][0], this.srcs);
735                 }
736             }
737         });
738         Animation.prototype._childable = ['asset', 'animation', 'source', 'sampler', 'channel', 'extra'];
739         var AnimationClip = enchant.Class.create(Unit, {
740            initialize: function(xml) {
741                Unit.call(this, xml);
742                this.urls = [];
743                for (var i = 0, l = this._datas['instance_animation'].length; i < l; i++) {
744                    this.urls.push(this._datas['instance_animation'][i].getAttribute('url').replace('#', ''));
745                }
746            } 
747         });
748         AnimationClip.prototype._childable = ['asset','instance_animation','instance_formula','extra'];
749         var Sampler = enchant.Class.create(Unit, {
750             initialize: function(xml, srcs) {
751                 Unit.call(this, xml);
752                 this.input = [];
753                 this.output = [];
754                 this.lerpedinput =[];
755                 this.lerpedoutput = [];
756                 for (var i = 0, l = this._datas['input'].length; i < l; i++) {
757                     if (this._datas['input'][i].getAttribute('semantic') === 'OUTPUT') {
758                         this.output = srcs[this.getReferenceAttribute(this._datas['input'][i], 'source')];
759                     }
760                     if (this._datas['input'][i].getAttribute('semantic') === 'INPUT') {
761                         this.input = srcs[this.getReferenceAttribute(this._datas['input'][i], 'source')];
762                     }
763                 }
764                 var stride = this.output.length / this.input.length;
765                 var ll = Math.floor(1 + this.input[this.input.length - 1] * enchant.Core.instance.fps);
766                 for (var li = 0; li < ll; li++) {
767                     this.lerpedinput.push(li / enchant.Core.instance.fps);
768                     for (var j = 0; j < stride; j++) {
769                         for (var post = 0, iil = this.input.length; post < iil; post++ ) {
770                             if (li / enchant.Core.instance.fps < this.input[post]) {
771                                 break;
772                             }
773                         }
774                         if (this.output[post * stride + j]) {
775                             this.lerpedoutput.push(this.output[(post - 1) * stride + j] + 1 / (this.input[post] - this.input[post - 1]) * (li / enchant.Core.instance.fps - this.input[post - 1]) * (this.output[post * stride + j] - this.output[(post - 1) * stride + j]));
776                         } else{
777                             this.lerpedoutput.push(this.output[(post - 1) * stride + j]);
778                         }
779                     }
780                 }
781             }
782         });
783         Sampler.prototype._childable = ['input'];
784         var Controller = enchant.Class.create(Unit, {
785             initialize: function(xml) {
786                 Unit.call(this, xml);
787                 for (var i = 0, l = this._datas['skin'].length; i < l; i++) {
788                     this.skin = new Skin(this._datas['skin'][i]);
789                 }
790             }
791         });
792         Controller.prototype._childable = ['asset', 'skin', 'morph', 'extra'];
793         var Skin = enchant.Class.create(Unit, {
794             initialize: function(xml) {
795                 Unit.call(this, xml);
796                 this.source = this.getReferenceAttribute(xml, 'source');
797                 this.sources = [];
798                 var child;
799                 for (var i = 0, l = this._datas['source'].length; i < l; i++) {
800                     var source = this._datas['source'][i];
801                     for (var j = 0, m = source.childNodes.length; j < m; j++) {
802                         child = source.childNodes[j];
803                         if (child.nodeName === 'Name_array') {
804                             this.sources[source.getAttribute('id')] = child.textContent.replace(/^\s+|\s+$/g, "").split(/[\s,]+/);
805                         }
806                         if (child.nodeName === 'float_array') {
807                             this.sources[source.getAttribute('id')] = this.parseFloatArray(child);
808                         }
809                     }
810                 }
811                 this.joints = {};
812                 var joints = this._datas['joints'][0];
813                 for (i = 0, l = joints.childNodes.length; i < l; i++) {
814                     child = joints.childNodes[i];
815                     if (child.nodeName === 'input') {
816                         this.joints[child.getAttribute('semantic')] = this.sources[this.getReferenceAttribute(child, 'source')];
817                     }
818                 }
819                 this.vertex_weights = [];
820                 var vweights = this._datas['vertex_weights'][0];
821                 for (i = 0, l = vweights.childNodes.length; i < l; i++) {
822                     child = vweights.childNodes[i];
823                     if (child.nodeName === 'input') {
824                         this.vertex_weights[child.getAttribute('semantic')] = this.sources[this.getReferenceAttribute(child, 'source')];
825                         this.vertex_weights[child.getAttribute('semantic') + '_offset'] = child.getAttribute('offset');
826                     }
827                     if (child.nodeName === 'vcount' || child.nodeName === 'v') {
828                         this.vertex_weights[child.nodeName] = this.parseFloatArray(child);
829                     }
830                 }
831                 this.bind_shape_matrix = mat4.identity();
832                 if (this._datas['bind_shape_matrix'].length > 0) {
833                     var bind_shape_matrix = this._datas['bind_shape_matrix'][0];
834                     this.bind_shape_matrix = mat4.transpose(this.parseFloatArray(bind_shape_matrix));
835                 }
836             },
837             getProcessedSkinData: function() {
838                 var resultSkin = {};
839                 resultSkin.bind_shape_matrix = this.bind_shape_matrix;
840                 resultSkin.joints = {};
841                 var ids = {};
842                 for (var i = 0, l = this.vertex_weights.JOINT.length; i < l; i++) {
843                     ids[this.vertex_weights.JOINT[i]] = i;
844                 }
845                 resultSkin.ids = ids;
846                 resultSkin.source = this.source;
847                 for (i = 0, l = this.joints['JOINT'].length; i < l; i++) {
848                     resultSkin.joints[this.joints['JOINT'][i]] = [];
849                     for (var j = 0; j < 16; j++) {
850                         var retu = (j - j % 4) / 4;
851                         var gyou = j % 4;
852                         resultSkin.joints[this.joints['JOINT'][i]].push(this.joints['INV_BIND_MATRIX'][i * 16 + gyou * 4 + retu]);
853                     }
854                 }
855                 resultSkin.vertex_weights = [];
856                 var last = 0;
857                 for (i = 0, l = this.vertex_weights['vcount'].length; i < l; i++) {
858                     resultSkin.vertex_weights[i] = [];
859                     for (var vj = 0, vl = this.vertex_weights['vcount'][i]; vj < vl; vj++) {
860                         var weight = this.vertex_weights['WEIGHT'][this.vertex_weights['v'][(last + vj) * 2 + 1]];
861                         resultSkin.vertex_weights[i][this.vertex_weights['JOINT'][this.vertex_weights['v'][(last + vj) * 2]]] = weight;
862                     }
863                     last += this.vertex_weights['vcount'][i];
864                 }
865                 return resultSkin;
866             }
867         });
868         Skin.prototype._childable = ['bind_shape_matrix', 'source', 'joints', 'vertex_weights', 'extra'];
869         var Effect = enchant.Class.create(Unit, {
870             getFieldFromXMLWithDefaultValue: function(defaultValue, elementName, floatArrayName) {
871                 var element = this._datas['profile_COMMON'][0].getElementsByTagName(elementName)[0];
872                 if (element) {
873                     var array = element.getElementsByTagName(floatArrayName)[0];
874                     if (array) {return this.parseFloatArray(array);}
875                 }
876                 return defaultValue;
877             },
878             initialize: function(xml) {
879                 Unit.call(this, xml);
880                 if (this._datas['profile_COMMON'][0].getElementsByTagName('newparam')[0]) {
881                     this.imageSrc = this._datas['profile_COMMON'][0].getElementsByTagName('newparam')[0].getElementsByTagName('surface')[0].getElementsByTagName('init_from')[0].textContent;
882                 }
883                 this.emission = this.getFieldFromXMLWithDefaultValue([0, 0, 0, 1], 'emission', 'color');
884                 this.ambient = this.getFieldFromXMLWithDefaultValue([1, 1, 1, 1], 'ambient', 'color');
885                 this.diffuse = this.getFieldFromXMLWithDefaultValue([1.0, 1.0, 1.0, 1], 'diffuse', 'color');
886                 this.specular = this.getFieldFromXMLWithDefaultValue([1, 1, 1, 1], 'specular', 'color');
887                 this.shininess = this.getFieldFromXMLWithDefaultValue([20], 'shininess', 'float');
888                 this.reflective = this.getFieldFromXMLWithDefaultValue([0, 0, 0, 0], 'reflective', 'color');
889                 this.reflectivity = this.getFieldFromXMLWithDefaultValue([0], 'reflectivity', 'float');
890                 this.transparent = this.getFieldFromXMLWithDefaultValue([0, 0, 0, 0], 'transparent', 'color');
891                 this.transparency = this.getFieldFromXMLWithDefaultValue(0, 'transparency', 'float');
892             }
893         });
894         Effect.prototype._childable = ['asset', 'annotate', 'image', 'newparam', 'profile_CG', 'profile_GLSL', 'profile_COMMON', 'extra'];
895 
896         /**
897          */
898         enchant.gl.collada = {};
899         /**
900          * @scope enchant.gl.collada.ColladaBone.prototype
901          */
902         enchant.gl.collada.ColladaBone = enchant.Class.create(enchant.gl.Bone, {
903             /**
904              */
905             initialize: function(node, parentpos, parentrot) {
906                 var rotation = node.getRotationMatrix();
907                 var translation = node.getTranslationMatrix();
908                 var matrix = node.getnMatrix();
909                 var animationMatrixes = [];
910                 animationMatrixes[0] = [];
911                 animationMatrixes[0][node.sid] = mat4.multiply(translation, rotation, mat4.create());
912                 mat4.multiply(animationMatrixes[0][node.sid],matrix);
913                 var pos = vec3.create([animationMatrixes[0][node.sid][12], animationMatrixes[0][node.sid][13], animationMatrixes[0][node.sid][14]]);
914                 var rotation3x3 = mat4.toMat3(animationMatrixes[0][node.sid], mat3.create());
915                 mat3.transpose(rotation3x3);
916                 var quatanion = mat3.toQuat4(rotation3x3, quat4.create());
917                 var wquatanion, local;
918                 if (parentrot) {
919                     wquatanion = quat4.multiply(parentrot, quatanion, quat4.create());
920                     local = quat4.multiplyVec3(parentrot, vec3.create(pos));
921                 } else {
922                     wquatanion = quatanion;
923                     local = vec3.create(pos);
924                 }
925                 var head = vec3.add(parentpos, local, vec3.create());
926                 enchant.gl.Bone.call(this, node.sid, head, pos, quatanion);
927                 for (var k in node.nodes) {
928                     var child = new enchant.gl.collada.ColladaBone(node.nodes[k], head, wquatanion);
929                     this.addChild(child);
930                 }
931             }
932         });
933         /**
934          * @scope enchant.gl.collada.ColladaSkeleton.prototype
935          */
936         enchant.gl.collada.ColladaSkeleton = enchant.Class.create(enchant.gl.Skeleton, {
937             /**
938              */
939             initialize: function() {
940                 enchant.gl.Skeleton.call(this);
941             },
942             calculateTableForIds: function(ids) {
943                 this.table = this._calculateFlatTableForIds(this, ids);
944             },
945             _calculateFlatTableForIds: function(skelPart, ids) {
946                 var table = {};
947                 table.pos = [];
948                 table.rot = [];
949                 for (var i = 0; i < 4; i++) {
950                     if (i < 3) {table['pos'][ids[skelPart._name] * 3 + i] = skelPart._globalpos[i];}
951                     table['rot'][ids[skelPart._name] * 4 + i] = skelPart._globalrot[i];
952                 }
953                 for (var x = 0, l = skelPart.childNodes.length; x < l; x++) {
954                     var child = this._calculateFlatTableForIds(skelPart.childNodes[x], ids);
955                     for (var key in child) {
956                         for (var k in child[key]) {
957                             table[key][k] = child[key][k];
958                         }
959                     }
960                 }
961                 return table;
962             }
963         });
964         /**
965          * @scope enchant.gl.collada.ColladaMesh.prototype
966          */
967         enchant.gl.collada.ColladaMesh = enchant.Class.create(enchant.gl.Mesh, {
968             /**
969              */
970             initialize: function(triangles) {
971                 enchant.gl.Mesh.call(this);
972                 this.parseMeshFromGeometryMesh(triangles);
973                 this.colors = [];
974                 for (var i = 0; i < (this.vertices.length / 3) * 4; i++) {
975                     this.colors[i] = 1.0;
976                 }
977             },
978             parseMeshFromGeometryMesh: function(triangles) {
979                 var inputs = triangles.inputs;
980                 this.vertices = [];
981                 this.normals = [];
982                 this.texCoords = [];
983                 this.indices = [];
984                 var index;
985                 for (var k = 0; k < triangles.primitives.length; k += triangles.stride) {
986                     if (triangles.inputs['POSITIONoffset'] >= 0) {
987                         index = triangles.primitives[k + triangles.inputs['POSITIONoffset']] * 3;
988                         this.vertices.push(inputs['POSITION'][index], inputs['POSITION'][index + 1], inputs['POSITION'][index + 2]);
989                     }
990                     if (triangles.inputs['NORMALoffset'] >= 0) {
991                         index = triangles.primitives[k + triangles.inputs['NORMALoffset']] * 3;
992                         this.normals.push(inputs['NORMAL'][index], inputs['NORMAL'][index + 1], inputs['NORMAL'][index + 2]);
993                     }
994                     if (triangles.inputs['TEXCOORDoffset'] >= 0) {
995                         index = triangles.primitives[k + triangles.inputs['TEXCOORDoffset']] * (2+triangles.inputs['TEXCOORDset']);
996                         this.texCoords.push(inputs['TEXCOORD'][index], inputs['TEXCOORD'][index + 1]);
997                     } else {
998                         this.texCoords.push(0, 0);
999                     }
1000                 }
1001                 for (k = 0; k < triangles.primitives.length / (triangles.stride); k++) {
1002                     this.indices.push(k);
1003                 }
1004             }
1005         });
1006         /**
1007          * @scope enchant.gl.collada.ColladaSkeletonSpriteMesh.prototype
1008          */
1009         enchant.gl.collada.ColladaSkeletonSpriteMesh = enchant.Class.create(enchant.gl.collada.ColladaMesh, {
1010             /**
1011              */
1012             initialize: function(triangles) {
1013                 enchant.gl.collada.ColladaMesh.call(this, triangles);
1014                 var vpos1Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
1015                 var vpos2Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
1016                 var vpos3Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
1017                 var bindicesBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.BONE_INDICES);
1018                 var weights1Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.WEIGHTS);
1019                 var weights2Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.WEIGHTS);
1020                 this._addAttribute(vpos1Buffer, 'vpos1');
1021                 this._addAttribute(vpos2Buffer, 'vpos2');
1022                 this._addAttribute(vpos3Buffer, 'vpos3');
1023                 this._addAttribute(bindicesBuffer, 'boneIndices');
1024                 this._addAttribute(weights1Buffer, 'weights1');
1025                 this._addAttribute(weights2Buffer, 'weights2');
1026             },
1027             _addAttribute: function(buffer, prop) {
1028                 this['_' + prop] = buffer;
1029                 Object.defineProperty(this, prop, {
1030                     get: function() {
1031                         return this['_' + prop]._array;
1032                     },
1033                     set: function(array) {
1034                         this['_' + prop]._array = array;
1035                         if (this._appear) {
1036                             this['_' + prop]._bufferData();
1037                         }
1038                     }
1039                 });
1040             }
1041         });
1042         /**
1043          * @scope enchant.gl.collada.AbstractColladaSprite3D.prototype
1044          */
1045         enchant.gl.collada.AbstractColladaSprite3D = enchant.Class.create(enchant.gl.Sprite3D, {
1046             /**
1047              */
1048             initialize: function(lib, node, triangles) {
1049                 enchant.gl.Sprite3D.call(this);
1050                 this.lib = lib;
1051                 if (triangles) {
1052                     this.mesh = this._getMesh(triangles);
1053                     this.initSpriteTexture(node, lib, triangles);
1054                 }
1055             },
1056             _getMesh: function(triangles) {
1057                 return null;
1058             },
1059             getPose: function(poses, length, localframe) {
1060                 var core = enchant.Core.instance;
1061                 var frame = (core.frame) % length;
1062                 if (localframe) {
1063                     frame = localframe;
1064                 }
1065                 var pose = [];
1066                 for (var k in poses) {
1067                     pose[k] = poses[k].getFrame(frame);
1068                 }
1069                 return pose;
1070             },
1071             createPoses: function(node, poses, lib) {
1072                 var matrix = node.getAnimationMatrixesLocal(lib['animations'], lib['animation_clips'], true);
1073                 var length = 0;
1074                 for (var k in matrix) {
1075                     poses[k] = new enchant.gl.KeyFrameManager();
1076                     for (var i in matrix[k]) {
1077                         var pos = vec3.create([matrix[k][i][12], matrix[k][i][13], matrix[k][i][14]]);
1078                         var rotation3x3 = mat4.toMat3(matrix[k][i], mat3.create());
1079                         mat3.transpose(rotation3x3);
1080                         var quatanion = quat4.fromRotationMatrix(rotation3x3, quat4.create());
1081                         poses[k].addFrame(new enchant.gl.Pose(pos, quatanion), parseInt(i, 10));
1082                     }
1083                     length = Math.max(poses[k].length, length);
1084                 }
1085                 return length;
1086             },
1087             createPosesClips: function(node, poseclips, lib) {
1088                 var matrixclips = node.getAnimationMatrixesLocalFromAnimationClips(lib['animations'],lib['animation_clips']);
1089                 var length = [];
1090                 var core = enchant.Core.instance;
1091                 for (var pkey in matrixclips) {
1092                     length[pkey] = 0;
1093                     var matrix = matrixclips[pkey];
1094                     poseclips[pkey] = [];
1095                     for (var mkey in matrix) {
1096                         poseclips[pkey][mkey] = new enchant.gl.KeyFrameManager();
1097                         for (var i in matrix[mkey]) {
1098                             var num = 0;
1099                             if (matrix[mkey].length > parseInt(lib['animation_clips'][pkey].start * core.fps, 10)) {
1100                                 num = i - parseInt(lib['animation_clips'][pkey].start * core.fps, 10);
1101                             } else {
1102                                 num = i;
1103                             }
1104                             var pos = vec3.create([matrix[mkey][i][12], matrix[mkey][i][13], matrix[mkey][i][14]]);
1105                             var rotation3x3 = mat4.toMat3(matrix[mkey][i], mat3.create());
1106                             mat3.transpose(rotation3x3);
1107                             var quatanion = quat4.fromRotationMatrix(rotation3x3, quat4.create());
1108                             if (num >= 0 && i <= parseInt(lib['animation_clips'][pkey].end * core.fps, 10)) {
1109                                 poseclips[pkey][mkey].addFrame(new enchant.gl.Pose(pos, quatanion), parseInt(num, 10));
1110                             }
1111                         }
1112                         length[pkey] = Math.max(poseclips[pkey][mkey].length, length[pkey]);
1113                     }
1114                 }
1115                 return length;
1116             },
1117             initSpriteTexture: function(node, lib, triangles) {
1118                 var libMaterials = lib['materials'];
1119                 var libEffects = lib['effects'];
1120                 var libImages = lib['images'];
1121                 if (node.materialTarget && this.mesh) {
1122                     var material = node.materialTarget[triangles.material];
1123                     if (material) {
1124                         var texture = this.mesh.texture;
1125                         var effect = libEffects[libMaterials[material].effectUrl];
1126                         texture.emission = effect.emission;
1127                         texture.ambient = effect.ambient;
1128                         texture.diffuse = effect.diffuse;
1129                         texture.specular = effect.specular;
1130                         texture.shininess = effect.shininess[0];
1131                         if (effect.imageSrc) {
1132                             texture.src=libImages[effect.imageSrc].initFrom;
1133                         }
1134                     }
1135                 }
1136             },
1137             _getTriangles: function(geometry, index) {
1138                 if (geometry) {
1139                     return geometry.Mesh.triangles[index];
1140                 }
1141                 return null;
1142             },
1143             _getTrianglesLength: function(geometry) {
1144                 if (geometry) {
1145                     return geometry.Mesh.triangles.length;
1146                 }
1147                 return 0;
1148             }
1149         });
1150         /**
1151          * @scope enchant.gl.collada.RootColladaSprite3D.prototype
1152          */
1153         enchant.gl.collada.RootColladaSprite3D = enchant.Class.create(enchant.gl.Sprite3D, {
1154             /**
1155             */
1156             pushAnimationClip: function(clipId){
1157                 this.childNodes[1].pushAnimationClip(clipId);
1158             },
1159             /**
1160             */
1161             clearAnimationClip: function(){
1162                 this.childNodes[1].clearAnimationClip();
1163             },
1164             getAnimationClip: function() {
1165                 return this.childNodes[1].animationClips;
1166             },
1167             loop: {
1168                 set: function(flag) {
1169                     this.childNodes[1].loop = flag;
1170                 },
1171                 get: function() {
1172                     return this.childNodes[1].loop;
1173                 }
1174             }
1175         });
1176         /**
1177          * @scope enchant.gl.collada.ColladaSprite3D.prototype
1178          */
1179         enchant.gl.collada.ColladaSprite3D = enchant.Class.create(enchant.gl.collada.AbstractColladaSprite3D, {
1180             _getMesh: function(triangles) {
1181                 return new enchant.gl.collada.ColladaMesh(triangles);
1182             },
1183             /**
1184              */
1185             addColladaSprite3DFromNode: function(node) {
1186                 var geometry = this.lib['geometries'][node.geometryUrl];
1187                 var trianglesLength = this._getTrianglesLength(geometry);
1188                 var currentTriangle = 0;
1189                 var makeEnterframe = function(poses, length, sid, obj) {
1190                     return function() {
1191                          var currentPose = obj.getPose(poses, length)[sid];
1192                          obj.rotation = quat4.toMat4(currentPose._rotation);
1193                     };
1194                 };
1195                 do {
1196                     var sprite = new enchant.gl.collada.ColladaSprite3D(this.lib, node, this._getTriangles(geometry, currentTriangle));
1197                     if (node._datas['translate'][0]) {
1198                         var translate = node.parseFloatArray(node._datas['translate'][0]);
1199                         sprite.x = translate[0];
1200                         sprite.y = translate[1];
1201                         sprite.z = translate[2];
1202                     } else {
1203                         sprite.x = sprite.y = sprite.z = 0;
1204                     }
1205                     var rotation = [];
1206                     var rotateX = [1, 0, 0];
1207                     var rotateY = [0, 1, 0];
1208                     var rotateZ = [0, 0, 1];
1209                     for (var i = 0, l = node._datas['rotate'].length; i < l; i++) {
1210                         var rotate = node._datas['rotate'][i];
1211                         var sid = rotate.getAttribute('sid');
1212                         if (sid === 'rotateZ') {
1213                             rotateZ = node.parseFloatArray(rotate);
1214                         } else if (sid === 'rotateY') {
1215                             rotateY = node.parseFloatArray(rotate);
1216                         } else if (sid === 'rotateX') {
1217                             rotateX = node.parseFloatArray(rotate);
1218                         }
1219                     }
1220                     for (i = 0; i < 3; i++) {
1221                         rotation.push(rotateX[i], rotateY[i], rotateZ[i], 0);
1222                     }
1223                     rotation.push(0, 0, 0, 1);
1224                     sprite.rotation = rotation;
1225                     if (node._datas['matrix'][0]) {
1226                         var matrix = node.parseFloatArray(node._datas['matrix'][0]);
1227                         var transposed = [matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], matrix[3], matrix[7], matrix[11], matrix[15]];
1228                         sprite.matrix = transposed;
1229                     } else {
1230                         sprite.matrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
1231                     }
1232                     if (node._datas['scale'][0]) {
1233                         var scale = node.parseFloatArray(node._datas['scale'][0]);
1234                         sprite.scaleX = scale[0];
1235                         sprite.scaleY = scale[1];
1236                         sprite.scaleZ = scale[2];
1237                     } else {
1238                         sprite.scaleX = sprite.scaleY = sprite.scaleZ = 1;
1239                     }
1240                     if (node.nodes) {
1241                         for (var k in node.nodes) {
1242                             sprite.addColladaSprite3DFromNode(node.nodes[k]);
1243                         }
1244                     }
1245                     var poses = [];
1246                     var poselength = this.createPoses(node, poses, this.lib);
1247                     if (poselength > 0) {
1248                         sprite.addEventListener('enterframe', makeEnterframe(poses, poselength, node.sid, sprite));
1249                     }
1250                     //var poselength = this.createPoses(node, poses, this.lib);
1251                     //if (poselength > 0) {
1252                         //sprite.addEventListener('enterframe', function() {
1253                             //var currentPose = this.getPose(poses, poselength)[node.sid];
1254 
1255                             // TODO : USE CURRENT POSE TO MODIFY SPRITE ROTATION / TRANSLATION
1256                             //var mat = new Quat();
1257                             //mat._quat = currentPose._rotation;
1258                             //console.log(currentPose._rotation);
1259                             //sprite.rotationApply(mat);
1260                             //                          var glMat = mat4.create();
1261                             //                          mat.toMat4(glMat);
1262                             //                          mat4.multiply(sprite._rotation, glMat);
1263                             //mat4.rotateX(sprite._rotation, currentPose._rotation[2]);
1264                             //mat4.rotateY(sprite._rotation, currentPose._rotation[1]);
1265                             //mat4.rotateZ(sprite._rotation, currentPose._rotation[0]);
1266                             //sprite._changedRotation = true;
1267                             //sprite.translate(currentPose._position[2],currentPose._position[1],currentPose._position[0]);
1268                         //});
1269                     //}
1270                     this.addChild(sprite);
1271                     currentTriangle++;
1272                 } while (currentTriangle < trianglesLength);
1273             }
1274         });
1275         /**
1276          * @scope enchant.gl.collada.ColladaSprite3D.prototype
1277          */
1278         enchant.gl.collada.ColladaSkeletonSprite3D = enchant.Class.create(enchant.gl.collada.ColladaSprite3D, {
1279             /**
1280              */
1281             initialize: function(lib, node, triangles) {
1282                 enchant.gl.collada.AbstractColladaSprite3D.call(this, lib, node, triangles);
1283                 this.program = enchant.gl.collada.COLLADA_SHADER_PROGRAM;
1284                 this.animation = [];
1285                 this.defaultAnimation = function(){
1286                 };
1287                 this.animationClips = [];
1288                 this.uMVMatrix = mat4.create();
1289                 this.uNMatrix = mat3.create();
1290                 this.applyAnimationChild = function() {
1291                     for (var cni = 0, cnl = this.childNodes.length; cni < cnl; cni++) {
1292                         this.childNodes[cni].defaultAnimation(this.childNodes[cni]);
1293                         this.childNodes[cni].applyAnimationChild();
1294                     }
1295                 };
1296                 this.addEventListener("enterframe", function() {
1297                     this.applyAnimationChild();
1298                     if (this.animation.length === 0) {
1299                     } else {
1300                         var first = this.animation[0];
1301                         first.frame++;
1302                         for(var i = 0, l = this.childNodes.length; i < l; i++) {
1303                             first.animation.enterframe(this.childNodes[i], first.frame);
1304                         }
1305                         if (first.frame >= this.animation[0].animation.length) {
1306                             first = this.animation.shift();
1307                             if (this.loop) {
1308                                 first.frame = 0;
1309                                 this.animation.push(first);
1310                             }
1311                         }
1312                     }
1313                 });
1314             },
1315             pushAnimationClip: function(clipId) {
1316                 if(this.animationClips[clipId]){
1317                     this.animation.push({animation: this.animationClips[clipId], frame: 0});
1318                 }
1319             },
1320             clearAnimationClip: function() {
1321                 this.animation = [];
1322             },
1323             _getMesh: function(triangles) {
1324                 return new enchant.gl.collada.ColladaSkeletonSpriteMesh(triangles);
1325             },
1326             /**
1327              */
1328             addColladaSkeletonSprite3DFromNode: function(node, skin, skeleton, maxbonenum) {
1329                 var controller = this.lib['controllers'][node.controllerUrl];
1330                 var geometry = this.lib['geometries'][controller.skin.source];
1331                 var trianglesLength = this._getTrianglesLength(geometry);
1332                 var currentTriangle = 0;
1333                 var makeEnterframe = function(poses, length, skin, maxbonem) {
1334                     return function(obj) {
1335                         skeleton.setPoses(obj.getPose(poses, length));
1336                         skeleton.solveFKs();
1337                         skeleton.calculateTableForIds(skin.ids);
1338                         obj.mesh.udBoneInfo = obj.calculateSkeletonTable(obj.divisioninfo.dividedIndices, skeleton.table, maxbonenum);
1339                     };
1340                 };
1341                 var makeClipEnterframe = function(poses, length, skin, maxbonem, clipId) {
1342                     return function(obj, frame) {
1343                         skeleton.setPoses(obj.getPose(poses, length, frame));
1344                         skeleton.solveFKs();
1345                         skeleton.calculateTableForIds(skin.ids);
1346                         obj.mesh.udBoneInfo = obj.calculateSkeletonTable(obj.divisioninfo.dividedIndices, skeleton.table, maxbonenum);
1347                     };
1348                 };
1349                 do {
1350                     var triangles = this._getTriangles(geometry, currentTriangle);
1351                     var child = new enchant.gl.collada.ColladaSkeletonSprite3D(this.lib, node, triangles);
1352                     var arrays = this.createStaticArrayForShader(triangles, skin, skeleton);
1353                     child.divisioninfo = this.getDivisionInfo(arrays, skeleton.table, maxbonenum);
1354                     this.addChild(child);
1355 
1356                     child.mesh.vpos1 = arrays.vectorFromBone1;
1357                     child.mesh.vpos2 = arrays.vectorFromBone2;
1358                     child.mesh.vpos3 = arrays.vectorFromBone3;
1359 
1360                     child.mesh.weights1 = arrays.weights1;
1361                     child.mesh.weights2 = arrays.weights2;
1362 
1363                     child.mesh.dividedpoints = child.divisioninfo.dividedPoint;
1364                     child.mesh.boneIndices = child.divisioninfo.boneIndices;
1365                     child.mesh.udBoneInfo = child.divisioninfo.skeletontable;
1366                     var poses = [];
1367                     var length = this.createPoses(node, poses, this.lib);
1368                     var posesclips = [];
1369                     var cliplength = this.createPosesClips(node, posesclips, this.lib);
1370                     for (var clk in cliplength) {
1371                         if (cliplength[clk] > 0) {
1372                             var clipenterframe = makeClipEnterframe(posesclips[clk], cliplength[clk], skin, maxbonenum, clk);
1373                             this.animationClips[clk] = {enterframe: clipenterframe, length: cliplength[clk]};
1374                         }
1375                     }
1376                     if (length > 0) {
1377                         child.defaultAnimation = makeEnterframe(poses, length, skin, maxbonenum);
1378                     }
1379                     currentTriangle++;
1380                 } while (currentTriangle < trianglesLength);
1381             },
1382             calculateSkeletonTable: function(dividedIndices, table, n) {
1383                 var skeletontable = [];
1384                 var indices, index, postable, rottable;
1385                 for (var i = 0, l = dividedIndices.length; i < l; i++) {
1386                     indices = dividedIndices[i];
1387                     postable = [];
1388                     rottable = [];
1389                     for (var j = 0, ll = indices.length; j < ll; j++) {
1390                         index = indices[j];
1391                         postable.push(
1392                             table.pos[index * 3],
1393                             table.pos[index * 3 + 1],
1394                             table.pos[index * 3 + 2]
1395                         );
1396                         rottable.push(
1397                             table.rot[index * 4],
1398                             table.rot[index * 4 + 1],
1399                             table.rot[index * 4 + 2],
1400                             table.rot[index * 4 + 3]
1401                         );
1402                     }
1403                     skeletontable.push({
1404                         pos: new Float32Array(postable),
1405                         rot: new Float32Array(rottable)
1406                     });
1407                 }
1408                 return skeletontable;
1409             },
1410             /**
1411              * スキニングの分割描画を行う境界を計算する.
1412              *
1413              */
1414             getDivisionInfo: function(arrays, table, n) {
1415                 var dividedPoint = [0];
1416                 var dividedIndices = [];
1417                 var indices = [];
1418                 var packedIndices = [];
1419                 var count = 0;
1420                 var index, packedIndex, num;
1421                 for (var i = 0, l = arrays.boneIndices.length; i < l; i += 9) {
1422                     for (var j = 0; j < 9; j++) {
1423                         index = arrays.boneIndices[i + j];
1424                         num = indices.indexOf(index);
1425                         if (num === -1) {
1426                             indices.push(index);
1427                             packedIndex = indices.length - 1;
1428                         } else {
1429                             packedIndex = num;
1430                         }
1431                         packedIndices.push(packedIndex);
1432                         if (j === 8) {
1433                             if (indices.length > n) {
1434                                 dividedPoint.push(i + 9);
1435                                 dividedIndices.push(indices);
1436                                 count++;
1437                                 indices = [];
1438                             }
1439                         }
1440                     }
1441                 }
1442                 dividedPoint.push(packedIndices.length);
1443                 dividedIndices.push(indices);
1444                 return {
1445                     dividedPoint: dividedPoint,
1446                     dividedIndices: dividedIndices,
1447                     skeletontable: this.calculateSkeletonTable(dividedIndices, table, n),
1448                     boneIndices: new Uint16Array(packedIndices)
1449                 };
1450             },
1451             createStaticArrayForShader: function(triangles, skin, skeleton) {
1452                 var arraysForShader = {};
1453                 var length = 0;
1454                 var vectorForBones = [
1455                     [],
1456                     [],
1457                     []
1458                 ];
1459                 var weights = [
1460                     [],
1461                     []
1462                 ];
1463                 var boneIndices = [];
1464                 var keys = [];
1465                 var index, vec, rvec;
1466                 rvec = vec3.create();
1467                 for (var i = 0, l = triangles.primitives.length; i < l; i += triangles.stride) {
1468                     if (triangles.inputs['POSITIONoffset'] >= 0) {
1469                         length++;
1470                         index = triangles.primitives[i + triangles.inputs['POSITIONoffset']];
1471                         vec = [
1472                             triangles.inputs['POSITION'][index * 3],
1473                             triangles.inputs['POSITION'][index * 3 + 1],
1474                             triangles.inputs['POSITION'][index * 3 + 2]
1475                         ];
1476                         mat4.multiplyVec3(skin.bind_shape_matrix, vec);
1477                         var count = -1;
1478                         keys.push(skin.vertex_weights[index]);
1479                         for (var key in skin.vertex_weights[index]) {
1480                             count++;
1481                             mat4.multiplyVec3(skin.joints[key], vec, rvec);
1482                             vectorForBones[count].push(rvec[0], rvec[1], rvec[2]);
1483                             boneIndices.push(skin.ids[key]);
1484                             if (count < 2) {
1485                                 weights[count].push(skin.vertex_weights[index][key]);
1486                             } else {
1487                                 break;
1488                             }
1489                         }
1490                         for (var j = count + 1; j < 3; j++) {
1491                             if (j < 2) {
1492                                 weights[j].push(0);
1493                             }
1494                             vectorForBones[j].push(0, 0, 0);
1495                             boneIndices.push(0);
1496                         }
1497                     }
1498                 }
1499                 for (i = 0; i < 3; i++) {
1500                     arraysForShader['vectorFromBone' + (i + 1)] = new Float32Array(vectorForBones[i]);
1501                     if (i < 2) {arraysForShader['weights' + (i + 1)] = new Float32Array(weights[i]);}
1502                 }
1503                 arraysForShader.boneIndices = new Uint16Array(boneIndices);
1504                 arraysForShader.keys = keys;
1505                 return arraysForShader;
1506             },
1507             _render: function(detectTouch) {
1508                 var core = enchant.Core.instance;
1509                 var scene = core.currentScene3D;
1510                 var l = scene.directionalLight;
1511                 var detect = (detectTouch === 'detect') ? 1.0 : 0.0;
1512                 mat4.multiply(scene._camera.mat, this.tmpMat, this.uMVMatrix);
1513                 mat4.toInverseMat3(this.tmpMat, this.uNMatrix);
1514                 mat3.transpose(this.uNMatrix);
1515                 core.GL.currentProgram.setAttributes({
1516                     aVertexPosition: this.mesh._vertices,
1517                     aVertexNormal: this.mesh._normals,
1518                     aTextureCoord: this.mesh._texCoords,
1519                     aBoneIndices: this.mesh._boneIndices,
1520                     aVectorFromBone1: this.mesh._vpos1,
1521                     aVectorFromBone2: this.mesh._vpos2,
1522                     aVectorFromBone3: this.mesh._vpos3,
1523                     aBoneWeight1: this.mesh._weights1,
1524                     aBoneWeight2: this.mesh._weights2
1525                 });
1526                 core.GL.currentProgram.setUniforms({
1527                     uUseDirectionalLight: scene.useDirectionalLight,
1528                     uLightColor: l.color,
1529                     uDetectTouch: detect,
1530                     uAmbientLightColor: scene.ambientLight.color,
1531                     uPMatrix: scene._camera.projMat,
1532                     uMVMatrix: this.uMVMatrix,
1533                     uNMatrix: this.uNMatrix,
1534                     uLightDirection: [
1535                         l.directionX, l.directionY, l.directionZ
1536                     ],
1537                     uLookVec: [
1538                         scene._camera._centerX - scene._camera._x,
1539                         scene._camera._centerY - scene._camera._y,
1540                         scene._camera._centerZ - scene._camera._z
1541                     ]
1542                 });
1543                 var u = {
1544                     uDetectColor: this.detectColor,
1545                     uSpecular: this.mesh.texture.specular,
1546                     uDiffuse: this.mesh.texture.diffuse,
1547                     uEmission: this.mesh.texture.emission,
1548                     uAmbient: this.mesh.texture.ambient,
1549                     uShininess: this.mesh.texture.shininess
1550                 };
1551 
1552                 if (this.mesh.texture._image) {
1553                     u.uUseTexture = 1;
1554                     u.uSampler = this.mesh.texture;
1555                 } else {
1556                     u.uUseTexture = 0;
1557                     u.uSampler = 0;
1558                 }
1559                 core.GL.currentProgram.setUniforms(u);
1560                 for (var i = 0; i < this.mesh.dividedpoints.length - 1; i++) {
1561                     core.GL.currentProgram.setUniforms({
1562                         uBonePos: this.mesh.udBoneInfo[i]['pos'],
1563                         uBoneRot: this.mesh.udBoneInfo[i]['rot']
1564                     });
1565                     enchant.Core.instance.GL.renderElements(this.mesh._indices, this.mesh.dividedpoints[i] / 3 * 2, this.mesh.dividedpoints[i + 1] / 3 - this.mesh.dividedpoints[i] / 3);
1566                 }
1567             }
1568         });
1569         var bufferProto = Object.getPrototypeOf(enchant.gl.Buffer);
1570         bufferProto.MORPHS = bufferProto.NORMALS;
1571         bufferProto.QUATS = bufferProto.COLORS;
1572         bufferProto.BONE_INDICES = {
1573             size: 3,
1574             type: 5123,
1575             normed: false,
1576             stride: 0,
1577             offset: 0,
1578             btype: 34962,
1579             usage: 35044,
1580             Atype: Uint16Array
1581         };
1582         bufferProto.WEIGHTS = {
1583             size: 1,
1584             type: 5126,
1585             norm: false,
1586             stride: 0,
1587             offset: 0,
1588             btype: 34962,
1589             usage: 35044,
1590             Atype: Float32Array
1591         };
1592         var COLLADA_VERTEX_SHADER_SOURCE = '\n\
1593             uniform mat4 uMVMatrix;\n\
1594             uniform mat4 uPMatrix;\n\
1595             uniform mat3 uNMatrix;\n\
1596             \n\
1597             uniform vec3 uBonePos[55];\n\
1598             uniform vec4 uBoneRot[55];\n\
1599             \n\
1600             attribute vec3 aBoneIndices;\n\
1601             attribute vec3 aVertexNormal;\n\
1602             attribute vec2 aTextureCoord;\n\
1603             \n\
1604             attribute float aBoneWeight1;\n\
1605             attribute float aBoneWeight2;\n\
1606             attribute vec3 aVectorFromBone1;\n\
1607             attribute vec3 aVectorFromBone2;\n\
1608             attribute vec3 aVectorFromBone3;\n\
1609             \n\
1610             varying vec3 vNormal;\n\
1611             varying vec4 vColor;\n\
1612             varying vec2 vTextureCoord;\n\
1613             \n\
1614             \n\
1615             vec3 qtransform(vec4 q, vec3 v) {\n\
1616                 return v + 2.0 * cross(cross(v, q.xyz) - q.w*v, q.xyz);\n\
1617             }\n\
1618             \n\
1619             void main() {\n\
1620                 int  index[3];\n\
1621                 index[0] = int(aBoneIndices.x);\n\
1622                 index[1] = int(aBoneIndices.y);\n\
1623                 index[2] = int(aBoneIndices.z);\n\
1624                 \n\
1625                 float w3 = 1.0 - aBoneWeight1 - aBoneWeight2;\n\
1626                 \n\
1627                 vec3 position = (qtransform(uBoneRot[index[0]], aVectorFromBone1) + uBonePos[index[0]]) * aBoneWeight1\n\
1628                         + (qtransform(uBoneRot[index[1]], aVectorFromBone2) + uBonePos[index[1]]) * aBoneWeight2\n\
1629                         + (qtransform(uBoneRot[index[2]], aVectorFromBone3) + uBonePos[index[2]]) * w3;\n\
1630                 vec3 normal = qtransform(uBoneRot[index[0]], aVertexNormal) * aBoneWeight1\n\
1631                         + qtransform(uBoneRot[index[1]], aVertexNormal) * aBoneWeight2\n\
1632                         + qtransform(uBoneRot[index[2]], aVertexNormal) * w3;\n\
1633                 \n\
1634                 gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);\n\
1635                 vColor = vec4(1,1,1,1);\n\
1636                 vTextureCoord = aTextureCoord;\n\
1637                 vNormal = normalize(uNMatrix * normal);\n\
1638                 vNormal = normalize(uNMatrix * aVertexNormal);\n\
1639             }\n\
1640             ';
1641 
1642         enchant.gl.Core.prototype._original_start = enchant.gl.Core.prototype.start;
1643         enchant.gl.Core.prototype.start = function() {
1644             enchant.gl.collada.COLLADA_SHADER_PROGRAM = new enchant.gl.Shader(COLLADA_VERTEX_SHADER_SOURCE, enchant.Core.instance.GL.defaultProgram._fShaderSource);
1645             this._original_start();
1646         };
1647         var ColladaLibraryLoader = enchant.Class.create({
1648             initialize: function(libraryName, libraryPropertyName, className) {
1649                 this.libraryName = libraryName;
1650                 this.libraryPropertyName = libraryPropertyName;
1651                 this.className = className;
1652                 this.library = {};
1653             },
1654             loadLibraryFromXML: function(colladaRootElement, url) {
1655                 var libraries = colladaRootElement.getElementsByTagName('library_' + this.libraryName);
1656                 this.library = {};
1657                 var props = [];
1658                 if (libraries.length > 0) {
1659                     for (var ci = 0, cl = libraries[0].childNodes.length; ci < cl; ci++) {
1660                         if (libraries[0].childNodes[ci].nodeName === this.libraryPropertyName) {
1661                             props.push(libraries[0].childNodes[ci]);
1662                         }
1663                     }
1664                 }
1665                 var childNodes=colladaRootElement.childNodes;
1666                 if (this.libraryPropertyName === "node") {
1667                     props = colladaRootElement.getElementsByTagName(this.libraryPropertyName);
1668                 }
1669                 for (var i = 0, l = props.length; i < l; i++) {
1670                     var child = props[i];
1671                     this.library[child.getAttribute('id')] = new this.className(child, url);
1672                     if (this.libraryPropertyName === "animation_clip") {
1673                         this.library[child.getAttribute('id')].start=child.getAttribute('start');
1674                         this.library[child.getAttribute('id')].end=child.getAttribute('end');
1675                     }
1676                 }
1677                 return this.library;
1678             }
1679         });
1680         var availableLibraryFeatures = [new ColladaLibraryLoader('images', 'image', Image), new ColladaLibraryLoader('geometries', 'geometry', Geometry), new ColladaLibraryLoader('nodes', 'node', Node), new ColladaLibraryLoader('visual_scenes', 'visual_scene', VisualScene), new ColladaLibraryLoader('materials', 'material', Material), new ColladaLibraryLoader('effects', 'effect', Effect), new ColladaLibraryLoader('controllers', 'controller', Controller), new ColladaLibraryLoader('animations', 'animation', Animation), new ColladaLibraryLoader('animation_clips', 'animation_clip', AnimationClip)];
1681     }());
1682 }
1683