1 /**
  2  * @fileOverview
  3  * mmd.gl.enchant.js
  4  * @version 0.2.2
  5  * @require enchant.js v0.6.3+
  6  * @require gl.enchant.js v0.3.7+
  7  * @author UEI Corporation
  8  *
  9  * @description
 10  * Plugin to allow use of MikuMikuDance PMD and VMD files in gl.enchant.js.
 11  *
 12  * @detail
 13  * MMD.js' MMD.Model and MMD.Motion are used in file loading and parse.
 14  * Shader source is quoted from MMD.VertexShaderSource and MMD.FragmentShaderSource.
 15  *
 16  * MMD.js:
 17  * https://github.com/edvakf/MMD.js
 18  * About MMD.js:
 19  * http://edv.sakura.ne.jp/mmd/
 20  */
 21 
 22 // for MMD.js
 23 var MMD = {};
 24 
 25 (function() {
 26 
 27     var splitPath = function(path) {
 28         var split = path.match(/(.{0,})\/([^\/\s]{1,}\.pmd)/);
 29         if (split == null) {
 30             split = [ '.' + path, '.', path ];
 31         }
 32         return split;
 33     };
 34 
 35     /**
 36      * @type {Object}
 37      */
 38     enchant.gl.mmd = {};
 39 
 40     enchant.Core._loadFuncs['pmd'] = function(src, ext, callback, onerror) {
 41         return new enchant.gl.mmd.MSprite3D(src, callback, onerror);
 42     };
 43 
 44     enchant.Core._loadFuncs['vmd'] = function(src, ext, callback, onerror) {
 45         return new enchant.gl.mmd.MAnimation(src, callback, onerror);
 46     };
 47 
 48     /**
 49      * @scope enchant.gl.mmd.MMesh.prototype
 50      */
 51     enchant.gl.mmd.MMesh = enchant.Class.create(enchant.gl.Mesh, {
 52         /**
 53          * MSprite3D mesh object.
 54          * @constructs
 55          * @extends enchant.gl.Mesh
 56          */
 57         initialize: function() {
 58             enchant.gl.Mesh.call(this);
 59             var vpos1Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
 60             var vpos2Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
 61             var bone1posBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
 62             var bone2posBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
 63             var quats1Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.QUATS);
 64             var quats2Buffer = new enchant.gl.Buffer(enchant.gl.Buffer.QUATS);
 65             var morphsBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.MORPHS);
 66             var weightsBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.WEIGHTS);
 67             var edgesBuffer = new enchant.gl.Buffer(enchant.gl.Buffer.EDGES);
 68             this._addAttribute(vpos1Buffer, 'vpos1');
 69             this._addAttribute(vpos2Buffer, 'vpos2');
 70             this._addAttribute(bone1posBuffer, 'bone1pos');
 71             this._addAttribute(bone2posBuffer, 'bone2pos');
 72             this._addAttribute(quats1Buffer, 'quats1');
 73             this._addAttribute(quats2Buffer, 'quats2');
 74             this._addAttribute(morphsBuffer, 'morphs');
 75             this._addAttribute(weightsBuffer, 'weights');
 76             this._addAttribute(edgesBuffer, 'edges');
 77         },
 78         _addAttribute: function(buffer, prop) {
 79             this['_' + prop] = buffer;
 80             Object.defineProperty(this, prop, {
 81                 get: function() {
 82                     return this['_' + prop]._array;
 83                 },
 84                 set: function(array) {
 85                     this['_' + prop]._array = array;
 86                     if (this._appear) {
 87                         this['_' + prop]._bufferData();
 88                     }
 89                 }
 90             });
 91         }
 92     });
 93 
 94     enchant.gl.mmd.MBone = enchant.Class.create(enchant.gl.Bone, {
 95         initialize: function(param) {
 96             var pos = vec3.create();
 97             var rot = quat4.identity();
 98             enchant.gl.Bone.call(this, param.name, param.head_pos, pos, rot);
 99         },
100         _applyPose: function() {
101             var parent = this.parentNode;
102             var local = vec3.create();
103             vec3.subtract(this._origin, parent._origin, local);
104             vec3.add(local, this._position);
105             quat4.multiply(parent._globalrot, this._rotation, this._globalrot);
106             quat4.multiplyVec3(parent._globalrot, local, this._globalpos);
107             vec3.add(this._globalpos, parent._globalpos);
108         }
109     });
110 
111     enchant.gl.mmd.MSkeleton = enchant.Class.create(enchant.gl.Skeleton, {
112         initialize: function(bones) {
113             enchant.gl.Skeleton.call(this);
114             this.table = [];
115             if (bones) {
116                 this.load(bones);
117             }
118         },
119         load: function(bones) {
120             var bone;
121             for (var i = 0, l = bones.length; i < l; i++) {
122                 bone = bones[i];
123                 this._add(bone);
124             }
125         },
126         _add: function(param) {
127             var bone = new enchant.gl.mmd.MBone(param);
128             this.table.push(bone);
129             if (param.parent_bone_index === 0xFFFF) {
130                 this.addChild(bone);
131             } else {
132                 this.table[param.parent_bone_index].addChild(bone);
133             }
134             if (param.name.match(/ひざ/)) {
135                 bone.constraint = function(q) {
136                     return quat4.set([ Math.sqrt(1 - q[3] * q[3]), 0, 0, q[3] ], q);
137                 };
138             }
139         },
140         _addIK: function(data) {
141             var bones = [];
142             var effector = this.table[data.bone_index];
143             var target = this.table[data.target_bone_index];
144             for (var i = 0, l = data.child_bones.length; i < l; i++) {
145                 bones[i] = this.table[data.child_bones[i]];
146             }
147             var maxangle = data.control_weight * 4;
148             var iteration = data.iterations;
149             this.addIKControl(effector, target, bones, maxangle, iteration);
150         }
151     });
152 
153     /**
154      * @scope enchant.gl.mmd.MSprite3D.prototype
155      */
156     enchant.gl.mmd.MSprite3D = enchant.Class.create(enchant.gl.Sprite3D, {
157         /**
158          * Sprite3D optimized for PMD files.
159          * By preloading PMD file, it will be set in assets automatically.
160          * @param {String} [path] file path.
161          * @param {Function} [callback] on load callback.
162          * @param {Function} [onerror] on error callback.
163          * @constructs
164          * @extends enchant.gl.Sprite3D
165          */
166         initialize: function(path, callback, onerror) {
167             enchant.gl.Sprite3D.call(this);
168             this.program = enchant.gl.mmd.MMD_SHADER_PROGRAM;
169             this.animation = [];
170             this.uMVMatrix = mat4.create();
171             this.uNMatrix = mat4.create();
172 
173             this.addEventListener('enterframe', function() {
174                 var first;
175                 var skeleton = this.skeleton;
176                 var morph = this.morph;
177                 if (this.animation.length === 0) {
178                 } else {
179                     first = this.animation[0];
180 
181                     var data = first.animation._tick(first.frame);
182                     first.frame++;
183 
184                     this._skinning(data.poses);
185 
186                     this._morphing(data.morphs);
187 
188                     if (first.frame > first.animation.length) {
189                         first = this.animation.shift();
190                         if (this.loop) {
191                             first.frame = 0;
192                             this.animation.push(first);
193                         }
194                     }
195                 }
196             });
197             if (arguments.length >= 2) {
198                 this.loadPmd(path, callback, onerror);
199             }
200         },
201         /**
202          * Add animation.
203          * Animation will be played in the order that it is added.
204          * @param {enchant.gl.mmd.MAnimation} animation
205          */
206         pushAnimation: function(animation) {
207             this.animation.push({ frame: 0, animation: animation });
208         },
209         /**
210          * Delete added animation.
211          */
212         clearAnimation: function(animation) {
213             this.animation = [];
214         },
215         _skinning: function(poses) {
216             var skeleton = this.skeleton;
217             skeleton.setPoses(poses);
218             skeleton.solveFKs();
219             skeleton.solveIKs();
220             this._applySkeleton();
221 
222         },
223         _morphing: function(morphs) {
224             var target = this.mesh.morphs;
225             for (var i = 0, l = target.length; i < l; i++) {
226                 target[i] = 0;
227             }
228             this.morph.morphing(morphs, target);
229             this.mesh._morphs._bufferDataFast();
230         },
231         _render: function() {
232             var core = enchant.Core.instance;
233             var scene = core.currentScene3D;
234             var light = scene.directionalLight;
235             var lvec = [ light._directionX, light._directionY, light._directionZ ];
236             var uMVMatrix = mat4.identity(this.uMVMatrix);
237             mat4.multiply(scene._camera.mat, this.tmpMat, uMVMatrix);
238             var uNMatrix = mat4.identity(this.uNMatrix);
239             mat4.transpose(mat4.inverse(uMVMatrix, uNMatrix));
240             var uLightDirection = vec3.normalize(lvec);
241             mat4.multiplyVec3(uNMatrix, uLightDirection);
242             core.GL.currentProgram.setAttributes({
243                 aVertexPosition: this.mesh._vertices,
244                 aVertexNormal: this.mesh._normals,
245                 aTextureCoord: this.mesh._texCoords,
246                 aVectorFromBone1: this.mesh._vpos1,
247                 aVectorFromBone2: this.mesh._vpos2,
248                 aBone1Position: this.mesh._bone1pos,
249                 aBone2Position: this.mesh._bone2pos,
250                 aBone1Rotation: this.mesh._quats1,
251                 aBone2Rotation: this.mesh._quats2,
252                 aMultiPurposeVector: this.mesh._morphs,
253                 aBoneWeight: this.mesh._weights,
254                 aVertexEdge: this.mesh._edges
255             });
256             core.GL.currentProgram.setUniforms({
257                 uLightDirection: uLightDirection,
258                 uPMatrix: scene._camera.projMat,
259                 uMVMatrix: uMVMatrix,
260                 uNMatrix: uNMatrix
261             });
262             var length;
263             var material;
264             var offset = 0;
265             for (var i = 0, l = this.mesh.materials.length; i < l; i++) {
266                 material = this.mesh.materials[i];
267                 var u = {
268                     uAmbientColor: material.ambient,
269                     uDiffuseColor: material.diffuse,
270                     uSpecularColor: material.specular,
271                     uShininess: material.shininess,
272                     uAlpha: material.alpha
273                 };
274                 if (material.toon) {
275                     u.uToon = material.toon;
276                 }
277                 if (material.texture) {
278                     if (material.texture._image.src.match(/sph/)) {
279                         u.uUseSphereMap = 1;
280                         u.uUseTexture = 0;
281                         u.uUseSphereMapAdditive = 0;
282                         u.uSphereMap = material.texture;
283                     } else {
284                         u.uUseSphereMap = 0;
285                         u.uUseTexture = 1;
286                         u.uTexture = material.texture;
287                     }
288                 } else {
289                     u.uUseTexture = 0;
290                     u.uTexture = 0;
291                     u.uUseSphereMap = 0;
292                 }
293                 core.GL.currentProgram.setUniforms(u);
294 
295 
296                 length = material.face_vert_count;
297                 enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length);
298 
299                 if (material.edge_flag) {
300                     enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 1 });
301                     gl.cullFace(gl.FRONT);
302                     enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length);
303                     gl.cullFace(gl.BACK);
304                     enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 0 });
305                 }
306 
307                 offset += material.face_vert_count;
308             }
309         },
310         /**
311          * Load PMD files.
312          * Will be dispatched LOAD event when data has loaded.
313          * @param {String} path File path
314          * @param {Function} [callback] onload callback.
315          * @param {Function} [onerror] onerror callback.
316          * @example
317          * // model/miku.pmd loading.
318          * var mk = new MSprite3D();
319          * mk.loadPmd('model/miku.pmd', function() {
320          *     scene.addChild(mk);
321          * });
322          */
323         loadPmd: function(path, callback, onerror) {
324             var split = splitPath(path);
325             var model = new MMD.Model(split[1], split[2]);
326             var that = this;
327             this._data = model;
328             callback = callback || function() {};
329             onerror = onerror || function() {};
330             this.addEventListener('load', callback);
331             this.addEventListener('error', onerror);
332             model.load(function() {
333                 var e;
334                 try {
335                     that._parse(model);
336                     that.dispatchEvent(new enchant.Event(enchant.Event.LOAD));
337                 } catch (err) {
338                     e = new enchant.Event(enchant.Event.ERROR);
339                     e.message = err.message;
340                     enchant.Core.instance.dispatchEvent(e);
341                     that.dispatchEvent(e);
342                 }
343             });
344         },
345         set: function(sp) {
346             this._parse(sp._data);
347             this._data = sp._data;
348         },
349         clone: function() {
350             var sp = new enchant.gl.mmd.MSprite3D();
351             sp._parse(this._data);
352             sp._data = this._data;
353             return sp;
354         },
355         _parse: function(model) {
356             var data;
357             var original;
358             var params = [ 'ambient', 'diffuse', 'specular', 'shininess', 'alpha', 'face_vert_count', 'edge_flag' ];
359 
360             var mesh = new enchant.gl.mmd.MMesh();
361             var length = model.vertices.length;
362             var v;
363             var b1, b2;
364             var ind;
365             var material;
366             var vertices = new Float32Array(length * 3);
367             var normals = new Float32Array(length * 3);
368             var texCoords = new Float32Array(length * 2);
369             var indices = new Uint16Array(model.triangles);
370             var vpos1 = new Float32Array(length * 3);
371             var vpos2 = new Float32Array(length * 3);
372             var bone1pos = new Float32Array(length * 3);
373             var bone2pos = new Float32Array(length * 3);
374             var quats1 = new Float32Array(length * 4);
375             var quats2 = new Float32Array(length * 4);
376             var morphs = new Float32Array(length * 3);
377             var weights = new Float32Array(length);
378             var edges = new Uint16Array(length);
379             var bindex1 = new Float32Array(length);
380             var bindex2 = new Float32Array(length);
381             var tmp = vec3.create();
382             var tmp2 = vec3.create();
383             for (var i = 0; i < length; i++) {
384                 v = model.vertices[i];
385                 b1 = model.bones[v.bone_num1];
386                 b2 = model.bones[v.bone_num2];
387                 bindex1[i] = v.bone_num1;
388                 bindex2[i] = v.bone_num2;
389                 tmp.set([ v.x, v.y, v.z ]);
390                 vertices.set(tmp, i * 3);
391                 vec3.subtract(tmp, b1.head_pos, tmp2);
392                 vpos1.set(tmp2, i * 3);
393                 vec3.subtract(tmp, b2.head_pos, tmp2);
394                 vpos2.set(tmp2, i * 3);
395                 normals.set([ v.nx, v.ny, v.nz ], i * 3);
396                 texCoords.set([ v.u, v.v ], i * 2);
397                 bone1pos.set(b1.head_pos, i * 3);
398                 bone2pos.set(b2.head_pos, i * 3);
399                 quats1.set([ 0, 0, 0, 1 ], i * 4);
400                 quats2.set([ 0, 0, 0, 1 ], i * 4);
401                 morphs.set([ 0, 0, 0 ], i * 3);
402                 weights[i] = v.bone_weight;
403                 edges[i] = 1 - v.edge_flag;
404             }
405 
406 
407             mesh.vertices = vertices;
408             mesh.normals = normals;
409             mesh.texCoords = texCoords;
410             mesh.indices = indices;
411             mesh.vpos1 = vpos1;
412             mesh.vpos2 = vpos2;
413             mesh.bone1pos = bone1pos;
414             mesh.bone2pos = bone2pos;
415             mesh.quats1 = quats1;
416             mesh.quats2 = quats2;
417             mesh.weights = weights;
418             mesh.edges = edges;
419             mesh.morphs = morphs;
420             mesh.colors = new Float32Array(length * 4);
421             mesh.bindex1 = bindex1;
422             mesh.bindex2 = bindex2;
423 
424             this.mesh = mesh;
425 
426             this.mesh.materials = [];
427 
428             this.skeleton = new enchant.gl.mmd.MSkeleton(model.bones);
429             var l;
430             for (i = 0, l = model.iks.length; i < l; i++) {
431                 data = model.iks[i];
432                 this.skeleton._addIK(data);
433             }
434 
435             this.morph = new enchant.gl.mmd.MMorph(model.morphs);
436 
437             for (i = 0, l = model.materials.length; i < l; i++) {
438                 original = model.materials[i];
439                 material = this.mesh.materials[i] = {};
440                 for (var prop in params) {
441                     material[params[prop]] = original[params[prop]];
442                 }
443                 if (typeof model.toon_file_names[i] !== 'undefined') {
444                     material.toon = new enchant.gl.Texture(model.directory + '/' + model.toon_file_names[original.toon_index], {flipY: false});
445                 }
446                 if (original.texture_file_name) {
447                     material.texture = new enchant.gl.Texture(model.directory + '/' + original.texture_file_name);
448                 }
449             }
450         },
451         _applySkeleton: function() {
452             var sk = this.skeleton;
453             var mesh = this.mesh;
454             var b1pos, b2pos, b1rot, b2rot;
455             var i3 = 0, i4 = 0;
456             var length = this.mesh.vertices.length / 3;
457             for (var i = 0; i < length; i++) {
458                 b1pos = sk.table[mesh.bindex1[i]]._globalpos;
459                 b2pos = sk.table[mesh.bindex2[i]]._globalpos;
460                 b1rot = sk.table[mesh.bindex1[i]]._globalrot;
461                 b2rot = sk.table[mesh.bindex2[i]]._globalrot;
462 
463                 mesh._bone1pos._array[i3 + 0] = b1pos[0];
464                 mesh._bone1pos._array[i3 + 1] = b1pos[1];
465                 mesh._bone1pos._array[i3 + 2] = b1pos[2];
466                 mesh._bone2pos._array[i3 + 0] = b2pos[0];
467                 mesh._bone2pos._array[i3 + 1] = b2pos[1];
468                 mesh._bone2pos._array[i3 + 2] = b2pos[2];
469 
470                 mesh._quats1._array[i4 + 0] = b1rot[0];
471                 mesh._quats1._array[i4 + 1] = b1rot[1];
472                 mesh._quats1._array[i4 + 2] = b1rot[2];
473                 mesh._quats1._array[i4 + 3] = b1rot[3];
474                 mesh._quats2._array[i4 + 0] = b2rot[0];
475                 mesh._quats2._array[i4 + 1] = b2rot[1];
476                 mesh._quats2._array[i4 + 2] = b2rot[2];
477                 mesh._quats2._array[i4 + 3] = b2rot[3];
478 
479                 i3 += 3;
480                 i4 += 4;
481             }
482             mesh._bone1pos._bufferDataFast();
483             mesh._bone2pos._bufferDataFast();
484             mesh._quats1._bufferDataFast();
485             mesh._quats2._bufferDataFast();
486         }
487     });
488 
489 
490     enchant.gl.mmd.MPose = enchant.Class.create(enchant.gl.Pose, {
491         initialize: function(param) {
492             enchant.gl.Pose.call(this, param.location, param.rotation);
493             this._interpolation = param.interpolation;
494         },
495         _internalInterpole: function(i, x) {
496             var x1 = this._interpolation[0 + i] / 127;
497             var y1 = this._interpolation[4 + i] / 127;
498             var x2 = this._interpolation[8 + i] / 127;
499             var y2 = this._interpolation[12 + i] / 127;
500             return this._bezierp(x1, y1, x2, y2, x);
501         },
502         getInterpolation: function(another, ratio) {
503             var v = vec3.create();
504             var q = quat4.create();
505             var xt = this._internalInterpole(0, ratio);
506             var yt = this._internalInterpole(1, ratio);
507             var zt = this._internalInterpole(2, ratio);
508             var rt = this._internalInterpole(3, ratio);
509             v[0] = this._position[0] + (another._position[0] - this._position[0]) * xt;
510             v[1] = this._position[1] + (another._position[1] - this._position[1]) * yt;
511             v[2] = this._position[2] + (another._position[2] - this._position[2]) * zt;
512             var loc = v;
513             var rot = quat4.slerp(this._rotation, another._rotation, rt, q);
514             return new enchant.gl.Pose(loc, rot);
515         }
516     });
517 
518     enchant.gl.mmd.MMorph = enchant.Class.create({
519         initialize: function(data) {
520             this._base = {};
521             this._morphs = {};
522             if (typeof data !== 'undefined') {
523                 this._load(data);
524             }
525         },
526         _load: function(data) {
527             this._base = data.slice(0, 1)[0];
528             var m, name, vert, morph;
529             for (var i = 1, l = data.length; i < l; i++) {
530                 m = data[i];
531                 name = m.name;
532                 vert = m.vert_data;
533                 morph = this._morphs[name] = {};
534                 morph.index = new Float32Array(vert.length);
535                 morph.vert = new Float32Array(vert.length * 3);
536                 for (var j = 0, ll = vert.length; j < ll; j++) {
537                     morph.index[j] = this._base.vert_data[vert[j].index].index * 3;
538                     morph.vert[j * 3] = vert[j].x;
539                     morph.vert[j * 3 + 1] = vert[j].y;
540                     morph.vert[j * 3 + 2] = vert[j].z;
541                 }
542             }
543         },
544         morphing: function(data, target) {
545             var weight, index;
546             for (var prop in data) {
547                 weight = data[prop]._weight;
548                 if (weight && this._morphs[prop]) {
549                     this._morphing(prop, target, weight);
550                 }
551             }
552         },
553         _morphing: function(name, target, weight) {
554             var set = this._morphs[name];
555             var index;
556             for (var i = 0, l = set.index.length; i < l; i++) {
557                 index = set.index[i];
558                 target[index] += set.vert[i * 3] * weight;
559                 target[index + 1] += set.vert[i * 3 + 1] * weight;
560                 target[index + 2] += set.vert[i * 3 + 2] * weight;
561             }
562         }
563     });
564 
565     enchant.gl.mmd.MMorphPoint = enchant.Class.create({
566         initialize: function(weight) {
567             this._weight = weight;
568         },
569         getInterpolation: function(another, ratio) {
570             return new enchant.gl.mmd.MMorphPoint(lerp(this._weight, another._weight, ratio));
571         }
572     });
573 
574     enchant.gl.mmd.MKeyFrameManager = enchant.Class.create(enchant.gl.KeyFrameManager, {
575         initialize: function() {
576             enchant.gl.KeyFrameManager.call(this);
577         }
578     });
579 
580     /**
581      * @scope enchant.gl.mmd.MAnimation.prototype
582      */
583     enchant.gl.mmd.MAnimation = enchant.Class.create(enchant.EventTarget, {
584         /**
585          * Animation class optimized to VMD file.
586          * Character data and morphing are loaded.
587          * By preloading VMD file, it will be set in assets automatically.
588          * If argument is delivered {@link enchant.gl.mmd.MAnimation#loadVmd} will be called up.
589          * @param {String} [path] File path.
590          * @param {Function} [callback] onload callback.
591          * @param {Function} [onerror] onerror callback.
592          * @constructs
593          * @extends enchant.EventTarget
594          * @see enchant.gl.mmd.MAnimation#loadVmd
595          */
596         initialize: function(path, callback, onerror) {
597             enchant.EventTarget.call(this);
598             this.length = -1;
599             if (arguments.length >= 2) {
600                 this.loadVmd(path, callback, onerror);
601             }
602         },
603         /**
604          * Load VMD file.
605          * Will be dispatched LOAD event when data has loaded.
606          * @param {String} path File path
607          * @param {Function} callback Callback function
608          * @example
609          * // motion/dance.vmd is loaded.
610          * var dance = new MAnimation();
611          * dance.loadVmd('motion/dance.vmd', function() {
612          *     mk.pushAnimation(dance);
613          * });
614          */
615         loadVmd: function(path, callback, onerror) {
616             var motion = new MMD.Motion(path);
617             var frame;
618             var that = this;
619 
620             callback = callback || function() {};
621             onerror = onerror || function() {};
622             console.log(this);
623             this.addEventListener('load', callback);
624             this.addEventListener('error', onerror);
625             motion.load(function() {
626                 var e;
627                 try {
628                     that.motions = parseMotion(motion.bone);
629                     that.morphs = parseMorph(motion.morph);
630                     that._calcLength();
631                     that.dispatchEvent(new enchant.Event(enchant.Event.LOAD));
632                 } catch (err) {
633                     e = new enchant.Event(enchant.Event.ERROR);
634                     e.message = err.message;
635                     enchant.Core.instance.dispatchEvent(e);
636                     that.dispatchEvent(e);
637                 }
638             });
639         },
640         bake: function() {
641             var prop, manager;
642             for (prop in this.morphs) {
643                 manager = this.morphs[prop];
644                 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) {
645                     manager.bake();
646                 }
647             }
648             for (prop in this.motions) {
649                 manager = this.motions[prop];
650                 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) {
651                     manager.bake();
652                 }
653             }
654         },
655         _tick: function(frame) {
656             var poses = this._getFrame(this.motions, frame);
657             var morphs = this._getFrame(this.morphs, frame);
658             return {
659                 poses: poses,
660                 morphs: morphs
661             };
662         },
663         _getFrame: function(data, frame) {
664             var ret = {};
665             for (var prop in data) {
666                 ret[prop] = data[prop].getFrame(frame);
667             }
668             return ret;
669         },
670         _calcLength: function() {
671             var data, deta;
672             for (var prop in this) {
673                 data = this[prop];
674                 if (data instanceof Object) {
675                     for (var plop in data) {
676                         deta = data[plop];
677                         if (deta instanceof enchant.gl.mmd.MKeyFrameManager) {
678                             if (this.length < deta.length) {
679                                 this.length = deta.length;
680                             }
681                         }
682                     }
683                 }
684             }
685         }
686     });
687 
688     var parseMorph = function(data) {
689         var morphs = {};
690         var morph, name, frame, weight;
691         for (var i = 0, l = data.length; i < l; i++) {
692             morph = data[i];
693             name = morph.name;
694             frame = morph.frame;
695             weight = morph.weight;
696             if (typeof morphs[name] === 'undefined') {
697                 morphs[name] = new enchant.gl.mmd.MKeyFrameManager();
698             }
699             morphs[name].addFrame(new enchant.gl.mmd.MMorphPoint(weight), frame);
700         }
701         for (var prop in morphs) {
702             morphs[prop]._sort();
703         }
704         return morphs;
705     };
706 
707     var parseMotion = function(data) {
708         var motions = {};
709         var bone, name, frame;
710         for (var i = 0, l = data.length; i < l; i++) {
711             bone = data[i];
712             name = bone.name;
713             frame = bone.frame;
714             if (typeof motions[name] === 'undefined') {
715                 motions[name] = new enchant.gl.mmd.MKeyFrameManager();
716             }
717             motions[name].addFrame(new enchant.gl.mmd.MPose(bone), frame);
718         }
719         for (var prop in motions) {
720             motions[prop]._sort();
721         }
722         return motions;
723     };
724 
725     var bufferProto = Object.getPrototypeOf(enchant.gl.Buffer);
726     bufferProto.MORPHS = bufferProto.NORMALS;
727     bufferProto.QUATS = bufferProto.COLORS;
728     bufferProto.WEIGHTS = {
729         size: 1,
730         type: 5126,
731         norm: false,
732         stride: 0,
733         offset: 0,
734         btype: 34962,
735         usage: 35044,
736         Atype: Float32Array
737     };
738     bufferProto.EDGES = {
739         size: 1,
740         type: 5123,
741         norm: false,
742         stride: 0,
743         offset: 0,
744         btype: 34962,
745         usage: 35044,
746         Atype: Uint16Array
747     };
748 
749     var _original_start = enchant.gl.Core.prototype.start;
750     enchant.gl.Core.prototype.start = function() {
751         enchant.gl.mmd.MMD_SHADER_PROGRAM = new enchant.gl.Shader(MMD_VERTEX_SHADER_SOURCE, MMD_FRAGMENT_SHADER_SOURCE);
752         this.GL.setProgram(enchant.gl.mmd.MMD_SHADER_PROGRAM);
753         enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({
754             uLightMatrix: [
755                 1, 0, 0, 0,
756                 0, 1, 0, 0,
757                 0, 0, 1, 0,
758                 0, 0, 0, 1
759             ],
760             uLightColor: [ 0.6, 0.6, 0.6 ],
761             uSelfShadow: 0,
762             uShadowMap: 0,
763             uGenerateShadowMap: 0,
764             uCenterPoint: 0,
765             uAxis: 0,
766             uAxisColor: [ 1, 0, 1 ],
767             uEdge: 0,
768             uEdgeColor: [ 0, 0, 0 ],
769             uEdgeThickness: 0.004
770         });
771         this.GL.setDefaultProgram();
772         _original_start.call(this);
773     };
774 
775     var lerp = function(n1, n2, r) {
776         return n1 + r * (n2 - n1);
777     };
778 
779     var MMD_VERTEX_SHADER_SOURCE = '\n\
780         uniform mat4 uMVMatrix;\n\
781         uniform mat4 uPMatrix;\n\
782         uniform mat4 uNMatrix;\n\
783         \n\
784         uniform mat4 uLightMatrix;\n\
785         \n\
786         attribute vec3 aVertexNormal;\n\
787         attribute vec2 aTextureCoord;\n\
788         attribute float aVertexEdge;\n\
789         \n\
790         attribute float aBoneWeight;\n\
791         attribute vec3 aVectorFromBone1;\n\
792         attribute vec3 aVectorFromBone2;\n\
793         attribute vec4 aBone1Rotation;\n\
794         attribute vec4 aBone2Rotation;\n\
795         attribute vec3 aBone1Position;\n\
796         attribute vec3 aBone2Position;\n\
797         \n\
798         attribute vec3 aMultiPurposeVector;\n\
799         \n\
800         varying vec3 vPosition;\n\
801         varying vec3 vNormal;\n\
802         varying vec2 vTextureCoord;\n\
803         varying vec4 vLightCoord;\n\
804         \n\
805         uniform float uEdgeThickness;\n\
806         uniform bool uEdge;\n\
807         \n\
808         uniform bool uGenerateShadowMap;\n\
809         \n\
810         uniform bool uSelfShadow;\n\
811         \n\
812         uniform bool uAxis;\n\
813         uniform bool uCenterPoint;\n\
814         \n\
815         vec3 qtransform(vec4 q, vec3 v) {\n\
816             return v + 2.0 * cross(cross(v, q.xyz) - q.w*v, q.xyz);\n\
817         }\n\
818         \n\
819         void main() {\n\
820             vec3 position;\n\
821             vec3 normal;\n\
822         \n\
823             if (uAxis || uCenterPoint) {\n\
824         \n\
825                 position = aMultiPurposeVector;\n\
826         \n\
827             } else {\n\
828         \n\
829                 float weight = aBoneWeight;\n\
830                 vec3 morph = aMultiPurposeVector;\n\
831         \n\
832                 position = qtransform(aBone1Rotation, aVectorFromBone1 + morph) + aBone1Position;\n\
833                 normal = qtransform(aBone1Rotation, aVertexNormal);\n\
834         \n\
835                 if (weight < 0.99) {\n\
836                     vec3 p2 = qtransform(aBone2Rotation, aVectorFromBone2 + morph) + aBone2Position;\n\
837                     vec3 n2 = qtransform(aBone2Rotation, normal);\n\
838         \n\
839                     position = mix(p2, position, weight);\n\
840                     normal = normalize(mix(n2, normal, weight));\n\
841                 }\n\
842             }\n\
843         \n\
844            \n\
845             gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);\n\
846         \n\
847             if (uCenterPoint) {\n\
848                 gl_Position.z = 0.0;\n\
849                 gl_PointSize = 16.0;\n\
850             }\n\
851         \n\
852             if (uGenerateShadowMap || uAxis || uCenterPoint) return;\n\
853         \n\
854            \n\
855             vTextureCoord = aTextureCoord;\n\
856             vPosition = (uMVMatrix * vec4(position, 1.0)).xyz;\n\
857             vNormal = (uNMatrix * vec4(normal, 1.0)).xyz;\n\
858         \n\
859             if (uSelfShadow) {\n\
860                 vLightCoord = uLightMatrix * vec4(position, 1.0);\n\
861             }\n\
862         \n\
863             if (uEdge) {\n\
864                 vec4 pos = gl_Position;\n\
865                 vec4 pos2 = uPMatrix * uMVMatrix * vec4(position + normal, 1.0);\n\
866                 vec4 norm = normalize(pos2 - pos);\n\
867                 gl_Position = pos + norm * uEdgeThickness * aVertexEdge * pos.w;\n\
868                 return;\n\
869             }\n\
870         }\n\
871     ';
872 
873     var MMD_FRAGMENT_SHADER_SOURCE = '\n\
874         #ifdef GL_ES\n\
875             precision highp float;\n\
876         #endif\n\
877         \n\
878         varying vec2 vTextureCoord;\n\
879         varying vec3 vPosition;\n\
880         varying vec3 vNormal;\n\
881         varying vec4 vLightCoord;\n\
882         \n\
883         uniform vec3 uLightDirection;\n\
884         uniform vec3 uLightColor;\n\
885         \n\
886         uniform vec3 uAmbientColor;\n\
887         uniform vec3 uSpecularColor;\n\
888         uniform vec3 uDiffuseColor;\n\
889         uniform float uAlpha;\n\
890         uniform float uShininess;\n\
891         \n\
892         uniform bool uUseTexture;\n\
893         uniform bool uUseSphereMap;\n\
894         uniform bool uIsSphereMapAdditive;\n\
895         \n\
896         uniform sampler2D uToon;\n\
897         uniform sampler2D uTexture;\n\
898         uniform sampler2D uSphereMap;\n\
899         \n\
900         uniform bool uEdge;\n\
901         uniform float uEdgeThickness;\n\
902         uniform vec3 uEdgeColor;\n\
903         \n\
904         uniform bool uGenerateShadowMap;\n\
905         uniform bool uSelfShadow;\n\
906         uniform sampler2D uShadowMap;\n\
907         \n\
908         uniform bool uAxis;\n\
909         uniform vec3 uAxisColor;\n\
910         uniform bool uCenterPoint;\n\
911         \n\
912         // from http://spidergl.org/example.php?id=6\n\
913         vec4 pack_depth(const in float depth) {\n\
914             const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n\
915             const vec4 bit_mask  = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n\
916             vec4 res = fract(depth * bit_shift);\n\
917             res -= res.xxyz * bit_mask;\n\
918             return res;\n\
919         }\n\
920         float unpack_depth(const in vec4 rgba_depth)\n\
921         {\n\
922             const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);\n\
923             float depth = dot(rgba_depth, bit_shift);\n\
924             return depth;\n\
925         }\n\
926         \n\
927         void main() {\n\
928             if (uGenerateShadowMap) {\n\
929                \n\
930                 gl_FragColor = pack_depth(gl_FragCoord.z);\n\
931                 return;\n\
932             }\n\
933             if (uAxis) {\n\
934                 gl_FragColor = vec4(uAxisColor, 1.0);\n\
935                 return;\n\
936             }\n\
937             if (uCenterPoint) {\n\
938                 vec2 uv = gl_PointCoord * 2.0 - 1.0;\n\
939                 float w = dot(uv, uv);\n\
940                 if (w < 0.3 || (w > 0.5 && w < 1.0)) {\n\
941                     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\
942                 } else {\n\
943                     discard;\n\
944                 }\n\
945                 return;\n\
946             }\n\
947         \n\
948            \n\
949             vec3 norm = normalize(vNormal);\n\
950             vec3 cameraDirection = normalize(-vPosition);\n\
951         \n\
952             vec3 color;\n\
953             float alpha = uAlpha;\n\
954         \n\
955             if (uEdge) {\n\
956         \n\
957                 color = uEdgeColor;\n\
958         \n\
959             } else {\n\
960         \n\
961                 color = vec3(1.0, 1.0, 1.0);\n\
962                 if (uUseTexture) {\n\
963                     vec4 texColor = texture2D(uTexture, vTextureCoord);\n\
964                     color *= texColor.rgb;\n\
965                     alpha *= texColor.a;\n\
966                 }\n\
967                 if (uUseSphereMap) {\n\
968                     vec2 sphereCoord = 0.5 * (1.0 + vec2(1.0, -1.0) * norm.xy);\n\
969                     if (uIsSphereMapAdditive) {\n\
970                         color += texture2D(uSphereMap, sphereCoord).rgb;\n\
971                     } else {\n\
972                         color *= texture2D(uSphereMap, sphereCoord).rgb;\n\
973                     }\n\
974                 }\n\
975         \n\
976                \n\
977                 vec3 halfAngle = normalize(uLightDirection + cameraDirection);\n\
978                 float specularWeight = pow( max(0.001, dot(halfAngle, norm)) , uShininess );\n\
979                \n\
980                 vec3 specular = specularWeight * uSpecularColor;\n\
981         \n\
982                 vec2 toonCoord = vec2(0.0, 0.5 * (1.0 - dot( uLightDirection, norm )));\n\
983         \n\
984                 if (uSelfShadow) {\n\
985                     vec3 lightCoord = vLightCoord.xyz / vLightCoord.w;\n\
986                     vec4 rgbaDepth = texture2D(uShadowMap, lightCoord.xy);\n\
987                     float depth = unpack_depth(rgbaDepth);\n\
988                     if (depth < lightCoord.z - 0.01) {\n\
989                         toonCoord = vec2(0.0, 0.55);\n\
990                     }\n\
991                 }\n\
992         \n\
993                 color *= uAmbientColor + uLightColor * (uDiffuseColor + specular);\n\
994         \n\
995                 color = clamp(color, 0.0, 1.0);\n\
996                 color *= texture2D(uToon, toonCoord).rgb;\n\
997         \n\
998             }\n\
999             gl_FragColor = vec4(color, alpha);\n\
1000         \n\
1001         }\n\
1002     ';
1003 }());
1004