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