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