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  * MikuMikuDanceのPMDファイルとVMDファイルをgl.enchant.js上で使用できるようにするプラグイン.
 11  *
 12  * @detail
 13  * ファイルの読み込み・パースにMMD.jsのMMD.Model.jsとMMD.Motion.jsを使用します.
 14  * シェーダのソースをMMD.VertexShaderSource.jsとMMD.FragmentShaderSource.jsから引用しています.
 15  *
 16  * MMD.js:
 17  * https://github.com/edvakf/MMD.js
 18  * 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用のメッシュオブジェクト.
 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          * PMDファイルに対応したSprite3D.
159          * 引数を渡すと{@link enchant.gl.mmd.MAnimation#loadVmd}が呼び出される.
160          * PMDファイルをプリロードすることでassets内に自動的に生成される.
161          * @param {String} [path] ファイルパス.
162          * @param {Function} [callback] ロード完了時のコールバック関数.
163          * @param {Function} [onerror] ロード失敗時のコールバック関数.
164          * @constructs
165          * @extends enchant.gl.Sprite3D
166          */
167         initialize: function(path, callback, onerror) {
168             enchant.gl.Sprite3D.call(this);
169             this.program = enchant.gl.mmd.MMD_SHADER_PROGRAM;
170             this.animation = [];
171             this.uMVMatrix = mat4.create();
172             this.uNMatrix = mat4.create();
173 
174             this.addEventListener('enterframe', function() {
175                 var first;
176                 var skeleton = this.skeleton;
177                 var morph = this.morph;
178                 if (this.animation.length === 0) {
179                 } else {
180                     first = this.animation[0];
181 
182                     var data = first.animation._tick(first.frame);
183                     first.frame++;
184 
185                     this._skinning(data.poses);
186 
187                     this._morphing(data.morphs);
188 
189                     if (first.frame > first.animation.length) {
190                         first = this.animation.shift();
191                         if (this.loop) {
192                             first.frame = 0;
193                             this.animation.push(first);
194                         }
195                     }
196                 }
197             });
198             if (arguments.length >= 2) {
199                 this.loadPmd(path, callback, onerror);
200             }
201         },
202         /**
203          * アニメーションを追加する.
204          * アニメーションは追加された順に再生されていく.
205          * @param {enchant.gl.mmd.MAnimation} animation
206          */
207         pushAnimation: function(animation) {
208             this.animation.push({ frame: 0, animation: animation });
209         },
210         /**
211          * 追加されたアニメーションを削除する.
212          */
213         clearAnimation: function(animation) {
214             this.animation = [];
215         },
216         _skinning: function(poses) {
217             var skeleton = this.skeleton;
218             skeleton.setPoses(poses);
219             skeleton.solveFKs();
220             skeleton.solveIKs();
221             this._applySkeleton();
222 
223         },
224         _morphing: function(morphs) {
225             var target = this.mesh.morphs;
226             for (var i = 0, l = target.length; i < l; i++) {
227                 target[i] = 0;
228             }
229             this.morph.morphing(morphs, target);
230             this.mesh._morphs._bufferDataFast();
231         },
232         _render: function() {
233             var core = enchant.Core.instance;
234             var scene = core.currentScene3D;
235             var light = scene.directionalLight;
236             var lvec = [ light._directionX, light._directionY, light._directionZ ];
237             var uMVMatrix = mat4.identity(this.uMVMatrix);
238             mat4.multiply(scene._camera.mat, this.tmpMat, uMVMatrix);
239             var uNMatrix = mat4.identity(this.uNMatrix);
240             mat4.transpose(mat4.inverse(uMVMatrix, uNMatrix));
241             var uLightDirection = vec3.normalize(lvec);
242             mat4.multiplyVec3(uNMatrix, uLightDirection);
243             core.GL.currentProgram.setAttributes({
244                 aVertexPosition: this.mesh._vertices,
245                 aVertexNormal: this.mesh._normals,
246                 aTextureCoord: this.mesh._texCoords,
247                 aVectorFromBone1: this.mesh._vpos1,
248                 aVectorFromBone2: this.mesh._vpos2,
249                 aBone1Position: this.mesh._bone1pos,
250                 aBone2Position: this.mesh._bone2pos,
251                 aBone1Rotation: this.mesh._quats1,
252                 aBone2Rotation: this.mesh._quats2,
253                 aMultiPurposeVector: this.mesh._morphs,
254                 aBoneWeight: this.mesh._weights,
255                 aVertexEdge: this.mesh._edges
256             });
257             core.GL.currentProgram.setUniforms({
258                 uLightDirection: uLightDirection,
259                 uPMatrix: scene._camera.projMat,
260                 uMVMatrix: uMVMatrix,
261                 uNMatrix: uNMatrix
262             });
263             var length;
264             var material;
265             var offset = 0;
266             for (var i = 0, l = this.mesh.materials.length; i < l; i++) {
267                 material = this.mesh.materials[i];
268                 var u = {
269                     uAmbientColor: material.ambient,
270                     uDiffuseColor: material.diffuse,
271                     uSpecularColor: material.specular,
272                     uShininess: material.shininess,
273                     uAlpha: material.alpha
274                 };
275                 if (material.toon) {
276                     u.uToon = material.toon;
277                 }
278                 if (material.texture) {
279                     if (material.texture._image.src.match(/sph/)) {
280                         u.uUseSphereMap = 1;
281                         u.uUseTexture = 0;
282                         u.uUseSphereMapAdditive = 0;
283                         u.uSphereMap = material.texture;
284                     } else {
285                         u.uUseSphereMap = 0;
286                         u.uUseTexture = 1;
287                         u.uTexture = material.texture;
288                     }
289                 } else {
290                     u.uUseTexture = 0;
291                     u.uTexture = 0;
292                     u.uUseSphereMap = 0;
293                 }
294                 core.GL.currentProgram.setUniforms(u);
295 
296 
297                 length = material.face_vert_count;
298                 enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length);
299 
300                 if (material.edge_flag) {
301                     enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 1 });
302                     gl.cullFace(gl.FRONT);
303                     enchant.Core.instance.GL.renderElements(this.mesh._indices, offset * 2, length);
304                     gl.cullFace(gl.BACK);
305                     enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({ uEdge: 0 });
306                 }
307 
308                 offset += material.face_vert_count;
309             }
310         },
311         /**
312          * PMDファイルをロードする.
313          * ロード完了時にLOADイベントが発行される.
314          * @param {String} path ファイルパス
315          * @param {Function} [callback] ロード完了時のコールバック.
316          * @param {Function} [onerror] ロード失敗時のコールバック.
317          * @example
318          * // model/miku.pmd を読み込む.
319          * var mk = new MSprite3D();
320          * mk.loadPmd('model/miku.pmd', function() {
321          *     scene.addChild(mk);
322          * });
323          */
324         loadPmd: function(path, callback, onerror) {
325             var split = splitPath(path);
326             var model = new MMD.Model(split[1], split[2]);
327             var that = this;
328             this._data = model;
329             callback = callback || function() {};
330             onerror = onerror || function() {};
331             this.addEventListener('load', callback);
332             this.addEventListener('error', onerror);
333             model.load(function() {
334                 var e;
335                 try {
336                     that._parse(model);
337                     that.dispatchEvent(new enchant.Event(enchant.Event.LOAD));
338                 } catch (err) {
339                     e = new enchant.Event(enchant.Event.ERROR);
340                     e.message = err.message;
341                     enchant.Core.instance.dispatchEvent(e);
342                     that.dispatchEvent(e);
343                 }
344             });
345         },
346         set: function(sp) {
347             this._parse(sp._data);
348             this._data = sp._data;
349         },
350         clone: function() {
351             var sp = new enchant.gl.mmd.MSprite3D();
352             sp._parse(this._data);
353             sp._data = this._data;
354             return sp;
355         },
356         _parse: function(model) {
357             var data;
358             var original;
359             var params = [ 'ambient', 'diffuse', 'specular', 'shininess', 'alpha', 'face_vert_count', 'edge_flag' ];
360 
361             var mesh = new enchant.gl.mmd.MMesh();
362             var length = model.vertices.length;
363             var v;
364             var b1, b2;
365             var ind;
366             var material;
367             var vertices = new Float32Array(length * 3);
368             var normals = new Float32Array(length * 3);
369             var texCoords = new Float32Array(length * 2);
370             var indices = new Uint16Array(model.triangles);
371             var vpos1 = new Float32Array(length * 3);
372             var vpos2 = new Float32Array(length * 3);
373             var bone1pos = new Float32Array(length * 3);
374             var bone2pos = new Float32Array(length * 3);
375             var quats1 = new Float32Array(length * 4);
376             var quats2 = new Float32Array(length * 4);
377             var morphs = new Float32Array(length * 3);
378             var weights = new Float32Array(length);
379             var edges = new Uint16Array(length);
380             var bindex1 = new Float32Array(length);
381             var bindex2 = new Float32Array(length);
382             var tmp = vec3.create();
383             var tmp2 = vec3.create();
384             for (var i = 0; i < length; i++) {
385                 v = model.vertices[i];
386                 b1 = model.bones[v.bone_num1];
387                 b2 = model.bones[v.bone_num2];
388                 bindex1[i] = v.bone_num1;
389                 bindex2[i] = v.bone_num2;
390                 tmp.set([ v.x, v.y, v.z ]);
391                 vertices.set(tmp, i * 3);
392                 vec3.subtract(tmp, b1.head_pos, tmp2);
393                 vpos1.set(tmp2, i * 3);
394                 vec3.subtract(tmp, b2.head_pos, tmp2);
395                 vpos2.set(tmp2, i * 3);
396                 normals.set([ v.nx, v.ny, v.nz ], i * 3);
397                 texCoords.set([ v.u, v.v ], i * 2);
398                 bone1pos.set(b1.head_pos, i * 3);
399                 bone2pos.set(b2.head_pos, i * 3);
400                 quats1.set([ 0, 0, 0, 1 ], i * 4);
401                 quats2.set([ 0, 0, 0, 1 ], i * 4);
402                 morphs.set([ 0, 0, 0 ], i * 3);
403                 weights[i] = v.bone_weight;
404                 edges[i] = 1 - v.edge_flag;
405             }
406 
407 
408             mesh.vertices = vertices;
409             mesh.normals = normals;
410             mesh.texCoords = texCoords;
411             mesh.indices = indices;
412             mesh.vpos1 = vpos1;
413             mesh.vpos2 = vpos2;
414             mesh.bone1pos = bone1pos;
415             mesh.bone2pos = bone2pos;
416             mesh.quats1 = quats1;
417             mesh.quats2 = quats2;
418             mesh.weights = weights;
419             mesh.edges = edges;
420             mesh.morphs = morphs;
421             mesh.colors = new Float32Array(length * 4);
422             mesh.bindex1 = bindex1;
423             mesh.bindex2 = bindex2;
424 
425             this.mesh = mesh;
426 
427             this.mesh.materials = [];
428 
429             this.skeleton = new enchant.gl.mmd.MSkeleton(model.bones);
430             var l;
431             for (i = 0, l = model.iks.length; i < l; i++) {
432                 data = model.iks[i];
433                 this.skeleton._addIK(data);
434             }
435 
436             this.morph = new enchant.gl.mmd.MMorph(model.morphs);
437 
438             for (i = 0, l = model.materials.length; i < l; i++) {
439                 original = model.materials[i];
440                 material = this.mesh.materials[i] = {};
441                 for (var prop in params) {
442                     material[params[prop]] = original[params[prop]];
443                 }
444                 if (typeof model.toon_file_names[i] !== 'undefined') {
445                     material.toon = new enchant.gl.Texture(model.directory + '/' + model.toon_file_names[original.toon_index], {flipY: false});
446                 }
447                 if (original.texture_file_name) {
448                     material.texture = new enchant.gl.Texture(model.directory + '/' + original.texture_file_name);
449                 }
450             }
451         },
452         _applySkeleton: function() {
453             var sk = this.skeleton;
454             var mesh = this.mesh;
455             var b1pos, b2pos, b1rot, b2rot;
456             var i3 = 0, i4 = 0;
457             var length = this.mesh.vertices.length / 3;
458             for (var i = 0; i < length; i++) {
459                 b1pos = sk.table[mesh.bindex1[i]]._globalpos;
460                 b2pos = sk.table[mesh.bindex2[i]]._globalpos;
461                 b1rot = sk.table[mesh.bindex1[i]]._globalrot;
462                 b2rot = sk.table[mesh.bindex2[i]]._globalrot;
463 
464                 mesh._bone1pos._array[i3 + 0] = b1pos[0];
465                 mesh._bone1pos._array[i3 + 1] = b1pos[1];
466                 mesh._bone1pos._array[i3 + 2] = b1pos[2];
467                 mesh._bone2pos._array[i3 + 0] = b2pos[0];
468                 mesh._bone2pos._array[i3 + 1] = b2pos[1];
469                 mesh._bone2pos._array[i3 + 2] = b2pos[2];
470 
471                 mesh._quats1._array[i4 + 0] = b1rot[0];
472                 mesh._quats1._array[i4 + 1] = b1rot[1];
473                 mesh._quats1._array[i4 + 2] = b1rot[2];
474                 mesh._quats1._array[i4 + 3] = b1rot[3];
475                 mesh._quats2._array[i4 + 0] = b2rot[0];
476                 mesh._quats2._array[i4 + 1] = b2rot[1];
477                 mesh._quats2._array[i4 + 2] = b2rot[2];
478                 mesh._quats2._array[i4 + 3] = b2rot[3];
479 
480                 i3 += 3;
481                 i4 += 4;
482             }
483             mesh._bone1pos._bufferDataFast();
484             mesh._bone2pos._bufferDataFast();
485             mesh._quats1._bufferDataFast();
486             mesh._quats2._bufferDataFast();
487         }
488     });
489 
490 
491     enchant.gl.mmd.MPose = enchant.Class.create(enchant.gl.Pose, {
492         initialize: function(param) {
493             enchant.gl.Pose.call(this, param.location, param.rotation);
494             this._interpolation = param.interpolation;
495         },
496         _internalInterpole: function(i, x) {
497             var x1 = this._interpolation[0 + i] / 127;
498             var y1 = this._interpolation[4 + i] / 127;
499             var x2 = this._interpolation[8 + i] / 127;
500             var y2 = this._interpolation[12 + i] / 127;
501             return this._bezierp(x1, y1, x2, y2, x);
502         },
503         getInterpolation: function(another, ratio) {
504             var v = vec3.create();
505             var q = quat4.create();
506             var xt = this._internalInterpole(0, ratio);
507             var yt = this._internalInterpole(1, ratio);
508             var zt = this._internalInterpole(2, ratio);
509             var rt = this._internalInterpole(3, ratio);
510             v[0] = this._position[0] + (another._position[0] - this._position[0]) * xt;
511             v[1] = this._position[1] + (another._position[1] - this._position[1]) * yt;
512             v[2] = this._position[2] + (another._position[2] - this._position[2]) * zt;
513             var loc = v;
514             var rot = quat4.slerp(this._rotation, another._rotation, rt, q);
515             return new enchant.gl.Pose(loc, rot);
516         }
517     });
518 
519     enchant.gl.mmd.MMorph = enchant.Class.create({
520         initialize: function(data) {
521             this._base = {};
522             this._morphs = {};
523             if (typeof data !== 'undefined') {
524                 this._load(data);
525             }
526         },
527         _load: function(data) {
528             this._base = data.slice(0, 1)[0];
529             var m, name, vert, morph;
530             for (var i = 1, l = data.length; i < l; i++) {
531                 m = data[i];
532                 name = m.name;
533                 vert = m.vert_data;
534                 morph = this._morphs[name] = {};
535                 morph.index = new Float32Array(vert.length);
536                 morph.vert = new Float32Array(vert.length * 3);
537                 for (var j = 0, ll = vert.length; j < ll; j++) {
538                     morph.index[j] = this._base.vert_data[vert[j].index].index * 3;
539                     morph.vert[j * 3] = vert[j].x;
540                     morph.vert[j * 3 + 1] = vert[j].y;
541                     morph.vert[j * 3 + 2] = vert[j].z;
542                 }
543             }
544         },
545         morphing: function(data, target) {
546             var weight, index;
547             for (var prop in data) {
548                 weight = data[prop]._weight;
549                 if (weight && this._morphs[prop]) {
550                     this._morphing(prop, target, weight);
551                 }
552             }
553         },
554         _morphing: function(name, target, weight) {
555             var set = this._morphs[name];
556             var index;
557             for (var i = 0, l = set.index.length; i < l; i++) {
558                 index = set.index[i];
559                 target[index] += set.vert[i * 3] * weight;
560                 target[index + 1] += set.vert[i * 3 + 1] * weight;
561                 target[index + 2] += set.vert[i * 3 + 2] * weight;
562             }
563         }
564     });
565 
566     enchant.gl.mmd.MMorphPoint = enchant.Class.create({
567         initialize: function(weight) {
568             this._weight = weight;
569         },
570         getInterpolation: function(another, ratio) {
571             return new enchant.gl.mmd.MMorphPoint(lerp(this._weight, another._weight, ratio));
572         }
573     });
574 
575     enchant.gl.mmd.MKeyFrameManager = enchant.Class.create(enchant.gl.KeyFrameManager, {
576         initialize: function() {
577             enchant.gl.KeyFrameManager.call(this);
578         }
579     });
580 
581     /**
582      * @scope enchant.gl.mmd.MAnimation.prototype
583      */
584     enchant.gl.mmd.MAnimation = enchant.Class.create(enchant.EventTarget, {
585         /**
586          * VMDファイルに対応したアニメーションクラス.
587          * キャラクターの姿勢とモーフィングのデータが読み込まれる.
588          * 引数を渡すと{@link enchant.gl.mmd.MAnimation#loadVmd}が呼び出される.
589          * VMDファイルをプリロードすることでassets内に自動的に生成される.
590          * @param {String} [path] ファイルパス.
591          * @param {Function} [callback] ロード成功時のコールバック関数.
592          * @param {Function} [onerror] ロード失敗時のコールバック関数.
593          * @constructs
594          * @extends enchant.EventTarget
595          * @see enchant.gl.mmd.MAnimation#loadVmd
596          */
597         initialize: function(path, callback, onerror) {
598             enchant.EventTarget.call(this);
599             this.length = -1;
600             if (arguments.length >= 2) {
601                 this.loadVmd(path, callback, onerror);
602             }
603         },
604         /**
605          * VMDファイルをロードする.
606          * ロード完了時にLOADイベントが発行される.
607          * @param {String} path ファイルパス
608          * @param {Function} callback コールバック関数
609          * @example
610          * // motion/dance.vmd を読み込む.
611          * var dance = new MAnimation();
612          * dance.loadVmd('motion/dance.vmd', function() {
613          *     mk.pushAnimation(dance);
614          * });
615          */
616         loadVmd: function(path, callback, onerror) {
617             var motion = new MMD.Motion(path);
618             var frame;
619             var that = this;
620 
621             callback = callback || function() {};
622             onerror = onerror || function() {};
623             console.log(this);
624             this.addEventListener('load', callback);
625             this.addEventListener('error', onerror);
626             motion.load(function() {
627                 var e;
628                 try {
629                     that.motions = parseMotion(motion.bone);
630                     that.morphs = parseMorph(motion.morph);
631                     that._calcLength();
632                     that.dispatchEvent(new enchant.Event(enchant.Event.LOAD));
633                 } catch (err) {
634                     e = new enchant.Event(enchant.Event.ERROR);
635                     e.message = err.message;
636                     enchant.Core.instance.dispatchEvent(e);
637                     that.dispatchEvent(e);
638                 }
639             });
640         },
641         bake: function() {
642             var prop, manager;
643             for (prop in this.morphs) {
644                 manager = this.morphs[prop];
645                 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) {
646                     manager.bake();
647                 }
648             }
649             for (prop in this.motions) {
650                 manager = this.motions[prop];
651                 if (manager instanceof enchant.gl.mmd.MKeyFrameManager) {
652                     manager.bake();
653                 }
654             }
655         },
656         _tick: function(frame) {
657             var poses = this._getFrame(this.motions, frame);
658             var morphs = this._getFrame(this.morphs, frame);
659             return {
660                 poses: poses,
661                 morphs: morphs
662             };
663         },
664         _getFrame: function(data, frame) {
665             var ret = {};
666             for (var prop in data) {
667                 ret[prop] = data[prop].getFrame(frame);
668             }
669             return ret;
670         },
671         _calcLength: function() {
672             var data, deta;
673             for (var prop in this) {
674                 data = this[prop];
675                 if (data instanceof Object) {
676                     for (var plop in data) {
677                         deta = data[plop];
678                         if (deta instanceof enchant.gl.mmd.MKeyFrameManager) {
679                             if (this.length < deta.length) {
680                                 this.length = deta.length;
681                             }
682                         }
683                     }
684                 }
685             }
686         }
687     });
688 
689     var parseMorph = function(data) {
690         var morphs = {};
691         var morph, name, frame, weight;
692         for (var i = 0, l = data.length; i < l; i++) {
693             morph = data[i];
694             name = morph.name;
695             frame = morph.frame;
696             weight = morph.weight;
697             if (typeof morphs[name] === 'undefined') {
698                 morphs[name] = new enchant.gl.mmd.MKeyFrameManager();
699             }
700             morphs[name].addFrame(new enchant.gl.mmd.MMorphPoint(weight), frame);
701         }
702         for (var prop in morphs) {
703             morphs[prop]._sort();
704         }
705         return morphs;
706     };
707 
708     var parseMotion = function(data) {
709         var motions = {};
710         var bone, name, frame;
711         for (var i = 0, l = data.length; i < l; i++) {
712             bone = data[i];
713             name = bone.name;
714             frame = bone.frame;
715             if (typeof motions[name] === 'undefined') {
716                 motions[name] = new enchant.gl.mmd.MKeyFrameManager();
717             }
718             motions[name].addFrame(new enchant.gl.mmd.MPose(bone), frame);
719         }
720         for (var prop in motions) {
721             motions[prop]._sort();
722         }
723         return motions;
724     };
725 
726     var bufferProto = Object.getPrototypeOf(enchant.gl.Buffer);
727     bufferProto.MORPHS = bufferProto.NORMALS;
728     bufferProto.QUATS = bufferProto.COLORS;
729     bufferProto.WEIGHTS = {
730         size: 1,
731         type: 5126,
732         norm: false,
733         stride: 0,
734         offset: 0,
735         btype: 34962,
736         usage: 35044,
737         Atype: Float32Array
738     };
739     bufferProto.EDGES = {
740         size: 1,
741         type: 5123,
742         norm: false,
743         stride: 0,
744         offset: 0,
745         btype: 34962,
746         usage: 35044,
747         Atype: Uint16Array
748     };
749 
750     var _original_start = enchant.gl.Core.prototype.start;
751     enchant.gl.Core.prototype.start = function() {
752         enchant.gl.mmd.MMD_SHADER_PROGRAM = new enchant.gl.Shader(MMD_VERTEX_SHADER_SOURCE, MMD_FRAGMENT_SHADER_SOURCE);
753         this.GL.setProgram(enchant.gl.mmd.MMD_SHADER_PROGRAM);
754         enchant.gl.mmd.MMD_SHADER_PROGRAM.setUniforms({
755             uLightMatrix: [
756                 1, 0, 0, 0,
757                 0, 1, 0, 0,
758                 0, 0, 1, 0,
759                 0, 0, 0, 1
760             ],
761             uLightColor: [ 0.6, 0.6, 0.6 ],
762             uSelfShadow: 0,
763             uShadowMap: 0,
764             uGenerateShadowMap: 0,
765             uCenterPoint: 0,
766             uAxis: 0,
767             uAxisColor: [ 1, 0, 1 ],
768             uEdge: 0,
769             uEdgeColor: [ 0, 0, 0 ],
770             uEdgeThickness: 0.004
771         });
772         this.GL.setDefaultProgram();
773         _original_start.call(this);
774     };
775 
776     var lerp = function(n1, n2, r) {
777         return n1 + r * (n2 - n1);
778     };
779 
780     var MMD_VERTEX_SHADER_SOURCE = '\n\
781         uniform mat4 uMVMatrix;\n\
782         uniform mat4 uPMatrix;\n\
783         uniform mat4 uNMatrix;\n\
784         \n\
785         uniform mat4 uLightMatrix;\n\
786         \n\
787         attribute vec3 aVertexNormal;\n\
788         attribute vec2 aTextureCoord;\n\
789         attribute float aVertexEdge;\n\
790         \n\
791         attribute float aBoneWeight;\n\
792         attribute vec3 aVectorFromBone1;\n\
793         attribute vec3 aVectorFromBone2;\n\
794         attribute vec4 aBone1Rotation;\n\
795         attribute vec4 aBone2Rotation;\n\
796         attribute vec3 aBone1Position;\n\
797         attribute vec3 aBone2Position;\n\
798         \n\
799         attribute vec3 aMultiPurposeVector;\n\
800         \n\
801         varying vec3 vPosition;\n\
802         varying vec3 vNormal;\n\
803         varying vec2 vTextureCoord;\n\
804         varying vec4 vLightCoord;\n\
805         \n\
806         uniform float uEdgeThickness;\n\
807         uniform bool uEdge;\n\
808         \n\
809         uniform bool uGenerateShadowMap;\n\
810         \n\
811         uniform bool uSelfShadow;\n\
812         \n\
813         uniform bool uAxis;\n\
814         uniform bool uCenterPoint;\n\
815         \n\
816         vec3 qtransform(vec4 q, vec3 v) {\n\
817             return v + 2.0 * cross(cross(v, q.xyz) - q.w*v, q.xyz);\n\
818         }\n\
819         \n\
820         void main() {\n\
821             vec3 position;\n\
822             vec3 normal;\n\
823         \n\
824             if (uAxis || uCenterPoint) {\n\
825         \n\
826                 position = aMultiPurposeVector;\n\
827         \n\
828             } else {\n\
829         \n\
830                 float weight = aBoneWeight;\n\
831                 vec3 morph = aMultiPurposeVector;\n\
832         \n\
833                 position = qtransform(aBone1Rotation, aVectorFromBone1 + morph) + aBone1Position;\n\
834                 normal = qtransform(aBone1Rotation, aVertexNormal);\n\
835         \n\
836                 if (weight < 0.99) {\n\
837                     vec3 p2 = qtransform(aBone2Rotation, aVectorFromBone2 + morph) + aBone2Position;\n\
838                     vec3 n2 = qtransform(aBone2Rotation, normal);\n\
839         \n\
840                     position = mix(p2, position, weight);\n\
841                     normal = normalize(mix(n2, normal, weight));\n\
842                 }\n\
843             }\n\
844         \n\
845            \n\
846             gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);\n\
847         \n\
848             if (uCenterPoint) {\n\
849                 gl_Position.z = 0.0;\n\
850                 gl_PointSize = 16.0;\n\
851             }\n\
852         \n\
853             if (uGenerateShadowMap || uAxis || uCenterPoint) return;\n\
854         \n\
855            \n\
856             vTextureCoord = aTextureCoord;\n\
857             vPosition = (uMVMatrix * vec4(position, 1.0)).xyz;\n\
858             vNormal = (uNMatrix * vec4(normal, 1.0)).xyz;\n\
859         \n\
860             if (uSelfShadow) {\n\
861                 vLightCoord = uLightMatrix * vec4(position, 1.0);\n\
862             }\n\
863         \n\
864             if (uEdge) {\n\
865                 vec4 pos = gl_Position;\n\
866                 vec4 pos2 = uPMatrix * uMVMatrix * vec4(position + normal, 1.0);\n\
867                 vec4 norm = normalize(pos2 - pos);\n\
868                 gl_Position = pos + norm * uEdgeThickness * aVertexEdge * pos.w;\n\
869                 return;\n\
870             }\n\
871         }\n\
872     ';
873 
874     var MMD_FRAGMENT_SHADER_SOURCE = '\n\
875         #ifdef GL_ES\n\
876             precision highp float;\n\
877         #endif\n\
878         \n\
879         varying vec2 vTextureCoord;\n\
880         varying vec3 vPosition;\n\
881         varying vec3 vNormal;\n\
882         varying vec4 vLightCoord;\n\
883         \n\
884         uniform vec3 uLightDirection;\n\
885         uniform vec3 uLightColor;\n\
886         \n\
887         uniform vec3 uAmbientColor;\n\
888         uniform vec3 uSpecularColor;\n\
889         uniform vec3 uDiffuseColor;\n\
890         uniform float uAlpha;\n\
891         uniform float uShininess;\n\
892         \n\
893         uniform bool uUseTexture;\n\
894         uniform bool uUseSphereMap;\n\
895         uniform bool uIsSphereMapAdditive;\n\
896         \n\
897         uniform sampler2D uToon;\n\
898         uniform sampler2D uTexture;\n\
899         uniform sampler2D uSphereMap;\n\
900         \n\
901         uniform bool uEdge;\n\
902         uniform float uEdgeThickness;\n\
903         uniform vec3 uEdgeColor;\n\
904         \n\
905         uniform bool uGenerateShadowMap;\n\
906         uniform bool uSelfShadow;\n\
907         uniform sampler2D uShadowMap;\n\
908         \n\
909         uniform bool uAxis;\n\
910         uniform vec3 uAxisColor;\n\
911         uniform bool uCenterPoint;\n\
912         \n\
913         // from http://spidergl.org/example.php?id=6\n\
914         vec4 pack_depth(const in float depth) {\n\
915             const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n\
916             const vec4 bit_mask  = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n\
917             vec4 res = fract(depth * bit_shift);\n\
918             res -= res.xxyz * bit_mask;\n\
919             return res;\n\
920         }\n\
921         float unpack_depth(const in vec4 rgba_depth)\n\
922         {\n\
923             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\
924             float depth = dot(rgba_depth, bit_shift);\n\
925             return depth;\n\
926         }\n\
927         \n\
928         void main() {\n\
929             if (uGenerateShadowMap) {\n\
930                \n\
931                 gl_FragColor = pack_depth(gl_FragCoord.z);\n\
932                 return;\n\
933             }\n\
934             if (uAxis) {\n\
935                 gl_FragColor = vec4(uAxisColor, 1.0);\n\
936                 return;\n\
937             }\n\
938             if (uCenterPoint) {\n\
939                 vec2 uv = gl_PointCoord * 2.0 - 1.0;\n\
940                 float w = dot(uv, uv);\n\
941                 if (w < 0.3 || (w > 0.5 && w < 1.0)) {\n\
942                     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\
943                 } else {\n\
944                     discard;\n\
945                 }\n\
946                 return;\n\
947             }\n\
948         \n\
949            \n\
950             vec3 norm = normalize(vNormal);\n\
951             vec3 cameraDirection = normalize(-vPosition);\n\
952         \n\
953             vec3 color;\n\
954             float alpha = uAlpha;\n\
955         \n\
956             if (uEdge) {\n\
957         \n\
958                 color = uEdgeColor;\n\
959         \n\
960             } else {\n\
961         \n\
962                 color = vec3(1.0, 1.0, 1.0);\n\
963                 if (uUseTexture) {\n\
964                     vec4 texColor = texture2D(uTexture, vTextureCoord);\n\
965                     color *= texColor.rgb;\n\
966                     alpha *= texColor.a;\n\
967                 }\n\
968                 if (uUseSphereMap) {\n\
969                     vec2 sphereCoord = 0.5 * (1.0 + vec2(1.0, -1.0) * norm.xy);\n\
970                     if (uIsSphereMapAdditive) {\n\
971                         color += texture2D(uSphereMap, sphereCoord).rgb;\n\
972                     } else {\n\
973                         color *= texture2D(uSphereMap, sphereCoord).rgb;\n\
974                     }\n\
975                 }\n\
976         \n\
977                \n\
978                 vec3 halfAngle = normalize(uLightDirection + cameraDirection);\n\
979                 float specularWeight = pow( max(0.001, dot(halfAngle, norm)) , uShininess );\n\
980                \n\
981                 vec3 specular = specularWeight * uSpecularColor;\n\
982         \n\
983                 vec2 toonCoord = vec2(0.0, 0.5 * (1.0 - dot( uLightDirection, norm )));\n\
984         \n\
985                 if (uSelfShadow) {\n\
986                     vec3 lightCoord = vLightCoord.xyz / vLightCoord.w;\n\
987                     vec4 rgbaDepth = texture2D(uShadowMap, lightCoord.xy);\n\
988                     float depth = unpack_depth(rgbaDepth);\n\
989                     if (depth < lightCoord.z - 0.01) {\n\
990                         toonCoord = vec2(0.0, 0.55);\n\
991                     }\n\
992                 }\n\
993         \n\
994                 color *= uAmbientColor + uLightColor * (uDiffuseColor + specular);\n\
995         \n\
996                 color = clamp(color, 0.0, 1.0);\n\
997                 color *= texture2D(uToon, toonCoord).rgb;\n\
998         \n\
999             }\n\
1000             gl_FragColor = vec4(color, alpha);\n\
1001         \n\
1002         }\n\
1003     ';
1004 }());
1005