1 /**
  2  * @fileOverview
  3  * gl.enchant.js
  4  * @version 0.3.7
  5  * @require enchant.js v0.4.5+
  6  * @require gl-matrix.js 1.3.7+
  7  * @author UEI Corporation
  8  *
  9  * @description
 10  * Drawing library using WebGL
 11  * By combining with enchant.js, high quality 3D drawing and combination with 2D drawing is possible
 12  *
 13  * @detail
 14  * Uses gl-matrix.js in vector, matrix operation.
 15  * gl-matrix.js:
 16  * https://github.com/toji/gl-matrix/
 17  */
 18 
 19 /**
 20  * Exports gl.enchant.js class to enchant.
 21  */
 22 enchant.gl = {};
 23 
 24 if (typeof glMatrixArrayType === 'undefined') {
 25     throw new Error('should load gl-matrix.js before loading gl.enchant.js');
 26 }
 27 
 28 (function() {
 29 
 30     var CONTEXT_NAME = 'experimental-webgl';
 31 
 32     var parentModule = null;
 33     (function() {
 34         enchant();
 35         if (enchant.nineleap !== undefined) {
 36             if (enchant.nineleap.memory !== undefined &&
 37                 Object.getPrototypeOf(enchant.nineleap.memory) === Object.prototype) {
 38                 parentModule = enchant.nineleap.memory;
 39             } else if (enchant.nineleap !== undefined &&
 40                 Object.getPrototypeOf(enchant.nineleap) === Object.prototype) {
 41                 parentModule = enchant.nineleap;
 42             }
 43         } else {
 44             parentModule = enchant;
 45         }
 46     }());
 47 
 48     enchant.gl.Core = enchant.Class.create(parentModule.Core, {
 49         initialize: function(width, height) {
 50             parentModule.Core.call(this, width, height);
 51             this.GL = new GLUtil();
 52             this.currentScene3D = null;
 53             this.addEventListener('enterframe', function(e) {
 54                 if (!this.currentScene3D) {
 55                     return;
 56                 }
 57                 var nodes = this.currentScene3D.childNodes.slice();
 58                 var push = Array.prototype.push;
 59                 while (nodes.length) {
 60                     var node = nodes.pop();
 61                     node.dispatchEvent(e);
 62                     node.age++;
 63                     if (node.childNodes) {
 64                         push.apply(nodes, node.childNodes);
 65                     }
 66                 }
 67             });
 68         },
 69         debug: function() {
 70             this.GL._enableDebugContext();
 71             this._debug = true;
 72             this.addEventListener("enterframe", function(time) {
 73                 this._actualFps = (1000 / time.elapsed);
 74             });
 75             this.start();
 76         }
 77     });
 78 
 79     var GLUtil = enchant.Class.create({
 80         initialize: function() {
 81             var core = enchant.Core.instance;
 82             if (typeof core.GL !== 'undefined') {
 83                 return core.GL;
 84             }
 85             this._createStage(core.width, core.height, core.scale);
 86             this._prepare();
 87             this.textureManager = new TextureManager();
 88             this.detectColorManager = new DetectColorManager();
 89             this.detectFrameBuffer = new enchant.gl.FrameBuffer(core.width, core.height);
 90             this.defaultProgram = new enchant.gl.Shader(DEFAULT_VERTEX_SHADER_SOURCE, DEFAULT_FRAGMENT_SHADER_SOURCE);
 91             this.setDefaultProgram();
 92         },
 93         setDefaultProgram: function() {
 94             this.setProgram(this.defaultProgram);
 95         },
 96         setProgram: function(program) {
 97             program.use();
 98             this.currentProgram = program;
 99         },
100         _prepare: function() {
101             var width = this._canvas.width;
102             var height = this._canvas.height;
103             gl.clearColor(0.0, 0.0, 0.0, 1.0);
104             gl.viewport(0, 0, width, height);
105             gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
106             gl.enable(gl.DEPTH_TEST);
107             gl.enable(gl.CULL_FACE);
108         },
109         _createStage: function(width, height, scale) {
110             var div = createParentDiv();
111             var that = this;
112             var stage = document.getElementById('enchant-stage');
113             var cvs = this._canvas = createGLCanvas(width, height, scale);
114             var detect = new enchant.Sprite(width, height);
115             var core = enchant.Core.instance;
116             (function() {
117                 var color = new Uint8Array(4);
118                 var touching = null;
119                 var sprite;
120                 detect.addEventListener('touchstart', function(e) {
121                     var scene = core.currentScene3D;
122                     var x = parseInt(e.x, 10);
123                     var y = parseInt(this.height - e.y, 10);
124                     that.detectFrameBuffer.bind();
125                     scene._draw('detect');
126                     gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, color);
127                     sprite = that.detectColorManager.getSpriteByColor(color);
128                     if (sprite) {
129                         touching = sprite;
130                         touching.dispatchEvent(e);
131                     }
132                     that.detectFrameBuffer.unbind();
133                 });
134                 detect.addEventListener('touchmove', function(e) {
135                     if (touching !== null) {
136                         touching.dispatchEvent(e);
137                     }
138                 });
139                 detect.addEventListener('touchend', function(e) {
140                     if (touching !== null) {
141                         touching.dispatchEvent(e);
142                     }
143                     touching = null;
144                 });
145             }());
146             window['gl'] = this._gl = this._getContext(cvs);
147             div.appendChild(cvs);
148             stage.insertBefore(div, core.rootScene._element);
149             core.rootScene.addChild(detect);
150         },
151         _getContext: function(canvas, debug) {
152             var ctx = canvas.getContext(CONTEXT_NAME);
153             if (!ctx) {
154                 window['alert']('could not initialized WebGL');
155                 throw new Error('could not initialized WebGL');
156             }
157             if (debug) {
158                 ctx = createDebugContext(ctx);
159             }
160             return ctx;
161         },
162         _enableDebugContext: function() {
163             window['gl'] = this._gl = createDebugContext(this._gl);
164         },
165         parseColor: function(string) {
166             return parseColor(string);
167         },
168         renderElements: function(buffer, offset, length, attributes, uniforms) {
169             if (attributes) {
170                 this.currentProgram.setAttributes(attributes);
171             }
172             if (uniforms) {
173                 this.currentProgram.setUniforms(uniforms);
174             }
175             buffer.bind();
176             gl.drawElements(gl.TRIANGLES, length, gl.UNSIGNED_SHORT, offset);
177             buffer.unbind();
178         }
179     });
180 
181     var parseColor = function(string) {
182         var color = [];
183         if (typeof string === 'string') {
184             if (string.match(/#/)) {
185                 string.match(/[0-9a-fA-F]{2}/g).forEach(function(n) {
186                     color[color.length] = ('0x' + n - 0) / 255;
187                 });
188                 color[color.length] = 1.0;
189             } else if (string.match(/rgba/)) {
190                 string.match(/[0-9]{1,3},/g).forEach(function(n) {
191                     color[color.length] = parseInt(n, 10) / 255;
192                 });
193                 color[color.length] = parseFloat(string.match(/[0-9]\.[0-9]{1,}/)[0]);
194             } else if (string.match(/rgb/)) {
195                 string.match(/[0-9]{1,3},/g).forEach(function(n) {
196                     color[color.length] = parseInt(n, 10) / 255;
197                 });
198                 color[color.length] = 1.0;
199             }
200         } else if (string instanceof Array) {
201             color = string;
202         }
203         return color;
204     };
205 
206     var createDebugContext = function(context) {
207         var ctx = {};
208         var names = {};
209         var type = '';
210         var val;
211         var makeFakedMethod = function(context, prop) {
212             return function() {
213                 var value, error;
214                 value = context[prop].apply(context, arguments);
215                 error = context.getError();
216                 if (error) {
217                     window['console'].log(names[error] + '(' + error + ')' + ': ' + prop);
218                     window['console'].log(arguments);
219                 }
220                 return value;
221             };
222         };
223         for (var prop in context) {
224             type = typeof context[prop];
225             val = context[prop];
226             if (type === 'function') {
227                 ctx[prop] = makeFakedMethod(context, prop);
228             } else if (type === 'number') {
229                 names[val] = prop;
230                 ctx[prop] = val;
231             } else {
232                 ctx[prop] = val;
233             }
234         }
235         ctx.getNameById = function(i) {
236             return names[i];
237         };
238         return ctx;
239     };
240 
241     var createParentDiv = function() {
242         var div = document.createElement('div');
243         div.style['position'] = 'absolute';
244         div.style['z-index'] = -1;
245         div.style[enchant.ENV.VENDOR_PREFIX + 'TransformOrigin'] = '0 0';
246         return div;
247     };
248 
249     var createGLCanvas = function(width, height, scale) {
250         var cvs = document.createElement('canvas');
251         cvs.width = width;
252         cvs.height = height;
253         cvs.style['position'] = 'absolute';
254         cvs.style['z-index'] = -1;
255         cvs.style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'scale(' + scale + ')';
256         cvs.style[enchant.ENV.VENDOR_PREFIX + 'TransformOrigin'] = '0 0';
257         return cvs;
258     };
259 
260     var TextureManager = enchant.Class.create({
261         initialize: function() {
262             this.storage = {};
263         },
264         hasTexture: function(src) {
265             return src in this.storage;
266         },
267         getWebGLTexture: function(image, flip, wrap, mipmap) {
268             var ret;
269             if (this.hasTexture(image.src)) {
270                 ret = this.storage[image.src];
271             } else {
272                 ret = this.createWebGLTexture(image, flip, wrap, mipmap);
273             }
274             return ret;
275         },
276         isPowerOfTwo: function(n) {
277             return (n > 0) && ((n & (n - 1)) === 0);
278         },
279         setTextureParameter: function(power, target, wrap, mipmap) {
280             var filter;
281             if (mipmap) {
282                 filter = gl.LINEAR_MIPMAP_LINEAR;
283             } else {
284                 filter = gl.NEAREST;
285             }
286             if (!power) {
287                 wrap = gl.CLAMP_TO_EDGE;
288             }
289             gl.texParameteri(target, gl.TEXTURE_WRAP_S, wrap);
290             gl.texParameteri(target, gl.TEXTURE_WRAP_T, wrap);
291             gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, filter);
292             gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, filter);
293         },
294         _texImage: function(image, target) {
295             gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
296         },
297         _writeWebGLTexture: function(image, target, wrap, mipmap) {
298             var power = this.isPowerOfTwo(image.width) && this.isPowerOfTwo(image.height);
299             if (typeof target === 'undefined') {
300                 target = gl.TEXTURE_2D;
301             }
302             if (typeof wrap === 'undefined') {
303                 wrap = gl.REPEAT;
304             }
305             this.setTextureParameter(power, target, wrap, mipmap);
306 
307             this._texImage(image, target);
308             if (mipmap) {
309                 gl.generateMipmap(target);
310             }
311         },
312         createWebGLTexture: function(image, flip, wrap, mipmap) {
313             var tex = gl.createTexture();
314             var target = gl.TEXTURE_2D;
315             gl.bindTexture(target, tex);
316             gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flip);
317             this._writeWebGLTexture(image, target, wrap, mipmap);
318             gl.bindTexture(target, null);
319             this.storage[image.src] = tex;
320             return tex;
321         },
322         createWebGLCubeMapTexture: function(images, wrap, mipmap) {
323             var faceTargets = [
324                 gl.TEXTURE_CUBE_MAP_POSITIVE_X,
325                 gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
326                 gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
327                 gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
328                 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
329                 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
330             ];
331 
332             var tex = gl.createTexture();
333             var target, image;
334             gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
335             gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
336             for (var i = 0, l = images.length; i < l; i++) {
337                 target = faceTargets[i];
338                 image = images[i];
339                 this._writeWebGLTexture(image, target, wrap, mipmap);
340             }
341             gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
342             return tex;
343         }
344     });
345 
346     var DetectColorManager = enchant.Class.create({
347         initialize: function() {
348             this.reference = [];
349             this.detectColorNum = 0;
350         },
351         attachDetectColor: function(sprite) {
352             this.detectColorNum += 1;
353             this.reference[this.detectColorNum] = sprite;
354             return this._createNewColor();
355         },
356         _createNewColor: function() {
357             var n = this.detectColorNum;
358             return [
359                 parseInt(n / 65536, 10) / 255,
360                 parseInt(n / 256, 10) / 255,
361                 parseInt(n % 256, 10) / 255, 1.0
362             ];
363         },
364         _decodeDetectColor: function(color) {
365             return Math.floor(color[0] * 65536) +
366                 Math.floor(color[1] * 256) +
367                 Math.floor(color[2]);
368         },
369         getSpriteByColor: function(color) {
370             return this.reference[this._decodeDetectColor(color)];
371         }
372     });
373 
374     /**
375      * @scope enchant.gl.Framebuffer.prototype
376      */
377     enchant.gl.FrameBuffer = enchant.Class.create({
378         /**
379          * Class for controlling WebGL frame buffers
380          * @param {String} width Frame buffer width
381          * @param {String} height Frame buffer height
382          * @constructs
383          */
384         initialize: function(width, height) {
385             var core = enchant.Core.instance;
386             if (typeof width === 'undefined') {
387                 width = core.width;
388             }
389             if (typeof height === 'undefined') {
390                 height = core.height;
391             }
392             this.framebuffer = gl.createFramebuffer();
393             this.colorbuffer = gl.createRenderbuffer();
394             this.depthbuffer = gl.createRenderbuffer();
395 
396             gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
397 
398             gl.bindRenderbuffer(gl.RENDERBUFFER, this.colorbuffer);
399             gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, width, height);
400             gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.colorbuffer);
401 
402             gl.bindRenderbuffer(gl.RENDERBUFFER, this.depthbuffer);
403             gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
404             gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depthbuffer);
405 
406             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
407             gl.bindRenderbuffer(gl.RENDERBUFFER, null);
408         },
409         /**
410          * Bind frame buffer.
411          */
412         bind: function() {
413             gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
414         },
415         /**
416          * Unbind frame buffer.
417          */
418         unbind: function() {
419             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
420         },
421         /**
422          * Destroy object.
423          */
424         destroy: function() {
425             gl.deleteFramebuffer(this.framebuffer);
426             gl.deleteFramebuffer(this.colorbuffer);
427             gl.deleteFramebuffer(this.depthbuffer);
428         }
429     });
430 
431     /**
432      * @scope enchant.gl.Shader.prototype
433      */
434     enchant.gl.Shader = enchant.Class.create({
435         /**
436          * Class to control WebGL shader program.
437          * A shader program will be created by delivering the vertex shader source and fragment shader source.
438          * @param {String} vshader Vertex shader source
439          * @param {String} fshader Fragment shader source
440          * @constructs
441          */
442         initialize: function(vshader, fshader) {
443             this._vShaderSource = '';
444             this._fShaderSource = '';
445             this._updatedVShaderSource = false;
446             this._updatedFShaderSource = false;
447             this._vShaderProgram = null;
448             this._fShaderProgram = null;
449             this._program = null;
450             this._uniforms = {};
451             this._attributes = {};
452             this._attribLocs = {};
453             this._samplersNum = 0;
454 
455             if (typeof vshader === 'string') {
456                 this.vShaderSource = vshader;
457             }
458             if (typeof fshader === 'string') {
459                 this.fShaderSource = fshader;
460             }
461             if (this._updatedVShaderSource && this._updatedFShaderSource) {
462                 this.compile();
463             }
464         },
465         /**
466          * Vertex shader source
467          * @type String
468          */
469         vShaderSource: {
470             get: function() {
471                 return this._vShaderSource;
472             },
473             set: function(string) {
474                 this._vShaderSource = string;
475                 this._updatedVShaderSource = true;
476             }
477         },
478         /**
479          * Fragment shader source
480          * @type String
481          */
482         fShaderSource: {
483             get: function() {
484                 return this._fShaderSource;
485             },
486             set: function(string) {
487                 this._fShaderSource = string;
488                 this._updatedFShaderSource = true;
489             }
490         },
491         /**
492          * Compile shader program.
493          * Will be automatically compiled when shader source is delivered from constructor.
494          * @example
495          * var shader = new Shader();
496          * // Deliver shader program source.
497          * shader.vShaderSource = vert;
498          * shader.fShaderSource = frag;
499          * // Compile.
500          * shader.compile();
501          */
502         compile: function() {
503             if (this._updatedVShaderSource) {
504                 this._prepareVShader();
505             }
506             if (this._updatedFShaderSource) {
507                 this._prepareFShader();
508             }
509             if (this._program === null) {
510                 this._program = gl.createProgram();
511             } else {
512                 gl.detachShader(this._program, this._vShaderProgram);
513                 gl.detachShader(this._program, this._fShaderProgram);
514             }
515             gl.attachShader(this._program, this._vShaderProgram);
516             gl.attachShader(this._program, this._fShaderProgram);
517             gl.linkProgram(this._program);
518             if (!gl.getProgramParameter(this._program, gl.LINK_STATUS)) {
519                 this._logShadersInfo();
520                 throw 'could not compile shader';
521             }
522             this._getAttributesProperties();
523             this._getUniformsProperties();
524         },
525         /**
526          * Set shader program to be used.
527          */
528         use: function() {
529             gl.useProgram(this._program);
530         },
531         /**
532          * Sets attribute variables to shader program.
533          * Used in enchant.gl.Sprite3D contents and elsewhere.
534          * @param {*} params Level
535          * @example
536          * var shader = new Shader(vert, frag);
537          * shader.setAttributes({
538          *     aVertexPosition: indices,
539          *     aNormal: normals
540          * });
541          */
542         setAttributes: function(params) {
543             for (var prop in params) {
544                 if (params.hasOwnProperty(prop)) {
545                     this._attributes[prop] = params[prop];
546                 }
547             }
548         },
549         /**
550          * Set uniform variables to shader program.
551          * Used in enchant.gl.Sprite3D and elsewhere.
552          * @param {*} params Level
553          * @example
554          * var shader = new Shader(vert, frag);
555          * shader.setUniforms({
556          *     uDiffuse: diffuse,
557          *     uLightColor: lightColor
558          * });
559          */
560         setUniforms: function(params) {
561             for (var prop in params) {
562                 if (params.hasOwnProperty(prop)) {
563                     this._uniforms[prop] = params[prop];
564                 }
565             }
566         },
567         _prepareVShader: function() {
568             if (this._vShaderProgram === null) {
569                 this._vShaderProgram = gl.createShader(gl.VERTEX_SHADER);
570             }
571             gl.shaderSource(this._vShaderProgram, this._vShaderSource);
572             gl.compileShader(this._vShaderProgram);
573             this._updatedVShaderSource = false;
574         },
575         _prepareFShader: function() {
576             if (this._fShaderProgram === null) {
577                 this._fShaderProgram = gl.createShader(gl.FRAGMENT_SHADER);
578             }
579             gl.shaderSource(this._fShaderProgram, this._fShaderSource);
580             gl.compileShader(this._fShaderProgram);
581             this._updatedFShaderSource = false;
582         },
583         _logShadersInfo: function() {
584             window['console'].log(gl.getShaderInfoLog(this._vShaderProgram));
585             window['console'].log(gl.getShaderInfoLog(this._fShaderProgram));
586         },
587         _getAttributesProperties: function() {
588             var n;
589             n = gl.getProgramParameter(this._program, gl.ACTIVE_ATTRIBUTES);
590             for (var i = 0; i < n; i++) {
591                 var info = gl.getActiveAttrib(this._program, i);
592                 this._attribLocs[info.name] = i;
593                 addAttributesProperty(this, info);
594             }
595         },
596         _getUniformsProperties: function() {
597             var n;
598             n = gl.getProgramParameter(this._program, gl.ACTIVE_UNIFORMS);
599             for (var i = 0; i < n; i++) {
600                 var info = gl.getActiveUniform(this._program, i);
601                 addUniformsProperty(this, info);
602             }
603         },
604         /**
605          * Destroy object.
606          */
607         destroy: function() {
608             gl.deleteProgram(this._vShaderProgram);
609             gl.deleteProgram(this._fShaderProgram);
610             gl.deleteProgram(this._program);
611         }
612     });
613 
614     var addAttributesProperty = function(program, info) {
615         var name = info.name;
616         var loc = program._attribLocs[name];
617         /**
618          * @type {Object}
619          * @memberOf Object.
620          */
621         var desc = {
622             get: function() {
623                 return 'attrib';
624             },
625             set: (function(loc) {
626                 return function(buf) {
627                     gl.enableVertexAttribArray(loc);
628                     buf._setToAttrib(loc);
629                 };
630             }(loc))
631         };
632         Object.defineProperty(program._attributes, name, desc);
633     };
634 
635     var addUniformsProperty = function(program, info) {
636         var name = (info.name.slice(-3) === '[0]') ? info.name.slice(0, -3) : info.name;
637         var loc = gl.getUniformLocation(program._program, info.name);
638         var suffix;
639         var sampler = false;
640         var matrix = false;
641         /**
642          * @type {Object}
643          */
644         var desc = {
645             get: function() {
646                 return 'uniform';
647             }
648         };
649         switch (info.type) {
650             case gl.FLOAT:
651                 suffix = '1f';
652                 break;
653 
654             case gl.FLOAT_MAT2:
655                 matrix = true;
656                 /* falls through */
657             case gl.FLOAT_VEC2:
658                 suffix = '2fv';
659                 break;
660 
661             case gl.FLOAT_MAT3:
662                 matrix = true;
663                 /* falls through */
664             case gl.FLOAT_VEC3:
665                 suffix = '3fv';
666                 break;
667 
668             case gl.FLOAT_MAT4:
669                 matrix = true;
670                 /* falls through */
671             case gl.FLOAT_VEC4:
672                 suffix = '4fv';
673                 break;
674 
675             case gl.SAMPLER_2D:
676             case gl.SAMPLER_CUBE:
677                 sampler = true;
678                 /* falls through */
679             case gl.INT:
680             case gl.BOOL:
681                 suffix = '1i';
682                 break;
683 
684             case gl.INT_VEC2:
685             case gl.BOOL_VEC2:
686                 suffix = '2iv';
687                 break;
688 
689             case gl.INT_VEC3:
690             case gl.BOOL_VEC3:
691                 suffix = '3iv';
692                 break;
693 
694             case gl.INT_VEC4:
695             case gl.BOOL_VEC4:
696                 suffix = '4iv';
697                 break;
698             default:
699                 throw new Error('no match');
700         }
701         if (matrix) {
702             desc.set = (function(loc, suffix) {
703                 return function(value) {
704                     gl['uniformMatrix' + suffix](loc, false, value);
705                 };
706             }(loc, suffix));
707         } else if (sampler) {
708             desc.set = (function(loc, suffix, samplersNum) {
709                 return function(texture) {
710                     gl.activeTexture(gl.TEXTURE0 + samplersNum);
711                     gl.bindTexture(gl.TEXTURE_2D, texture._glTexture);
712                     gl['uniform' + suffix](loc, samplersNum);
713                 };
714             }(loc, suffix, program._samplersNum));
715             program._samplersNum++;
716         } else {
717             desc.set = (function(loc, suffix) {
718                 return function(value) {
719                     gl['uniform' + suffix](loc, value);
720                 };
721             }(loc, suffix));
722         }
723         Object.defineProperty(program._uniforms, name, desc);
724     };
725 
726     /**
727      * @scope enchant.gl.Quat.prototype
728      */
729     enchant.gl.Quat = enchant.Class.create({
730         /**
731          * Class that easily uses quaternions.
732          * @param {Number} x
733          * @param {Number} y
734          * @param {Number} z
735          * @param {Number} rad
736          * @constructs
737          */
738         initialize: function(x, y, z, rad) {
739             var l = Math.sqrt(x * x + y * y + z * z);
740             if (l) {
741                 x /= l;
742                 y /= l;
743                 z /= l;
744             }
745             var s = Math.sin(rad / 2);
746             var w = Math.cos(rad / 2);
747             this._quat = quat4.create([x * s, y * s, z * s, w]);
748         },
749 
750         /**
751          * Performs spherical linear interpolation between quarternions.
752          * Calculates quarternion that supplements rotation between this quarternion and another.
753          * Degree of rotation will be expressed in levels from 0 to 1. 0 is the side of this quarternion, 1 is the side of its counterpart.
754          * New instance will be returned.
755          * @param {enchant.gl.Quat} another Quaternion
756          * @param {Number} ratio
757          * @return {enchant.gl.Quat}
758          */
759         slerp: function(another, ratio) {
760             var q = new enchant.gl.Quat(0, 0, 0, 0);
761             quat4.slerp(this._quat, another._quat, ratio, q._quat);
762             return q;
763         },
764         /**
765          * Performs spherical linear interpolation between quarternions.
766          * Calculates quarternion that supplements rotation between this quarternion and another.
767          * Degree of rotation will be expressed in levels from 0 to 1. 0 is the side of this quarternion, 1 is the side of its counterpart.
768          * This side's value will be overwritten.
769          * @param {enchant.gl.Quat} another Quaternion
770          * @param {Number} ratio
771          * @return {enchant.gl.Quat}
772          */
773         slerpApply: function(another, ratio) {
774             quat4.slerp(this._quat, another._quat, ratio);
775             return this;
776         },
777         /**
778          * Convert quarternion to rotation matrix.
779          * @param {Number[]} matrix
780          * @return {Number[]}
781          */
782         toMat4: function(matrix) {
783             quat4.toMat4(this._quat, matrix);
784             return matrix;
785         },
786         /**
787          * Apply quarternion to vector.
788          * @param {Number[]} vector
789          * @return {Number[]}
790          */
791         multiplyVec3: function(vector) {
792             quat4.multiplyVec3(this._quat, vector);
793             return vector;
794         }
795     });
796 
797     /**
798      * @scope enchant.gl.Light3D.prototype
799      */
800     enchant.gl.Light3D = enchant.Class.create(enchant.EventTarget, {
801         /**
802          * Light source class parent class.
803          *
804          * @constructs
805          * @extends enchant.EventTarget
806          */
807         initialize: function() {
808             this._changedColor = true;
809             this._color = [0.8, 0.8, 0.8];
810         },
811 
812         /**
813          * Light source light color
814          * @type Number[]
815          */
816         color: {
817             set: function(array) {
818                 this._color = array;
819                 this._changedColor = true;
820             },
821             get: function() {
822                 return this._color;
823             }
824         }
825     });
826 
827     /**
828      * @scope enchant.gl.AmbientLight.prototype
829      */
830     enchant.gl.AmbientLight = enchant.Class.create(enchant.gl.Light3D, {
831         /**
832          * Class for setting light source in 3D scene.
833          * Environmental Light.
834          * @example
835          *   var scene = new Scene3D();
836          *   var light = new AmbientLight();
837          *   light.color = [1.0, 1.0, 0.0];
838          *   light.directionY = 10;
839          *   scene.setAmbientLight(light);
840          *
841          * @constructs
842          * @extends enchant.gl.Light3D
843          */
844         initialize: function() {
845             enchant.gl.Light3D.call(this);
846         }
847     });
848 
849     /**
850      * @scope enchant.gl.DirectionalLight.prototype
851      */
852     enchant.gl.DirectionalLight = enchant.Class.create(enchant.gl.Light3D, {
853         /**
854          * Class for setting light source in 3D scene.
855          * Directioned light source without position.
856          * @example
857          *   var scene = new Scene3D();
858          *   var light = new DirectionalLight();
859          *   light.color = [1.0, 1.0, 0.0];
860          *   light.directionY = 10;
861          *   scene.setDirectionalLight(light);
862          *
863          * @constructs
864          * @extends enchant.gl.Light3D
865          */
866         initialize: function() {
867             enchant.gl.Light3D.call(this);
868             this._directionX = 0.5;
869             this._directionY = 0.5;
870             this._directionZ = 1.0;
871             this._changedDirection = true;
872         }
873     });
874 
875     /**
876      * Light source exposure direction x component
877      * @type Number
878      */
879     enchant.gl.DirectionalLight.prototype.directionX = 0.5;
880 
881     /**
882      * Light source exposure direction y component
883      * @type Number
884      */
885     enchant.gl.DirectionalLight.prototype.directionY = 0.5;
886 
887     /**
888      * Light source exposure direction z component
889      * @type Number
890      */
891     enchant.gl.DirectionalLight.prototype.directionZ = 1.0;
892 
893     /**
894      * Light source exposure direction
895      * @type {Number}
896      */
897     'directionX directionY directionZ'.split(' ').forEach(function(prop) {
898         Object.defineProperty(enchant.gl.DirectionalLight.prototype, prop, {
899             get: function() {
900                 return this['_' + prop];
901             },
902             set: function(n) {
903                 this['_' + prop] = n;
904                 this._changedDirection = true;
905             }
906         });
907         enchant.gl.DirectionalLight.prototype[prop] = 0;
908     });
909 
910     /**
911      * @scope enchant.gl.PointLight.prototype
912      */
913     enchant.gl.PointLight = enchant.Class.create(enchant.gl.Light3D, {
914         /**
915          * Class that sets 3D scene light source.
916          * Directionless positional light source.
917          * At present, will not be applied even if added to scene.
918          * @example
919          *   var scene = new Scene3D();
920          *   var light = new PointLight();
921          *   light.color = [1.0, 1.0, 0.0];
922          *   light.y = 10;
923          *   scene.addLight(light);
924          *
925          * @constructs
926          * @extends enchant.gl.Light3D
927          */
928         initialize: function() {
929             enchant.gl.Light3D.call(this);
930             this._x = 0;
931             this._y = 0;
932             this._z = 0;
933             this._changedPosition = true;
934         }
935     });
936 
937     /**
938      * Light source x axis
939      * @type Number
940      */
941     enchant.gl.PointLight.prototype.x = 0;
942 
943     /**
944      * Light source y axis
945      * @type Number
946      */
947     enchant.gl.PointLight.prototype.y = 0;
948 
949     /**
950      * Light source z axis
951      * @type Number
952      */
953     enchant.gl.PointLight.prototype.z = 0;
954 
955     'x y z'.split(' ').forEach(function(prop) {
956         Object.defineProperty(enchant.gl.PointLight.prototype, prop, {
957             get: function() {
958                 return this['_' + prop];
959             },
960             set: function(n) {
961                 this['_' + prop] = n;
962                 this._changedPosition = true;
963             }
964         });
965         enchant.gl.PointLight.prototype[prop] = 0;
966     });
967 
968 
969     /**
970      * @scope enchant.gl.Texture.prototype
971      */
972     enchant.gl.Texture = enchant.Class.create({
973         /**
974          * Class to store Sprite3D texture information.
975          * @example
976          *   var sprite = new Sprite3D();
977          *   var texture = new Texture();
978          *   texture.src = "http://example.com/texture.png";
979          *   // Can also be declared as below.
980          *   // var texture = new Texture("http://example.com/texture.png");
981          *   sprite.texture = texture;
982          * @constructs
983          */
984         initialize: function(src, opt) {
985             /**
986              * Ambient light parameter
987              * @type Number[]
988              */
989             this.ambient = [ 0.1, 0.1, 0.1, 1.0 ];
990 
991             /**
992              * Light scattering parameter
993              * @type Number[]
994              */
995             this.diffuse = [ 1.0, 1.0, 1.0, 1.0];
996 
997             /**
998              * Amount of light reflection
999              * @type Number[]
1000              */
1001             this.specular = [ 1.0, 1.0, 1.0, 1.0 ];
1002 
1003             /**
1004              * Amount of luminescence
1005              * @type Number[]
1006              */
1007             this.emission = [ 0.0, 0.0, 0.0, 1.0 ];
1008 
1009             /**
1010              * Specular figures
1011              * @type Number
1012              */
1013             this.shininess = 20;
1014 
1015             this._glTexture = null;
1016             this._image = null;
1017             this._wrap = 10497;
1018             this._mipmap = false;
1019             this._flipY = true;
1020             if (opt) {
1021                 var valid = ['flipY', 'wrap', 'mipmap'];
1022                 for (var prop in opt) {
1023                     if (opt.hasOwnProperty(prop)) {
1024                         if (valid.indexOf(prop) !== -1) {
1025                             this['_' + prop] = opt[prop];
1026                         }
1027                     }
1028                 }
1029             }
1030             if (src) {
1031                 this.src = src;
1032             }
1033         },
1034 
1035         _write: function() {
1036             gl.bindTexture(gl.TEXTURE_2D, this._glTexture);
1037             enchant.Core.instance.GL.textureManager._writeWebGLTexture(this._image, gl.TEXTURE_2D, this._wrap, this._mipmap);
1038             gl.bindTexture(gl.TEXTURE_2D, null);
1039         },
1040 
1041         /**
1042          * Texture image source.
1043          * You can set URL or core.assets data.
1044          * @type String
1045          * @type enchant.Surface
1046          */
1047         src: {
1048             get: function() {
1049                 return this._src;
1050             },
1051             set: function(source) {
1052                 if (typeof source === 'undefined' ||
1053                     source === null) {
1054                     return;
1055                 }
1056                 var that = this;
1057                 var core = enchant.Core.instance;
1058                 var onload = (function(that) {
1059                     return function() {
1060                         that._glTexture = core.GL.textureManager.getWebGLTexture(that._image, that._flipY, that._wrap, that._mipmap);
1061                     };
1062                 }(that));
1063                 if (source instanceof Image) {
1064                     this._image = source;
1065                     onload();
1066                 } else if (source instanceof enchant.Surface) {
1067                     this._image = source._element;
1068                     onload();
1069                 } else if (typeof source === 'string') {
1070                     this._image = new Image();
1071                     this._image.onload = onload;
1072                     this._image.src = source;
1073                 } else {
1074                     this._image = source;
1075                     this._image.src = "c" + Math.random();
1076                     onload();
1077                 }
1078             }
1079         }
1080     });
1081 
1082     /**
1083      * @scope enchant.gl.Buffer.prototype
1084      */
1085     enchant.gl.Buffer = enchant.Class.create({
1086         /**
1087          * Controls peak and other array information.
1088          * Used as enchant.gl.Mesh property.
1089          * @param {*} params parameter
1090          * @param {Number[]} array
1091          *
1092          * @example
1093          * var index = [ 0, 1, 2, 2, 3, 0 ];
1094          * var indices = new Buffer(Buffer.INDICES, index);
1095          *
1096          * @constructs
1097          */
1098         initialize: function(params, array) {
1099             this._setParams(params);
1100             if (typeof array !== 'undefined') {
1101                 this._array = array;
1102             } else {
1103                 this._array = [];
1104             }
1105             this._buffer = null;
1106         },
1107         /**
1108          * Bind buffer.
1109          */
1110         bind: function() {
1111             gl.bindBuffer(this.btype, this._buffer);
1112         },
1113         /**
1114          * Unbind buffer.
1115          */
1116         unbind: function() {
1117             gl.bindBuffer(this.btype, null);
1118         },
1119         _setParams: function(params) {
1120             for (var prop in params) {
1121                 if (params.hasOwnProperty(prop)) {
1122                     this[prop] = params[prop];
1123                 }
1124             }
1125         },
1126         _create: function() {
1127             this._buffer = gl.createBuffer();
1128         },
1129         _delete: function() {
1130             gl.deleteBuffer(this._buffer);
1131         },
1132         _bufferData: function() {
1133             this.bind();
1134             gl.bufferData(this.btype, new this.Atype(this._array), this.usage);
1135             this.unbind();
1136         },
1137         _bufferDataFast: function() {
1138             this.bind();
1139             gl.bufferData(this.btype, this._array, this.usage);
1140             this.unbind();
1141         },
1142         _setToAttrib: function(loc) {
1143             this.bind();
1144             gl.vertexAttribPointer(loc, this.size, this.type, this.norm, this.stride, this.offset);
1145             this.unbind();
1146         },
1147         /**
1148          * Destroy object.
1149          */
1150         destroy: function() {
1151             this._delete();
1152         }
1153     });
1154 
1155     var bufferProto = Object.getPrototypeOf(enchant.gl.Buffer);
1156     bufferProto.VERTICES = bufferProto.NORMALS = {
1157         size: 3,
1158         type: 5126,
1159         norm: false,
1160         stride: 0,
1161         offset: 0,
1162         btype: 34962,
1163         usage: 35044,
1164         Atype: Float32Array
1165     };
1166     bufferProto.TEXCOORDS = {
1167         size: 2,
1168         type: 5126,
1169         normed: false,
1170         stride: 0,
1171         ptr: 0,
1172         btype: 34962,
1173         usage: 35044,
1174         Atype: Float32Array
1175     };
1176     bufferProto.COLORS = {
1177         size: 4,
1178         type: 5126,
1179         normed: false,
1180         stride: 0,
1181         ptr: 0,
1182         btype: 34962,
1183         usage: 35044,
1184         Atype: Float32Array
1185     };
1186     bufferProto.INDICES = {
1187         size: 3,
1188         type: 5123,
1189         normed: false,
1190         stride: 0,
1191         offset: 0,
1192         btype: 34963,
1193         usage: 35044,
1194         Atype: Uint16Array
1195     };
1196 
1197     /**
1198      * @scope enchant.gl.Mesh.prototype
1199      */
1200     enchant.gl.Mesh = enchant.Class.create({
1201         /**
1202          * Class to store peak arrays and textures.
1203          * Used as a sprite property.
1204          * @constructs
1205          */
1206         initialize: function() {
1207             this.__count = 0;
1208             this._appear = false;
1209             this._vertices = new enchant.gl.Buffer(enchant.gl.Buffer.VERTICES);
1210             this._normals = new enchant.gl.Buffer(enchant.gl.Buffer.NORMALS);
1211             this._colors = new enchant.gl.Buffer(enchant.gl.Buffer.COLORS);
1212             this._texCoords = new enchant.gl.Buffer(enchant.gl.Buffer.TEXCOORDS);
1213             this._indices = new enchant.gl.Buffer(enchant.gl.Buffer.INDICES);
1214             this.texture = new enchant.gl.Texture();
1215         },
1216         /**
1217          * Change Mesh color.
1218          * Becomes peak array for Mesh.colors set color.
1219          * @param {Number[]|String} color z Amount of parallel displacement on z axis
1220          * @example
1221          *   var sprite = new Sprite3D();
1222          *   //Sets to purple. All yield the same result.
1223          *   sprite.mesh.setBaseColor([1.0, 0.0, 1.0, 0.0]);
1224          *   sprite.mesh.setBaseColor('#ff00ff');
1225          *   sprite.mesh.setBaseColor('rgb(255, 0, 255');
1226          *   sprite.mesh.setBaseColor('rgba(255, 0, 255, 1.0');
1227          */
1228         setBaseColor: function(color) {
1229             var c = enchant.Core.instance.GL.parseColor(color);
1230             var newColors = [];
1231             for (var i = 0, l = this.vertices.length / 3; i < l; i++) {
1232                 Array.prototype.push.apply(newColors, c);
1233             }
1234             this.colors = newColors;
1235         },
1236         /**
1237          * Reverse direction of the mesh surface and the normal vector.
1238          */
1239         reverse: function() {
1240             var norm = this.normals;
1241             var idx = this.indices;
1242             var t, i, l;
1243             for (i = 0, l = norm.length; i < l; i++) {
1244                 norm[i] *= -1;
1245             }
1246             for (i = 0, l = idx.length; i < l; i += 3) {
1247                 t = idx[i + 1];
1248                 idx[i + 1] = idx[i + 2];
1249                 idx[i + 2] = t;
1250             }
1251             this._normals._bufferData();
1252             this._indices._bufferData();
1253         },
1254         _createBuffer: function() {
1255             for (var prop in this) {
1256                 if (this.hasOwnProperty(prop)) {
1257                     if (this[prop] instanceof enchant.gl.Buffer) {
1258                         this[prop]._create();
1259                         this[prop]._bufferData();
1260                     }
1261                 }
1262             }
1263         },
1264         _deleteBuffer: function() {
1265             for (var prop in this) {
1266                 if (this.hasOwnProperty(prop)) {
1267                     if (this[prop] instanceof enchant.gl.Buffer) {
1268                         this[prop]._delete();
1269                     }
1270                 }
1271             }
1272         },
1273         _controlBuffer: function() {
1274             if (this._appear) {
1275                 if (this.__count <= 0) {
1276                     this._appear = false;
1277                     this._deleteBuffer();
1278                 }
1279             } else {
1280                 if (this.__count > 0) {
1281                     this._appear = true;
1282                     this._createBuffer();
1283                 }
1284             }
1285         },
1286         /**
1287          * @type {Number}
1288          */
1289         _count: {
1290             get: function() {
1291                 return this.__count;
1292             },
1293             set: function(c) {
1294                 this.__count = c;
1295                 this._controlBuffer();
1296             }
1297         },
1298         _join: function(another, ox, oy, oz) {
1299             var triangles = this.vertices.length / 3,
1300                 vertices = this.vertices.slice(0),
1301                 i, l;
1302             for (i = 0, l = another.vertices.length; i < l; i += 3) {
1303                 vertices.push(another.vertices[i] + ox);
1304                 vertices.push(another.vertices[i + 1] + oy);
1305                 vertices.push(another.vertices[i + 2] + oz);
1306             }
1307             this.vertices = vertices;
1308             this.normals = this.normals.concat(another.normals);
1309             this.texCoords = this.texCoords.concat(another.texCoords);
1310             this.colors = this.colors.concat(another.colors);
1311             var indices = this.indices.slice(0);
1312             for (i = 0, l = another.indices.length; i < l; i++) {
1313                 indices.push(another.indices[i] + triangles);
1314             }
1315             this.indices = indices;
1316         },
1317         /**
1318          * Destroy object.
1319          */
1320         destroy: function() {
1321             this._deleteBuffer();
1322         }
1323     });
1324 
1325     /**
1326      * Mesh peak array.
1327      * Sets 3 elements together at peak. The complete number of elements becomes 3n corresponding to the quantity of the peak.
1328      * The 3n, 3n+1, and 3n+2 elements become, respectively, the n peak x, y, and z coordinates.
1329      * @example
1330      *   var sprite = new Sprite3D();
1331      *   //Substitute peak array
1332      *   //Data is stored in an order of x, y, z, x, y, z...
1333      *   sprite.mesh.vertices = [
1334      *       0.0, 0.0, 0.0,  //0 peak (0.0, 0.0, 0.0)
1335      *       1.0, 0.0, 0.0,  //1 peak (1.0, 0.0, 0.0)
1336      *       1.0, 1.0, 0.0,  //2 peak (1.0, 1.0, 0.0)
1337      *       0.0, 1.0, 0.0   //3 peak (0.0, 1.0, 0.0)
1338      *   ];
1339      * @type Number[]
1340      * @see enchant.gl.Mesh#indices
1341      * @see enchant.gl.Mesh#normals
1342      * @see enchant.gl.Mesh#texCoords
1343      */
1344     enchant.gl.Mesh.prototype.vertices = [];
1345 
1346     /**
1347      * Mesh peak normal vector array.
1348      * Sets 3 elements as one in normal vector. The complete element number becomes 3n for normal vector quantity n.
1349      * 3n, 3n+1, and 3n+2 elements are the n level peak x, y, and z elements of the normal vector.
1350      * The normal vector is used in calculations for lighting and shadow.
1351      * @example
1352      *   var sprite = new Sprite3D();
1353      *   //Substitutes peak array
1354      *   //Data is stored in an order of x, y, z, x, y, z...
1355      *   sprite.vertices = [
1356      *       0.0, 0.0, 0.0,  //0 peak (0.0, 0.0, 0.0)
1357      *       1.0, 0.0, 0.0,  //1 peak (1.0, 0.0, 0.0)
1358      *       1.0, 1.0, 0.0,  //2 peak (1.0, 1.0, 0.0)
1359      *       0.0, 1.0, 0.0   //3 peak (0.0, 1.0, 0.0)
1360      *   ];
1361      *
1362      *   //Substitutes normal vector array
1363      *   //Data is a stored in an order of x, y, z, x, y, z...
1364      *   sprite.normals = [
1365      *       0.0, 0.0, 0.0,  //0 level peak normal vector (0.0, 0.0, 0.0)
1366      *       1.0, 0.0, 0.0,  //1 level peak normal vector (1.0, 0.0, 0.0)
1367      *       1.0, 1.0, 0.0,  //2 level peak normal vector (1.0, 1.0, 0.0)
1368      *       0.0, 1.0, 0.0   //3 level peak normal vector (0.0, 1.0, 0.0)
1369      *   ];
1370      * @type Number[]
1371      * @see enchant.gl.Mesh#vertices
1372      * @see enchant.gl.Mesh#indices
1373      * @see enchant.gl.Mesh#texCoords
1374      */
1375     enchant.gl.Mesh.prototype.normals = [];
1376 
1377     /**
1378      * Mesh texture mapping array.
1379      * Sets two elements as one in uv coordinates. The total number of elements becomes 2n in response to the peak quantity.
1380      * 2n, 2n+1 level elements correspond to n level peak texture u, v coordinates.
1381      * The coordinates that can be acquired for each coordinate correspond to 0<=u, v<=1.
1382      * @example
1383      *   var sprite = new Sprite3D();
1384      *   var texture = new Texture();
1385      *   texture.src = "texture.png";
1386      *   sprite.mesh.texture = texture;
1387      *
1388      *   //Substitutes peak level
1389      *   //Data is stored in an order of x, y, z, x, y, z...
1390      *   sprite.vertices = [
1391      *       0.0, 0.0, 0.0,  //0 peak (0.0, 0.0, 0.0)
1392      *       1.0, 0.0, 0.0,  //1 peak (1.0, 0.0, 0.0)
1393      *       1.0, 1.0, 0.0,  //2 peak (1.0, 1.0, 0.0)
1394      *       0.0, 1.0, 0.0   //3 peak (0.0, 1.0, 0.0)
1395      *   ];
1396      *
1397      *   //Substitutes uv coordinate array
1398      *   //Data is stored in an order of u, v, u, v...
1399      *   sprite.texCoords = [
1400      *       0.0, 0.0,  //0番目の頂点のuv座標(0.0, 0.0)
1401      *       1.0, 0.0,  //1番目の頂点のuv座標(1.0, 0.0)
1402      *       1.0, 1.0,  //2番目の頂点のuv座標(1.0, 1.0)
1403      *       0.0, 1.0   //3番目の頂点のuv座標(0.0, 1.0)
1404      *   ];
1405      * @type Number[]
1406      * @see enchant.gl.Mesh#vertices
1407      * @see enchant.gl.Mesh#indices
1408      * @see enchant.gl.Mesh#normals
1409      * @see enchant.gl.Mesh#texture#
1410      */
1411     enchant.gl.Mesh.prototype.texCoords = [];
1412 
1413     /**
1414      * Sprite3D peak index array.
1415      * 3 elements are set as one in a triangle. The total number of elements becomes 3n corresponding to the triangle's total quantity n.
1416      * Index level is the peak number designated in {@link enchant.gl.Sprite3D#vertices}.
1417      * @example
1418      *   var sprite = new Sprite3D();
1419      *   //Substitutes peak array
1420      *   //Data is stored in an order of x, y, z, x, y, z...
1421      *   sprite.vertices = [
1422      *       0.0, 0.0, 0.0,  //0 peak (0.0, 0.0, 0.0)
1423      *       1.0, 0.0, 0.0,  //1 peak (1.0, 0.0, 0.0)
1424      *       1.0, 1.0, 0.0,  //2 peak (1.0, 1.0, 0.0)
1425      *       0.0, 1.0, 0.0   //3 peak (0.0, 1.0, 0.0)
1426      *   ];
1427      *
1428      *   //Substitutes peak index
1429      *   //Draws triangle with 3 elements as one
1430      *   //In this example the two triangles (0,0,0), (1,0,0), (1,1,0) and
1431      *   //(1,1,0), (0,1,0), (0,0,0) are drawn.
1432      *   sprite.indices = [
1433      *       0, 1, 2,
1434      *       2, 3, 0
1435      *   ];
1436      *   var scene = new Scene3D();
1437      *   scene.addChild(sprite);
1438      * @type Integer[]
1439      * @see enchant.gl.Mesh#vertices
1440      * @see enchant.gl.Mesh#normals
1441      * @see enchant.gl.Mesh#texCoords
1442      */
1443     enchant.gl.Mesh.prototype.indices = [];
1444 
1445     /**
1446      * Mesh peak color array.
1447      * The 4 elements are set as one peak color. The entire number of elements becomes 4n corresponding to the peak quantity n.
1448      * The 4n, 4n+1, 4n+2, and 4n+3 elements are the n level peak colors r, g, b, a.
1449      * Peak color is used for drawing when Texture is not assigned to Sprite3D Texture.
1450      * {@link enchant.gl.Mesh#setBaseColor} can be used to bundle together and change.
1451      * @example
1452      *   var sprite = new Sprite3D();
1453      *   //Substitutes peak array
1454      *   //Data is stored in an order of x, y, z, x, y, z...
1455      *   sprite.vertices = [
1456      *       0.0, 0.0, 0.0,  //0 peak (0.0, 0.0, 0.0)
1457      *       1.0, 0.0, 0.0,  //1 peak (1.0, 0.0, 0.0)
1458      *       1.0, 1.0, 0.0,  //2 peak (1.0, 1.0, 0.0)
1459      *       0.0, 1.0, 0.0   //3 peak (0.0, 1.0, 0.0)
1460      *   ];
1461      *
1462      *   //Substitutes peak level array
1463      *   //Data is stored in an order of r, g, b, a, r, g, b, a...
1464      *   sprite.normals = [
1465      *       0.0, 0.0, 1.0, 1.0, //0 peak color (0.0, 0.0, 1.0, 1.0)
1466      *       0.0, 1.0, 0.0, 1.0, //1 peak color (0.0, 1.0, 0.0, 1.0)
1467      *       0.0, 1.0, 1.0, 1.0, //2 peak color (0.0, 1.0, 1.0, 1.0)
1468      *       1.0, 0.0, 0.0, 1.0  //3 peak color (1.0, 0.0, 0.0, 1.0)
1469      *   ];
1470      * @type Number[]
1471      * @see enchant.gl.Mesh#setBaseColor
1472      */
1473     enchant.gl.Mesh.prototype.colors = [];
1474 
1475     'vertices normals colors texCoords indices'.split(' ').forEach(function(prop) {
1476         Object.defineProperty(enchant.gl.Mesh.prototype, prop, {
1477             get: function() {
1478                 return this['_' + prop]._array;
1479             },
1480             set: function(array) {
1481                 this['_' + prop]._array = array;
1482                 if (this._appear) {
1483                     this['_' + prop]._bufferData();
1484                 }
1485             }
1486         });
1487     });
1488 
1489     /**
1490      * @scope enchant.gl.Sprite3D.prototype
1491      */
1492     enchant.gl.Sprite3D = enchant.Class.create(enchant.EventTarget, {
1493         /**
1494          * Class with Sprite3D display function.
1495          * <p>By adding {@link enchant.gl.Scene3D} instance, you can display atop an image.
1496          * By changing {@link enchant.gl.Sprite3D#vertices}, {@link enchant.gl.Sprite3D#indices},
1497          * {@link enchant.gl.Sprite3D#normals} and others, you can freely draw Sprite3D,
1498          * as well as pasting texture and more.</p>
1499          * <p>In addition, it is also possible to add Sprite3D as a child, and all child classes will be drawn with coordinates based on their parents.</p>
1500          * @example
1501          *   //Scene initialization
1502          *   var scene = new Scene3D();
1503          *   //Sprite3D initialization
1504          *   var sprite = new Sprite3D();
1505          *   //Add Sprite3D to scene
1506          *   scene.addChild(sprite);
1507          * @constructs
1508          * @extends enchant.EventTarget
1509          */
1510         initialize: function() {
1511             enchant.EventTarget.call(this);
1512 
1513             /**
1514              * Array for child Sprite 3D element.
1515              * Can acquire list of Sprite3Ds added as child classes to this element.
1516              * When adding or subtracting child classes, without directly operating this array,
1517              * {@link enchant.gl.Sprite3D#addChild} or {@link enchant.gl.Sprite3D#removeChild} is used.
1518              * @type enchant.gl.Sprite3D[]
1519              * @see enchant.gl.Sprite3D#addChild
1520              * @see enchant.gl.Sprite3D#removeChild
1521              */
1522             this.childNodes = [];
1523 
1524             /**
1525              * The scene object currently added by this Sprite3D.
1526              * When no scene is added this is null.
1527              * @type enchant.gl.Scene3D
1528              * @see enchant.gl.Scene3D#addChild
1529              */
1530             this.scene = null;
1531 
1532             /**
1533              * Sprite3D parent element.
1534              * When no parent exists this is null.
1535              * @type enchant.gl.Sprite3D|enchant.gl.Scene3D
1536              */
1537             this.parentNode = null;
1538 
1539             /**
1540              * Mesh object applied to Sprite3D.
1541              * @type enchant.gl.Mesh
1542              * @example
1543              *   var sprite = new Sprite3D();
1544              *   sprite.mesh = new Mesh();
1545              */
1546             this._mesh = null;
1547 
1548             this.program = null;
1549 
1550             this.bounding = new enchant.gl.collision.BS();
1551             this.bounding.parent = this;
1552 
1553             this.age = 0;
1554 
1555             this._x = 0;
1556             this._y = 0;
1557             this._z = 0;
1558             this._scaleX = 1;
1559             this._scaleY = 1;
1560             this._scaleZ = 1;
1561             this._changedTranslation = true;
1562             this._changedRotation = true;
1563             this._changedScale = true;
1564             this._touchable = true;
1565 
1566             this._global = vec3.create();
1567             this.globalX = 0;
1568             this.globalY = 0;
1569             this.globalZ = 0;
1570 
1571             this._matrix = mat4.identity();
1572             this.tmpMat = mat4.identity();
1573             this.modelMat = mat4.identity();
1574             this._rotation = mat4.identity();
1575             this._normMat = mat3.identity();
1576 
1577             var core = enchant.Core.instance;
1578             this.detectColor = core.GL.detectColorManager.attachDetectColor(this);
1579 
1580             var parentEvent = function(e) {
1581                 if (this.parentNode instanceof enchant.gl.Sprite3D) {
1582                     this.parentNode.dispatchEvent(e);
1583                 }
1584             };
1585             this.addEventListener('touchstart', parentEvent);
1586             this.addEventListener('touchmove', parentEvent);
1587             this.addEventListener('touchend', parentEvent);
1588 
1589             var added = function(e) {
1590                 if (this.mesh !== null) {
1591                     this.mesh._count++;
1592                 }
1593                 if (this.childNodes.length) {
1594                     for (var i = 0, l = this.childNodes.length; i < l; i++) {
1595                         this.childNodes[i].scene = this.scene;
1596                         this.childNodes[i].dispatchEvent(e);
1597                     }
1598                 }
1599             };
1600             this.addEventListener('addedtoscene', added);
1601 
1602             var removed = function(e) {
1603                 if (this.mesh !== null) {
1604                     this.mesh._count--;
1605                 }
1606                 if (this.childNodes.length) {
1607                     for (var i = 0, l = this.childNodes.length; i < l; i++) {
1608                         this.childNodes[i].scene = null;
1609                         this.childNodes[i].dispatchEvent(e);
1610                     }
1611                 }
1612             };
1613             this.addEventListener('removedfromscene', removed);
1614 
1615         },
1616 
1617         /**
1618          * Executes the reproduction of Sprite3D.
1619          * Position, rotation line, and others will be returned to a copied, new instance.
1620          * @example
1621          *   var sp = new Sprite3D();
1622          *   sp.x = 15;
1623          *   var sp2 = sp.clone();
1624          *   //sp2.x = 15;
1625          * @return {enchant.gl.Sprite3D}
1626          */
1627         clone: function() {
1628             var clone = new enchant.gl.Sprite3D();
1629             for (var prop in this) {
1630                 if (typeof this[prop] === 'number' ||
1631                     typeof this[prop] === 'string') {
1632                     clone[prop] = this[prop];
1633                 } else if (this[prop] instanceof WebGLBuffer) {
1634                     clone[prop] = this[prop];
1635                 } else if (this[prop] instanceof Float32Array) {
1636                     clone[prop] = new Float32Array(this[prop]);
1637                 } else if (this[prop] instanceof Array &&
1638                     prop !== 'childNodes' &&
1639                     prop !== 'detectColor') {
1640                     clone[prop] = this[prop].slice(0);
1641                 }
1642             }
1643             if (this.mesh !== null) {
1644                 clone.mesh = this.mesh;
1645             }
1646             if (this.childNodes) {
1647                 for (var i = 0, l = this.childNodes.length; i < l; i++) {
1648                     clone.addChild(this.childNodes[i].clone());
1649                 }
1650             }
1651             return clone;
1652         },
1653 
1654         /**
1655          * Sets condition of other Sprite3D.
1656          * Can be used corresponding Collada file's loaded assets.
1657          * @example
1658          *   var sp = new Sprite3D();
1659          *   sp.set(core.assets['sample.dae']);
1660          *   //Becomes Sprite3D with sample.dae model information
1661          */
1662         set: function(sprite) {
1663             for (var prop in sprite) {
1664                 if (typeof sprite[prop] === 'number' ||
1665                     typeof sprite[prop] === 'string') {
1666                     this[prop] = sprite[prop];
1667                 } else if (sprite[prop] instanceof WebGLBuffer) {
1668                     this[prop] = sprite[prop];
1669                 } else if (sprite[prop] instanceof Float32Array) {
1670                     this[prop] = new Float32Array(sprite[prop]);
1671                 } else if (sprite[prop] instanceof Array &&
1672                     prop !== 'childNodes' &&
1673                     prop !== 'detectColor') {
1674                     this[prop] = sprite[prop].slice(0);
1675                 }
1676             }
1677             if (sprite.mesh !== null) {
1678                 this.mesh = sprite.mesh;
1679             }
1680             if (sprite.childNodes) {
1681                 for (var i = 0, l = sprite.childNodes.length; i < l; i++) {
1682                     this.addChild(sprite.childNodes[i].clone());
1683                 }
1684             }
1685         },
1686 
1687         /**
1688          * Add child Sprite3D.
1689          * When it is added, an "added" event will be created for child Sprite3D.
1690          * When a parent is already added to scene, it will be added to scene,
1691          * and an "addedtoscene" event will be created.
1692          * Child Sprite3D for adding @param {enchant.gl.Sprite3D} sprite.
1693          * @example
1694          *   var parent = new Sprite3D();
1695          *   var child = new Sprite3D();
1696          *   //Add Sprite3D as child to another Sprite3D
1697          *   parent.addChild(child);
1698          * @see enchant.gl.Sprite3D#removeChild
1699          * @see enchant.gl.Sprite3D#childNodes
1700          * @see enchant.gl.Sprite3D#parentNode
1701          */
1702         addChild: function(sprite) {
1703             this.childNodes.push(sprite);
1704             sprite.parentNode = this;
1705             sprite.dispatchEvent(new enchant.Event('added'));
1706             if (this.scene) {
1707                 sprite.scene = this.scene;
1708                 sprite.dispatchEvent(new enchant.Event('addedtoscene'));
1709             }
1710         },
1711 
1712         /**
1713          * Deletes designated child Sprite3D.
1714          * When deletion is complete, a "removed" event will be created for child Sprite3D.
1715          * When added to scene, it will be deleted from that scene,
1716          * and a "removedfromscene" event will be created.
1717          * Child Sprite3D for deleting @param {enchant.gl.Sprite3D} sprite.
1718          * @example
1719          *   var scene = new Scene3D();
1720          *   //Deletes scene's first child
1721          *   scene.removeChild(scene.childNodes[0]);
1722          * @see enchant.gl.Sprite3D#addChild
1723          * @see enchant.gl.Sprite3D#childNodes
1724          * @see enchant.gl.Sprite3D#parentNode
1725          */
1726         removeChild: function(sprite) {
1727             var i;
1728             if ((i = this.childNodes.indexOf(sprite)) !== -1) {
1729                 this.childNodes.splice(i, 1);
1730                 sprite.parentNode = null;
1731                 sprite.dispatchEvent(new enchant.Event('removed'));
1732                 if (this.scene) {
1733                     sprite.scene = null;
1734                     sprite.dispatchEvent(new enchant.Event('removedfromscene'));
1735                 }
1736             }
1737         },
1738 
1739 
1740         /**
1741          * Other object collison detection.
1742          * Can detect collisions with collision detection objects with x, y, z properties.
1743          * @param {enchant.gl.Sprite3D} bounding Target object
1744          * @return {Boolean}
1745          */
1746         intersect: function(another) {
1747             return this.bounding.intersect(another.bounding);
1748         },
1749 
1750         /**
1751          * Parallel displacement of Sprite3D.
1752          * Displaces each coordinate a designated amount from its current location.
1753          * @param {Number} x Parallel displacement of x axis
1754          * @param {Number} y Parallel displacement of y axis
1755          * @param {Number} z Parallel displacement of z axis
1756          * @example
1757          *   var sprite = new Sprite3D();
1758          *   //Parallel displacement by 10 along the x axis, 3 along the y axis, and -20 along the z axis
1759          *   sprite.translate(10, 3, -20);
1760          * @see enchant.gl.Sprite3D#x
1761          * @see enchant.gl.Sprite3D#y
1762          * @see enchant.gl.Sprite3D#z
1763          * @see enchant.gl.Sprite3D#scale
1764          */
1765         translate: function(x, y, z) {
1766             this._x += x;
1767             this._y += y;
1768             this._z += z;
1769             this._changedTranslation = true;
1770         },
1771 
1772         /**
1773          * Moves forward Sprite3D.
1774          * @param {Number} speed
1775          */
1776         forward: function(speed) {
1777             var x = this._rotation[8] * speed;
1778             var y = this._rotation[9] * speed;
1779             var z = this._rotation[10] * speed;
1780             this.translate(x, y, z);
1781         },
1782 
1783         /**
1784          * Moves side Sprite3D.
1785          * @param {Number} speed
1786          */
1787         sidestep: function(speed) {
1788             var x = this._rotation[0] * speed;
1789             var y = this._rotation[1] * speed;
1790             var z = this._rotation[2] * speed;
1791             this.translate(x, y, z);
1792         },
1793 
1794         /**
1795          * Moves up Sprite3D.
1796          * @param {Number} speed
1797          */
1798         altitude: function(speed) {
1799             var x = this._rotation[4] * speed;
1800             var y = this._rotation[5] * speed;
1801             var z = this._rotation[6] * speed;
1802             this.translate(x, y, z);
1803         },
1804 
1805         /**
1806          * Expand or contract Sprite3D.
1807          * Expands each axis by a designated expansion rate.
1808          * @param {Number} x x axis expansion rate
1809          * @param {Number} y y axis expansion rate
1810          * @param {Number} z z axis expansion rate
1811          * @example
1812          *   var sprite = new Sprite3D();
1813          *   //Expand x axis by 2.0 times, y axis by 3.0 times, and z axis by 0.5 times
1814          *   sprite.scale(2,0, 3.0, 0.5);
1815          * @see enchant.gl.Sprite3D#scaleX
1816          * @see enchant.gl.Sprite3D#scaleY
1817          * @see enchant.gl.Sprite3D#scaleZ
1818          * @see enchant.gl.Sprite3D#translate
1819          */
1820         scale: function(x, y, z) {
1821             this._scaleX *= x;
1822             this._scaleY *= y;
1823             this._scaleZ *= z;
1824             this._changedScale = true;
1825         },
1826 
1827         /**
1828          * Sprite3D name
1829          * @type String
1830          */
1831         name: {
1832             get: function() {
1833                 return this._name;
1834             },
1835             set: function(name) {
1836                 this._name = name;
1837             }
1838         },
1839 
1840         /**
1841          * Sprite3D rotation line.
1842          * Array is a one-dimensional array of length 16, interpreted as the 4x4 line destination.
1843          * @example
1844          *   var sprite = new Sprite3D();
1845          *   //45 degree rotation along the x axis
1846          *   var rotX = Math.PI() / 4;
1847          *   sprite.rotation = [
1848          *       1, 0, 0, 0,
1849          *       0, Math.cos(rotX), -Math.sin(rotX), 0,
1850          *       0, Math.sin(rotX), Math.cos(rotX), 0,
1851          *       0, 0, 0, 1
1852          *   ];
1853          * @type Number[]
1854          */
1855         rotation: {
1856             get: function() {
1857                 return this._rotation;
1858             },
1859             set: function(rotation) {
1860                 this._rotation = rotation;
1861                 this._changedRotation = true;
1862             }
1863         },
1864 
1865         /**
1866          * Sets rotation line in rotation line received from quarterion.
1867          * @param {enchant.gl.Quat} quat
1868          */
1869         rotationSet: function(quat) {
1870             quat.toMat4(this._rotation);
1871             this._changedRotation = true;
1872         },
1873 
1874         /**
1875          * Applies rotation line in rotation line received from quarterion.
1876          * @type {enchant.gl.Quat} quat
1877          */
1878         rotationApply: function(quat) {
1879             quat.toMat4(this.tmpMat);
1880             mat4.multiply(this._rotation, this.tmpMat);
1881             this._changedRotation = true;
1882         },
1883 
1884         /**
1885          * Rotate Sprite3D in local Z acxis.
1886          * @param {Number} radius
1887          */
1888         rotateRoll: function(rad) {
1889             this.rotationApply(new enchant.gl.Quat(0, 0, 1, rad));
1890             this._changedRotation = true;
1891         },
1892 
1893         /**
1894          * Rotate Sprite3D in local X acxis.
1895          * @param {Number} radius
1896          */
1897         rotatePitch: function(rad) {
1898             this.rotationApply(new enchant.gl.Quat(1, 0, 0, rad));
1899             this._changedRotation = true;
1900         },
1901 
1902         /**
1903          * Rotate Sprite3D in local Y acxis.
1904          * @param {Number} radius
1905          */
1906         rotateYaw: function(rad) {
1907             this.rotationApply(new enchant.gl.Quat(0, 1, 0, rad));
1908             this._changedRotation = true;
1909         },
1910 
1911         /**
1912          * @type {enchant.gl.Mesh}
1913          */
1914         mesh: {
1915             get: function() {
1916                 return this._mesh;
1917             },
1918             set: function(mesh) {
1919                 if (this.scene !== null) {
1920                     this._mesh._count -= 1;
1921                     mesh._count += 1;
1922                 }
1923                 this._mesh = mesh;
1924             }
1925         },
1926 
1927         /**
1928          * Conversion line applied to Sprite3D.
1929          * @deprecated
1930          * @type Number[]
1931          */
1932         matrix: {
1933             get: function() {
1934                 return this._matrix;
1935             },
1936             set: function(matrix) {
1937                 this._matrix = matrix;
1938             }
1939         },
1940 
1941         /**
1942          * Object used in Sprite3D collision detection.
1943          * @type enchant.gl.Bounding | enchant.gl.BS | enchant.gl.AABB
1944          */
1945         bounding: {
1946             get: function() {
1947                 return this._bounding;
1948             },
1949             set: function(bounding) {
1950                 this._bounding = bounding;
1951                 this._bounding.parent = this;
1952             }
1953         },
1954 
1955         /**
1956          * Determine whether to make Sprite3D touch compatible.
1957          * If set to false, will be ignored each time touch detection occurs.
1958          * @type bool
1959          */
1960         touchable: {
1961             get: function() {
1962                 return this._touchable;
1963             },
1964             set: function(bool) {
1965                 this._touchable = bool;
1966                 if (this._touchable) {
1967                     this.detectColor[3] = 1.0;
1968                 } else {
1969                     this.detectColor[3] = 0.0;
1970                 }
1971             }
1972         },
1973 
1974         _transform: function(baseMatrix) {
1975             if (this._changedTranslation ||
1976                 this._changedRotation ||
1977                 this._changedScale) {
1978                 mat4.identity(this.modelMat);
1979                 mat4.translate(this.modelMat, [this._x, this._y, this._z]);
1980                 mat4.multiply(this.modelMat, this._rotation, this.modelMat);
1981                 mat4.scale(this.modelMat, [this._scaleX, this._scaleY, this._scaleZ]);
1982                 mat4.multiply(this.modelMat, this._matrix, this.modelMat);
1983                 this._changedTranslation = false;
1984                 this._changedRotation = false;
1985                 this._changedScale = false;
1986             }
1987 
1988             mat4.multiply(baseMatrix, this.modelMat, this.tmpMat);
1989 
1990             this._global[0] = this._x;
1991             this._global[1] = this._y;
1992             this._global[2] = this._z;
1993             mat4.multiplyVec3(this.tmpMat, this._global);
1994             this.globalX = this._global[0];
1995             this.globalY = this._global[1];
1996             this.globalZ = this._global[2];
1997         },
1998 
1999         _render: function(detectTouch) {
2000             var useTexture = this.mesh.texture._image ? 1.0 : 0.0;
2001 
2002             mat4.toInverseMat3(this.tmpMat, this._normMat);
2003             mat3.transpose(this._normMat);
2004 
2005             var attributes = {
2006                 aVertexPosition: this.mesh._vertices,
2007                 aVertexColor: this.mesh._colors,
2008                 aNormal: this.mesh._normals,
2009                 aTextureCoord: this.mesh._texCoords
2010             };
2011 
2012             var uniforms = {
2013                 uModelMat: this.tmpMat,
2014                 uDetectColor: this.detectColor,
2015                 uSpecular: this.mesh.texture.specular,
2016                 uDiffuse: this.mesh.texture.diffuse,
2017                 uEmission: this.mesh.texture.emission,
2018                 uAmbient: this.mesh.texture.ambient,
2019                 uShininess: this.mesh.texture.shininess,
2020                 uNormMat: this._normMat,
2021                 uSampler: this.mesh.texture,
2022                 uUseTexture: useTexture
2023             };
2024 
2025             var length = this.mesh.indices.length;
2026             enchant.Core.instance.GL.renderElements(this.mesh._indices, 0, length, attributes, uniforms);
2027         },
2028 
2029         _draw: function(scene, detectTouch, baseMatrix) {
2030 
2031             this._transform(baseMatrix);
2032 
2033             if (this.childNodes.length) {
2034                 for (var i = 0, l = this.childNodes.length; i < l; i++) {
2035                     this.childNodes[i]._draw(scene, detectTouch, this.tmpMat);
2036                 }
2037             }
2038 
2039             this.dispatchEvent(new enchant.Event('prerender'));
2040 
2041             if (this.mesh !== null) {
2042                 if (this.program !== null) {
2043                     enchant.Core.instance.GL.setProgram(this.program);
2044                     this._render(detectTouch);
2045                     enchant.Core.instance.GL.setDefaultProgram();
2046                 } else {
2047                     this._render(detectTouch);
2048                 }
2049             }
2050 
2051             this.dispatchEvent(new enchant.Event('render'));
2052         }
2053     });
2054 
2055     /**
2056      * Sprite3D x coordinates.
2057      * @default 0
2058      * @type Number
2059      * @see enchant.gl.Sprite3D#translate
2060      */
2061     enchant.gl.Sprite3D.prototype.x = 0;
2062 
2063     /**
2064      * Sprite3D y coordinates.
2065      * @default 0
2066      * @type Number
2067      * @see enchant.gl.Sprite3D#translate
2068      */
2069     enchant.gl.Sprite3D.prototype.y = 0;
2070 
2071     /**
2072      * Sprite3D z coordinates.
2073      * @default 0
2074      * @type Number
2075      * @see enchant.gl.Sprite3D#translate
2076      */
2077     enchant.gl.Sprite3D.prototype.z = 0;
2078 
2079     'x y z'.split(' ').forEach(function(prop) {
2080         Object.defineProperty(enchant.gl.Sprite3D.prototype, prop, {
2081             get: function() {
2082                 return this['_' + prop];
2083             },
2084             set: function(n) {
2085                 this['_' + prop] = n;
2086                 this._changedTranslation = true;
2087             }
2088         });
2089     });
2090 
2091     /**
2092      * Sprite3D x axis direction expansion rate
2093      * @default 1.0
2094      * @type Number
2095      * @see enchant.gl.Sprite3D#scale
2096      */
2097     enchant.gl.Sprite3D.prototype.scaleX = 1;
2098 
2099     /**
2100      * Sprite3D y axis direction expansion rate
2101      * @default 1.0
2102      * @type Number
2103      * @see enchant.gl.Sprite3D#scale
2104      */
2105     enchant.gl.Sprite3D.prototype.scaleY = 1;
2106     /**
2107      * Sprite3D z axis direction expansion rate
2108      * @default 1.0
2109      * @type Number
2110      * @see enchant.gl.Sprite3D#scale
2111      */
2112     enchant.gl.Sprite3D.prototype.scaleZ = 1;
2113 
2114     'scaleX scaleY scaleZ'.split(' ').forEach(function(prop) {
2115         Object.defineProperty(enchant.gl.Sprite3D.prototype, prop, {
2116             get: function() {
2117                 return this['_' + prop];
2118             },
2119             set: function(scale) {
2120                 this['_' + prop] = scale;
2121                 this._changedScale = true;
2122             }
2123         });
2124     });
2125 
2126     /**
2127      * Sprite3D global x coordinates.
2128      * @default 0
2129      * @type Number
2130      * @see enchant.gl.Sprite3D#translate
2131      */
2132     enchant.gl.Sprite3D.prototype.globalX = 0;
2133 
2134     /**
2135      * Sprite 3D global y coordinates.
2136      * @default 0
2137      * @type Number
2138      * @see enchant.gl.Sprite3D#translate
2139      */
2140     enchant.gl.Sprite3D.prototype.globalY = 0;
2141 
2142     /**
2143      * Sprite3D global 3D coordinates.
2144      * @default 0
2145      * @type Number
2146      * @see enchant.gl.Sprite3D#translate
2147      */
2148     enchant.gl.Sprite3D.prototype.globalZ = 0;
2149 
2150     /**
2151      * @scope enchant.gl.Camera3D.prototype
2152      */
2153     enchant.gl.Camera3D = enchant.Class.create({
2154         /**
2155          * Class to set 3D scene camera
2156          * @example
2157          * var scene = new Scene3D();
2158          * var camera = new Camera3D();
2159          * camera.x = 0;
2160          * camera.y = 0;
2161          * camera.z = 10;
2162          * scene.setCamera(camera);
2163          * @constructs
2164          */
2165         initialize: function() {
2166             var core = enchant.Core.instance;
2167             this.mat = mat4.identity();
2168             this.invMat = mat4.identity();
2169             this.invMatY = mat4.identity();
2170             this._projMat = mat4.create();
2171             mat4.perspective(20, core.width / core.height, 1.0, 1000.0, this._projMat);
2172             this._changedPosition = false;
2173             this._changedCenter = false;
2174             this._changedUpVector = false;
2175             this._changedProjection = false;
2176             this._x = 0;
2177             this._y = 0;
2178             this._z = 10;
2179             this._centerX = 0;
2180             this._centerY = 0;
2181             this._centerZ = 0;
2182             this._upVectorX = 0;
2183             this._upVectorY = 1;
2184             this._upVectorZ = 0;
2185         },
2186         /**
2187          * projection matrix
2188          */
2189         projMat: {
2190             get: function() {
2191                 return this._projMat;
2192             },
2193             set: function(mat) {
2194                 this._projMat = mat;
2195                 this._changedProjection = true;
2196             }
2197         },
2198         /**
2199          * Fit camera perspective to Sprite3D position.
2200          * @param {enchant.gl.Sprite3D} sprite Sprite3D being focused on
2201          */
2202         lookAt: function(sprite) {
2203             if (sprite instanceof enchant.gl.Sprite3D) {
2204                 this._centerX = sprite.x;
2205                 this._centerY = sprite.y;
2206                 this._centerZ = sprite.z;
2207                 this._changedCenter = true;
2208             }
2209         },
2210         /**
2211          * Bring camera position closer to that of Sprite3D.
2212          * @param {enchant.gl.Sprite3D} sprite Target Sprite3D
2213          * @param {Number} position Distance from target
2214          * @param {Number} speed Speed of approach to target
2215          * @example
2216          * var sp = new Sprite3D();
2217          * var camera = new Camera3D();
2218          * // Continue approaching camera position from 10 behind while focusing on sp
2219          * sp.addEventListener('enterframe', function() {
2220          *     camera.lookAt(sp);
2221          *     camera.chase(sp, -10, 20);
2222          * });
2223          */
2224         chase: function(sprite, position, speed) {
2225             if (sprite instanceof enchant.gl.Sprite3D) {
2226                 var vx = sprite.x + sprite.rotation[8] * position;
2227                 var vy = sprite.y + sprite.rotation[9] * position;
2228                 var vz = sprite.z + sprite.rotation[10] * position;
2229                 this._x += (vx - this._x) / speed;
2230                 this._y += (vy - this._y) / speed;
2231                 this._z += (vz - this._z) / speed;
2232                 this._changedPosition = true;
2233             }
2234         },
2235         _getForwardVec: function() {
2236             var x = this._centerX - this._x;
2237             var y = this._centerY - this._y;
2238             var z = this._centerZ - this._z;
2239             return vec3.normalize([x, y, z]);
2240         },
2241         _getSideVec: function() {
2242             var f = this._getForwardVec();
2243             var u = this._getUpVec();
2244             return vec3.cross(u, f);
2245         },
2246         _getUpVec: function() {
2247             var x = this._upVectorX;
2248             var y = this._upVectorY;
2249             var z = this._upVectorZ;
2250             return [x, y, z];
2251         },
2252         _move: function(v, s) {
2253             v[0] *= s;
2254             v[1] *= s;
2255             v[2] *= s;
2256             this._x += v[0];
2257             this._y += v[1];
2258             this._z += v[2];
2259             this._centerX += v[0];
2260             this._centerY += v[1];
2261             this._centerZ += v[2];
2262         },
2263         /**
2264          * Moves forward Camera3D.
2265          * @param {Number} speed
2266          */
2267         forward: function(s) {
2268             var v = this._getForwardVec();
2269             this._move(v, s);
2270         },
2271         /**
2272          * Moves side Camera3D.
2273          * @param {Number} speed
2274          */
2275         sidestep: function(s) {
2276             var v = this._getSideVec();
2277             this._move(v, s);
2278         },
2279         /**
2280          * Moves up Camera3D.
2281          * @param {Number} speed
2282          */
2283         altitude: function(s) {
2284             var v = this._getUpVec();
2285             this._move(v, s);
2286         },
2287         /**
2288          * Rotate Camera3D in local Z acxis.
2289          * @param {Number} radius
2290          */
2291         rotateRoll: function(rad) {
2292             var u = this._getUpVec();
2293             var f = this._getForwardVec();
2294             var x = f[0];
2295             var y = f[1];
2296             var z = f[2];
2297             var quat = new enchant.gl.Quat(x, y, z, -rad);
2298             var vec = quat.multiplyVec3(u);
2299             this._upVectorX = vec[0];
2300             this._upVectorY = vec[1];
2301             this._upVectorZ = vec[2];
2302             this._changedUpVector = true;
2303         },
2304         /**
2305          * Rotate Camera3D in local X acxis.
2306          * @param {Number} radius
2307          */
2308         rotatePitch: function(rad) {
2309             var u = this._getUpVec();
2310             var f = this._getForwardVec();
2311             var s = this._getSideVec();
2312             var sx = s[0];
2313             var sy = s[1];
2314             var sz = s[2];
2315             var quat = new enchant.gl.Quat(sx, sy, sz, -rad);
2316             var vec = quat.multiplyVec3(f);
2317             this._centerX = this._x + vec[0];
2318             this._centerY = this._y + vec[1];
2319             this._centerZ = this._z + vec[2];
2320             vec = vec3.normalize(quat.multiplyVec3(u));
2321             this._upVectorX = vec[0];
2322             this._upVectorY = vec[1];
2323             this._upVectorZ = vec[2];
2324             this._changedCenter = true;
2325             this._changedUpVector = true;
2326         },
2327         /**
2328          * Rotate Camera3D in local Y acxis.
2329          * @param {Number} radius
2330          */
2331         rotateYaw: function(rad) {
2332             var u = this._getUpVec();
2333             var ux = u[0];
2334             var uy = u[1];
2335             var uz = u[2];
2336             var f = this._getForwardVec();
2337             var quat = new enchant.gl.Quat(ux, uy, uz, -rad);
2338             var vec = quat.multiplyVec3(f);
2339             this._centerX = this._x + vec[0];
2340             this._centerY = this._y + vec[1];
2341             this._centerZ = this._z + vec[2];
2342             this._changedCenter = true;
2343         },
2344         _updateMatrix: function() {
2345             mat4.lookAt(
2346                 [this._x, this._y, this._z],
2347                 [this._centerX, this._centerY, this._centerZ],
2348                 [this._upVectorX, this._upVectorY, this._upVectorZ],
2349                 this.mat);
2350             mat4.lookAt(
2351                 [0, 0, 0],
2352                 [-this._x + this._centerX,
2353                     -this._y + this._centerY,
2354                     -this._z + this._centerZ],
2355                 [this._upVectorX, this._upVectorY, this._upVectorZ],
2356                 this.invMat);
2357             mat4.inverse(this.invMat);
2358             mat4.lookAt(
2359                 [0, 0, 0],
2360                 [-this._x + this._centerX,
2361                     0,
2362                     -this._z + this._centerZ],
2363                 [this._upVectorX, this._upVectorY, this._upVectorZ],
2364                 this.invMatY);
2365             mat4.inverse(this.invMatY);
2366         }
2367     });
2368 
2369     /**
2370      * Camera x coordinates
2371      * @type Number
2372      */
2373     enchant.gl.Camera3D.prototype.x = 0;
2374 
2375     /**
2376      * Camera y coordinates
2377      * @type Number
2378      */
2379     enchant.gl.Camera3D.prototype.y = 0;
2380 
2381     /**
2382      * Camera z coordinates
2383      * @type Number
2384      */
2385     enchant.gl.Camera3D.prototype.z = 0;
2386 
2387     'x y z'.split(' ').forEach(function(prop) {
2388         Object.defineProperty(enchant.gl.Camera3D.prototype, prop, {
2389             get: function() {
2390                 return this['_' + prop];
2391             },
2392             set: function(n) {
2393                 this['_' + prop] = n;
2394                 this._changedPosition = true;
2395             }
2396         });
2397     });
2398 
2399     /**
2400      * Camera perspective x coordinates
2401      * @type Number
2402      */
2403     enchant.gl.Camera3D.prototype.centerX = 0;
2404 
2405     /**
2406      * Camera perspective y coordinates
2407      * @type Number
2408      */
2409     enchant.gl.Camera3D.prototype.centerY = 0;
2410 
2411     /**
2412      * Camera perspective z coordinates
2413      * @type Number
2414      */
2415     enchant.gl.Camera3D.prototype.centerZ = 0;
2416 
2417     'centerX centerY centerZ'.split(' ').forEach(function(prop) {
2418         Object.defineProperty(enchant.gl.Camera3D.prototype, prop, {
2419             get: function() {
2420                 return this['_' + prop];
2421             },
2422             set: function(n) {
2423                 this['_' + prop] = n;
2424                 this._changedCenter = true;
2425             }
2426         });
2427     });
2428 
2429     /**
2430      * Camera upper vector x component
2431      * @type Number
2432      */
2433     enchant.gl.Camera3D.prototype.upVectorX = 0;
2434 
2435     /**
2436      * Camera upper vector y component
2437      * @type Number
2438      */
2439     enchant.gl.Camera3D.prototype.upVectorY = 1;
2440 
2441     /**
2442      * Camera upper vector z component
2443      * @type Number
2444      */
2445     enchant.gl.Camera3D.prototype.upVectorZ = 0;
2446 
2447     'upVectorX upVectorY upVectorZ'.split(' ').forEach(function(prop) {
2448         Object.defineProperty(enchant.gl.Camera3D.prototype, prop, {
2449             get: function() {
2450                 return this['_' + prop];
2451             },
2452             set: function(n) {
2453                 this['_' + prop] = n;
2454                 this._changedUpVector = true;
2455             }
2456         });
2457     });
2458 
2459     /**
2460      * @scope enchant.gl.Scene3D.prototype
2461      */
2462     enchant.gl.Scene3D = enchant.Class.create(enchant.EventTarget, {
2463         /**
2464          * Class for displayed Sprite3D tree route.
2465          * Currently, multiple definitions are impossible, and the Scene3D defined first will be returned.
2466          *
2467          * @example
2468          *   var scene = new Scene3D();
2469          *   var sprite = new Sprite3D();
2470          *   scene.addChild(sprite);
2471          *
2472          * @constructs
2473          * @extends enchant.EventTarget
2474          */
2475         initialize: function() {
2476             var core = enchant.Core.instance;
2477             if (core.currentScene3D) {
2478                 return core.currentScene3D;
2479             }
2480             enchant.EventTarget.call(this);
2481             /**
2482              * Child element array.
2483              * A list of Sprite3D added as child classes in this scene can be acquired.
2484              * When adding or subtracting child classes, without directly operating this array,
2485              * {@link enchant.gl.Scene3D#addChild} or {@link enchant.gl.Scene3D#removeChild} is used.
2486              * @type enchant.gl.Sprite3D[]
2487              */
2488             this.childNodes = [];
2489 
2490             /**
2491              * Lighting array.
2492              * At present, the only light source active in the scene is 0.
2493              * Acquires a list of light sources acquired in this scene.
2494              * When lighting is added or deleted, without directly operating this array,
2495              * {@link enchant.gl.Scene3D#addLight} or {@link enchant.gl.Scene3D#removeLight} is used.
2496              * @type enchant.gl.PointLight[]
2497              */
2498             this.lights = [];
2499 
2500             this.identityMat = mat4.identity();
2501             this._backgroundColor = [0.0, 0.0, 0.0, 1.0];
2502 
2503             var listener = function(e) {
2504                 for (var i = 0, len = this.childNodes.length; i < len; i++) {
2505                     var sprite = this.childNodes[i];
2506                     sprite.dispatchEvent(e);
2507                 }
2508             };
2509             this.addEventListener('added', listener);
2510             this.addEventListener('removed', listener);
2511             this.addEventListener('addedtoscene', listener);
2512             this.addEventListener('removedfromscene', listener);
2513 
2514             var that = this;
2515             var func = function() {
2516                 that._draw();
2517             };
2518             core.addEventListener('enterframe', func);
2519 
2520 
2521             var uniforms = {};
2522             uniforms['uUseCamera'] = 0.0;
2523             gl.activeTexture(gl.TEXTURE0);
2524             core.GL.defaultProgram.setUniforms(uniforms);
2525 
2526             if (core.currentScene3D === null) {
2527                 core.currentScene3D = this;
2528             }
2529 
2530             this.setAmbientLight(new enchant.gl.AmbientLight());
2531             this.setDirectionalLight(new enchant.gl.DirectionalLight());
2532             this.setCamera(new enchant.gl.Camera3D());
2533         },
2534 
2535         /**
2536          * Scene3D background color
2537          * @type Number[]
2538          */
2539         backgroundColor: {
2540             get: function() {
2541                 return this._backgroundColor;
2542             },
2543             set: function(arg) {
2544                 var c = enchant.Core.instance.GL.parseColor(arg);
2545                 this._backgroundColor = c;
2546                 gl.clearColor(c[0], c[1], c[2], c[3]);
2547 
2548             }
2549         },
2550 
2551         /**
2552          * Add Sprite3D to scene.
2553          * Adds Sprite3D delivered to argument and child classes to scene.
2554          * Sprite3D will automatically be displayed on screen if added to scene.
2555          * Use {@link enchant.gl.Scene3D#removeChild} to delete object added once.
2556          * @param {enchant.gl.Sprite3D} sprite Sprite3D to be added
2557          * @see enchant.gl.Scene3D#removeChild
2558          * @see enchant.gl.Scene3D#childNodes
2559          */
2560         addChild: function(sprite) {
2561             this.childNodes.push(sprite);
2562             sprite.parentNode = sprite.scene = this;
2563             sprite.dispatchEvent(new enchant.Event('added'));
2564             sprite.dispatchEvent(new enchant.Event('addedtoscene'));
2565             sprite.dispatchEvent(new enchant.Event('render'));
2566         },
2567 
2568         /**
2569          * Delete Sprite3D from scene.
2570          * Deletes designated Sprite3D from scene.
2571          * The deleted Sprite3D will no longer be displayed on the screen.
2572          * Use {@link enchant.gl.Scene3D#addChild} to add Sprite3D.
2573          * @param {enchant.gl.Sprite3D} sprite Sprite3D to delete
2574          * @see enchant.gl.Scene3D#addChild
2575          * @see enchant.gl.Scene3D#childNodes
2576          */
2577         removeChild: function(sprite) {
2578             var i;
2579             if ((i = this.childNodes.indexOf(sprite)) !== -1) {
2580                 this.childNodes.splice(i, 1);
2581                 sprite.parentNode = sprite.scene = null;
2582                 sprite.dispatchEvent(new enchant.Event('removed'));
2583                 sprite.dispatchEvent(new enchant.Event('removedfromscene'));
2584             }
2585         },
2586 
2587         /**
2588          * Sets scene's camera postion.
2589          * @param {enchant.gl.Camera3D} camera Camera to set
2590          * @see enchant.gl.Camera3D
2591          */
2592         setCamera: function(camera) {
2593             camera._changedPosition = true;
2594             camera._changedCenter = true;
2595             camera._changedUpVector = true;
2596             camera._changedProjection = true;
2597             this._camera = camera;
2598             enchant.Core.instance.GL.defaultProgram.setUniforms({
2599                 uUseCamera: 1.0
2600             });
2601         },
2602 
2603         /**
2604          * Gets camera source in scene.
2605          * @see enchant.gl.Camera3D
2606          * @return {enchant.gl.Camera}
2607          */
2608         getCamera: function() {
2609             return this._camera;
2610         },
2611 
2612         /**
2613          * Sets ambient light source in scene.
2614          * @param {enchant.gl.AmbientLight} light Lighting to set
2615          * @see enchant.gl.AmbientLight
2616          */
2617         setAmbientLight: function(light) {
2618             this.ambientLight = light;
2619         },
2620 
2621         /**
2622          * Gets ambient light source in scene.
2623          * @see enchant.gl.AmbientLight
2624          * @return {enchant.gl.AmbientLight}
2625          */
2626         getAmbientLight: function() {
2627             return this.ambientLight;
2628         },
2629 
2630         /**
2631          * Sets directional light source in scene.
2632          * @param {enchant.gl.DirectionalLight} light Lighting to set
2633          * @see enchant.gl.DirectionalLight
2634          */
2635         setDirectionalLight: function(light) {
2636             this.directionalLight = light;
2637             this.useDirectionalLight = true;
2638             enchant.Core.instance.GL.defaultProgram.setUniforms({
2639                 uUseDirectionalLight: 1.0
2640             });
2641         },
2642 
2643         /**
2644          * Gets directional light source in scene.
2645          * @see enchant.gl.DirectionalLight
2646          * @return {enchant.gl.DirectionalLight}
2647          */
2648         getDirectionalLight: function() {
2649             return this.directionalLight;
2650         },
2651 
2652         /**
2653          * Add lighting to scene.
2654          * Currently, will not be used even if added to scene.
2655          * @param {enchant.gl.PointLight} light Lighting to add
2656          * @see enchant.gl.PointLight
2657          */
2658         addLight: function(light) {
2659             this.lights.push(light);
2660             this.usePointLight = true;
2661         },
2662 
2663         /**
2664          * Delete lighting from scene
2665          * @param {enchant.gl.PointLight} light Lighting to delete
2666          * @see enchant.gl.PointLight.
2667          */
2668         removeLight: function(light) {
2669             var i;
2670             if ((i = this.lights.indexOf(light)) !== -1) {
2671                 this.lights.splice(i, 1);
2672             }
2673         },
2674 
2675         _draw: function(detectTouch) {
2676             var core = enchant.Core.instance;
2677             var program = core.GL.defaultProgram;
2678 
2679             gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
2680 
2681             var detect = (detectTouch === 'detect') ? 1.0 : 0.0;
2682 
2683             var uniforms = { uDetectTouch: detect };
2684 
2685             if (this.ambientLight._changedColor) {
2686                 uniforms['uAmbientLightColor'] = this.ambientLight.color;
2687                 this.ambientLight._changedColor = false;
2688             }
2689             if (this.useDirectionalLight) {
2690                 if (this.directionalLight._changedDirection) {
2691                     uniforms['uLightDirection'] = [
2692                         this.directionalLight.directionX,
2693                         this.directionalLight.directionY,
2694                         this.directionalLight.directionZ
2695                     ];
2696                     this.directionalLight._changedDirection = false;
2697                 }
2698                 if (this.directionalLight._changedColor) {
2699                     uniforms['uLightColor'] = this.directionalLight.color;
2700                     this.directionalLight._changedColor = false;
2701                 }
2702             }
2703 
2704             if (this._camera) {
2705                 if (this._camera._changedPosition ||
2706                     this._camera._changedCenter ||
2707                     this._camera._changedUpVector ||
2708                     this._camera._changedProjection) {
2709                     this._camera._updateMatrix();
2710                     uniforms['uCameraMat'] = this._camera.mat;
2711                     uniforms['uProjMat'] = this._camera._projMat;
2712                     uniforms['uLookVec'] = [
2713                         this._camera._centerX - this._camera._x,
2714                         this._camera._centerY - this._camera._y,
2715                         this._camera._centerZ - this._camera._z
2716                     ];
2717                     this._camera._changedPosition = false;
2718                     this._camera._changedCenter = false;
2719                     this._camera._changedUpVector = false;
2720                     this._camera._changedProjection = false;
2721                 }
2722             }
2723             program.setUniforms(uniforms);
2724 
2725             mat4.identity(this.identityMat);
2726             for (var i = 0, l = this.childNodes.length; i < l; i++) {
2727                 this.childNodes[i]._draw(this, detectTouch, this.identityMat);
2728             }
2729 
2730         }
2731     });
2732 
2733     /**
2734      * @type {Object}
2735      */
2736     enchant.gl.collision = {};
2737 
2738     var point2point = function(p1, p2) {
2739         var vx = p1.x + p1.parent.x - p2.x - p2.parent.x;
2740         var vy = p1.y + p1.parent.y - p2.y - p2.parent.y;
2741         var vz = p1.z + p1.parent.z - p2.z - p2.parent.z;
2742         return (vx * vx + vy * vy + vz * vz);
2743     };
2744 
2745     var point2BS = function(p, bs) {
2746         return (point2point(p, bs) - bs.radius * bs.radius);
2747     };
2748 
2749     var point2AABB = function(p, aabb) {
2750         var ppx = p.x + p.parent.x;
2751         var ppy = p.y + p.parent.y;
2752         var ppz = p.z + p.parent.z;
2753         var px = aabb.parent.x + aabb.x + aabb.scale;
2754         var py = aabb.parent.y + aabb.y + aabb.scale;
2755         var pz = aabb.parent.z + aabb.z + aabb.scale;
2756         var nx = aabb.parent.x + (aabb.x - aabb.scale);
2757         var ny = aabb.parent.y + (aabb.y - aabb.scale);
2758         var nz = aabb.parent.z + (aabb.z - aabb.scale);
2759         var dist = 0;
2760         if (ppx < nx) {
2761             dist += (ppx - nx) * (ppx - nx);
2762         } else if (px < ppx) {
2763             dist += (ppx - px) * (ppx - px);
2764         }
2765         if (ppy < ny) {
2766             dist += (ppy - ny) * (ppy - ny);
2767         } else if (py < ppy) {
2768             dist += (ppy - py) * (ppy - py);
2769         }
2770         if (ppz < nz) {
2771             dist += (ppz - nz) * (ppz - nz);
2772         } else if (pz < ppz) {
2773             dist += (ppz - pz) * (ppz - pz);
2774         }
2775         return dist;
2776     };
2777 
2778     var point2OBB = function(p, obb) {
2779         return 1;
2780     };
2781 
2782     var BS2BS = function(bs1, bs2) {
2783         return (point2point(bs1, bs2) - (bs1.radius + bs2.radius) * (bs1.radius + bs2.radius));
2784     };
2785 
2786     var BS2AABB = function(bs, aabb) {
2787         return (point2AABB(bs, aabb) - bs.radius * bs.radius);
2788     };
2789 
2790     var BS2OBB = function(bs, obb) {
2791         return 1;
2792     };
2793 
2794     var AABB2AABB = function(aabb1, aabb2) {
2795         var px1 = aabb1.parent.x + aabb1.x + aabb1.scale;
2796         var py1 = aabb1.parent.y + aabb1.y + aabb1.scale;
2797         var pz1 = aabb1.parent.z + aabb1.z + aabb1.scale;
2798 
2799         var nx1 = aabb1.parent.x + (aabb1.x - aabb1.scale);
2800         var ny1 = aabb1.parent.y + (aabb1.y - aabb1.scale);
2801         var nz1 = aabb1.parent.z + (aabb1.z - aabb1.scale);
2802 
2803         var px2 = aabb2.parent.x + aabb2.x + aabb2.scale;
2804         var py2 = aabb2.parent.y + aabb2.y + aabb2.scale;
2805         var pz2 = aabb2.parent.z + aabb2.z + aabb2.scale;
2806 
2807         var nx2 = aabb2.parent.x + (aabb2.x - aabb2.scale);
2808         var ny2 = aabb2.parent.y + (aabb2.y - aabb2.scale);
2809         var nz2 = aabb2.parent.z + (aabb2.z - aabb2.scale);
2810         return ((nx2 <= px1) && (nx1 <= px2) &&
2811             (ny2 <= py1) && (ny1 <= py2) &&
2812             (nz2 <= pz1) && (nz1 <= pz2)) ? 0.0 : 1.0;
2813     };
2814 
2815     var AABB2OBB = function(aabb, obb) {
2816         return 1;
2817     };
2818 
2819     var OBB2OBB = function(obb1, obb2) {
2820         return 1;
2821     };
2822 
2823     /**
2824      * @scope enchant.gl.collision.Bounding.prototype
2825      */
2826     enchant.gl.collision.Bounding = enchant.Class.create({
2827         /**
2828          * Class to set Sprite3D collision detection.
2829          * Defined as a point.
2830          * {@link enchant.gl.collision.BS}, {@link enchant.gl.collision.AABB},
2831          * {@link enchant.gl.collision.OBB} exist as
2832          * inherited classes of enchant.gl.collision.Bounding
2833          * Currently, OBB is not supported.
2834          * @constructs
2835          */
2836         initialize: function() {
2837             this.type = 'point';
2838             this.threshold = 0.0001;
2839             this.x = 0;
2840             this.y = 0;
2841             this.z = 0;
2842             this.parent = {
2843                 x: 0,
2844                 y: 0,
2845                 z: 0
2846             };
2847         },
2848         /**
2849          * Calculates distance between points.
2850          * @param {enchant.gl.collision.Bounding} bounding Collision point object
2851          * @return {Number}
2852          */
2853         toBounding: function(another) {
2854             return point2point(this, another);
2855         },
2856         /**
2857          * Calculates distance between balls.
2858          * @param {enchant.gl.collision.BS} boudning Collision ball object
2859          * @return {Number}
2860          */
2861         toBS: function(another) {
2862             return point2BS(this, another);
2863         },
2864         /**
2865          * Calculates distance from non-rotating cube.
2866          * Currently, 0 will be returned with or without collision.
2867          * @param {enchant.gl.collision.AABB} bounding AABB
2868          * @return {Number}
2869          */
2870         toAABB: function(another) {
2871             return point2AABB(this, another);
2872         },
2873         /**
2874          * Calculates distance from rotating cuboid.
2875          * Not currently supported.
2876          * @param {enchant.gl.collision.OBB} bounding OBB
2877          * @return {Number}
2878          */
2879         toOBB: function(another) {
2880             return point2OBB(this, another);
2881         },
2882         /**
2883          * Collision detection with other collision detection object.
2884          * A collision detection object can detect collision with an object with x, y, z properties.
2885          * @param {enchant.gl.collision.Bounding|enchant.gl.collision.BS|enchant.gl.collision.AABB|enchant.gl.collision.OBB} bounding Collision detection object
2886          * @return {Boolean}
2887          */
2888         intersect: function(another) {
2889             switch (another.type) {
2890                 case 'point':
2891                     return (this.toBounding(another) < this.threshold);
2892                 case 'BS':
2893                     return (this.toBS(another) < this.threshold);
2894                 case 'AABB':
2895                     return (this.toAABB(another) < this.threshold);
2896                 case 'OBB':
2897                     return (this.toOBB(another) < this.threshold);
2898                 default:
2899                     return false;
2900             }
2901         }
2902     });
2903 
2904     /**
2905      * @scope enchant.gl.collision.BS.prototype
2906      */
2907     enchant.gl.collision.BS = enchant.Class.create(enchant.gl.collision.Bounding, {
2908         /**
2909          * Class that sets Sprite3D collision detection.
2910          * Defined as a ball.
2911          * @constructs
2912          * @see enchant.gl.collision.Bounding
2913          */
2914         initialize: function() {
2915             enchant.gl.collision.Bounding.call(this);
2916             this.type = 'BS';
2917             this.radius = 0.5;
2918         },
2919         toBounding: function(another) {
2920             return point2BS(another, this);
2921         },
2922         toBS: function(another) {
2923             return BS2BS(this, another);
2924         },
2925         toAABB: function(another) {
2926             return BS2AABB(this, another);
2927         },
2928         toOBB: function(another) {
2929             return BS2OBB(this, another);
2930         }
2931     });
2932 
2933     /**
2934      * @scope enchant.gl.collision.AABB.prototype
2935      */
2936     enchant.gl.collision.AABB = enchant.Class.create(enchant.gl.collision.Bounding, {
2937         /**
2938          * Class that sets Sprite3D collision detection.
2939          * Defined as non-rotating cube.
2940          * @constructs
2941          * @see enchant.gl.collision.Bounding
2942          */
2943         initialize: function() {
2944             enchant.gl.collision.Bounding.call(this);
2945             this.type = 'AABB';
2946             this.scale = 0.5;
2947         },
2948         toBounding: function(another) {
2949             return point2AABB(another, this);
2950         },
2951         toBS: function(another) {
2952             return BS2AABB(another, this);
2953         },
2954         toAABB: function(another) {
2955             return AABB2AABB(this, another);
2956         },
2957         toOBB: function(another) {
2958             return AABB2OBB(this, another);
2959         }
2960     });
2961 
2962     /**
2963      * @scope enchant.gl.collision.OBB.prototype
2964      */
2965     enchant.gl.collision.OBB = enchant.Class.create(enchant.gl.collision.Bounding, {
2966         /**
2967          * Class that sets Sprite3D collision detection.
2968          * Defined as rotating.
2969          * @constructs
2970          * @see enchant.gl.collision.Bounding
2971 
2972          */
2973         initialize: function() {
2974             enchant.gl.collision.Bounding.call(this);
2975             this.type = 'OBB';
2976         },
2977         toBounding: function(another) {
2978             return point2OBB(another, this);
2979         },
2980         toBS: function(another) {
2981             return BS2OBB(another, this);
2982         },
2983         toAABB: function(another) {
2984             return AABB2OBB(another, this);
2985         },
2986         toOBB: function(another) {
2987             return OBB2OBB(this, another);
2988         }
2989     });
2990 
2991     // borrowed from MMD.js
2992     var bezierp = function(x1, x2, y1, y2, x) {
2993         var t, tt, v;
2994         t = x;
2995         while (true) {
2996             v = ipfunc(t, x1, x2) - x;
2997             if (v * v < 0.0000001) {
2998                 break;
2999             }
3000             tt = ipfuncd(t, x1, x2);
3001             if (tt === 0) {
3002                 break;
3003             }
3004             t -= v / tt;
3005         }
3006         return ipfunc(t, y1, y2);
3007     };
3008     var ipfunc = function(t, p1, p2) {
3009         return (1 + 3 * p1 - 3 * p2) * t * t * t + (3 * p2 - 6 * p1) * t * t + 3 * p1 * t;
3010     };
3011     var ipfuncd = function(t, p1, p2) {
3012         return (3 + 9 * p1 - 9 * p2) * t * t + (6 * p2 - 12 * p1) * t + 3 * p1;
3013     };
3014     var frac = function(n1, n2, t) {
3015         return (t - n1) / (n2 - n1);
3016     };
3017     var lerp = function(n1, n2, r) {
3018         return n1 + r * (n2 - n1);
3019     };
3020 
3021     var _tmpve = vec3.create();
3022     var _tmpvt = vec3.create();
3023     var _tmpaxis = vec3.create();
3024     var _tmpquat = quat4.create();
3025     var _tmpinv = quat4.create();
3026 
3027     /**
3028      * @scope enchant.gl.State.prototype
3029      */
3030     enchant.gl.State = enchant.Class.create({
3031         /**
3032          * Base class for expressing animation condition.
3033          * @param {Number[]} position
3034          * @param {Number[]} rotation
3035          * @constructs
3036          */
3037         initialize: function(position, rotation) {
3038             this._position = vec3.create();
3039             vec3.set(position, this._position);
3040             this._rotation = quat4.create();
3041             quat4.set(rotation, this._rotation);
3042         },
3043         /**
3044          * Sets position/rotation.
3045          */
3046         set: function(pose) {
3047             vec3.set(pose._position, this._position);
3048             quat4.set(pose._rotation, this._rotation);
3049         }
3050     });
3051 
3052     /**
3053      * @scope enchant.gl.Pose.prototype
3054      */
3055     enchant.gl.Pose = enchant.Class.create(enchant.gl.State, {
3056         /**
3057          * Class for processing pose.
3058          * @param {Number[]} position
3059          * @param {Number[]} rotation
3060          * @constructs
3061          * @extends enchant.gl.State
3062          */
3063         initialize: function(position, rotation) {
3064             enchant.gl.State.call(this, position, rotation);
3065         },
3066         /**
3067          * Performs interpolation with other pose.
3068          * @param {enchant.gl.Pose} another
3069          * @param {Number} ratio
3070          * @return {enchant.gl.Pose}
3071          */
3072         getInterpolation: function(another, ratio) {
3073             vec3.lerp(this._position, another._position, ratio, _tmpve);
3074             quat4.slerp(this._rotation, another._rotation, ratio, _tmpquat);
3075             return new enchant.gl.Pose(_tmpve, _tmpquat);
3076         },
3077         _bezierp: function(x1, y1, x2, y2, x) {
3078             return bezierp(x1, x2, y1, y2, x);
3079         }
3080     });
3081 
3082     /**
3083      * @scope enchant.gl.KeyFrameManager.prototype
3084      */
3085     enchant.gl.KeyFrameManager = enchant.Class.create({
3086         /**
3087          * Class for realizing key frame animation.
3088          * Handles various data, not limited to enchant.gl.Pose.
3089          * @constructs
3090          */
3091         initialize: function() {
3092             this._frames = [];
3093             this._units = [];
3094             this.length = -1;
3095             this._lastPose = null;
3096         },
3097         /**
3098          * Add frame.
3099          * @param {*} pose Key frame.
3100          * @param {Number} frame Frame number.
3101          */
3102         addFrame: function(pose, frame) {
3103             if (typeof frame !== 'number') {
3104                 this.length += 1;
3105                 frame = this.length;
3106             }
3107             if (frame > this.length) {
3108                 this.length = frame;
3109                 this._lastPose = pose;
3110             }
3111             this._frames.push(frame);
3112             this._units[frame] = pose;
3113         },
3114         /**
3115          * Return information for designated frame number.
3116          * When there is no data corresponding to the designated frame, interpolated data from before and after are acquired.
3117          * @param {Number} frame Frame number
3118          * @return {*}
3119          */
3120         getFrame: function(frame) {
3121             var prev, next, index, pidx, nidx;
3122             var ratio = 0;
3123             if (frame >= this.length) {
3124                 return this._lastPose;
3125             }
3126             if (this._units[frame]) {
3127                 return this._units[frame];
3128             } else {
3129                 index = this._getPrevFrameIndex(frame);
3130                 pidx = this._frames[index];
3131                 nidx = this._frames[index + 1];
3132                 prev = this._units[pidx];
3133                 next = this._units[nidx];
3134                 ratio = this._frac(pidx, nidx, frame);
3135                 return this._interpole(prev, next, ratio);
3136             }
3137         },
3138         bake: function() {
3139             var state;
3140             for (var i = 0, l = this.length; i < l; i++) {
3141                 if (this._units[i]) {
3142                     continue;
3143                 }
3144                 state = this.getFrame(i);
3145                 this.addFrame(state, i);
3146             }
3147             this._sort();
3148         },
3149         _frac: function(p, n, t) {
3150             return frac(p, n, t);
3151         },
3152         _interpole: function(prev, next, ratio) {
3153             return prev.getInterpolation(next, ratio);
3154         },
3155         _sort: function() {
3156             this._frames.sort(function(a, b) {
3157                 return a - b;
3158             });
3159         },
3160         _getPrevFrameIndex: function(frame) {
3161             for (var i = 0, l = this._frames.length; i < l; i++) {
3162                 if (this._frames[i] > frame) {
3163                     break;
3164                 }
3165             }
3166             return i - 1;
3167         }
3168     });
3169 
3170     /**
3171      * @scope enchant.gl.Bone.prototype
3172      */
3173     enchant.gl.Bone = enchant.Class.create(enchant.gl.State, {
3174         /**
3175          * Class to display bone status.
3176          * @param {String} name
3177          * @param {Number} head
3178          * @param {Number} position
3179          * @param {Number} rotation
3180          * @constructs
3181          * @extends enchant.gl.State
3182          */
3183         initialize: function(name, head, position, rotation) {
3184             enchant.gl.State.call(this, position, rotation);
3185             this._name = name;
3186             this._origin = vec3.create();
3187 
3188             vec3.set(head, this._origin);
3189 
3190             this._globalpos = vec3.create();
3191             vec3.set(head, this._globalpos);
3192 
3193             this._globalrot = quat4.identity();
3194 
3195             this.parentNode = null;
3196             this.childNodes = [];
3197 
3198             /**
3199              * During each IK settlement, function for which change is applied to quaternion is set.
3200              */
3201             this.constraint = null;
3202         },
3203         /**
3204          * Add child bone to bone.
3205          * @param {enchant.gl.Bone} child
3206          */
3207         addChild: function(child) {
3208             this.childNodes.push(child);
3209             child.parentNode = this;
3210         },
3211         /**
3212          * Delete child bone from bone.
3213          * @param {enchant.gl.Bone} child
3214          */
3215         removeChild: function(child) {
3216             var i;
3217             if ((i = this.childNodes.indexOf(child)) !== -1) {
3218                 this.childNodes.splice(i, 1);
3219             }
3220             child.parentNode = null;
3221         },
3222         /**
3223          * Set bone pose.
3224          * @param {*} poses
3225          */
3226         setPoses: function(poses) {
3227             var child;
3228             if (poses[this._name]) {
3229                 this.set(poses[this._name]);
3230             }
3231             for (var i = 0, l = this.childNodes.length; i < l; i++) {
3232                 child = this.childNodes[i];
3233                 child.setPoses(poses);
3234             }
3235         },
3236         _applyPose: function(){
3237             var parent = this.parentNode;
3238             quat4.multiply(parent._globalrot, this._rotation, this._globalrot);
3239             quat4.multiplyVec3(parent._globalrot, this._position, this._globalpos);
3240             vec3.add(parent._globalpos, this._globalpos, this._globalpos);
3241         },
3242         _solveFK: function() {
3243             var child;
3244             this._applyPose();
3245             for (var i = 0, l = this.childNodes.length; i < l; i++) {
3246                 child = this.childNodes[i];
3247                 child._solveFK();
3248             }
3249         },
3250         _solve: function(quat) {
3251             quat4.normalize(quat, this._rotation);
3252             this._solveFK();
3253         }
3254     });
3255 
3256     /**
3257      * @scope enchant.gl.Skeleton.prototype
3258      */
3259     enchant.gl.Skeleton = enchant.Class.create({
3260         /**
3261          * Class that becomes bone structure route.
3262          * @constructs
3263          */
3264         initialize: function() {
3265             this.childNodes = [];
3266             this._origin = vec3.create();
3267             this._position = vec3.create();
3268             this._rotation = quat4.identity();
3269             this._globalpos = vec3.create();
3270             this._globalrot = quat4.identity();
3271             this._iks = [];
3272         },
3273         /**
3274          * Add child bone to skeleton.
3275          * @param {enchant.gl.Bone} child
3276          */
3277         addChild: function(bone) {
3278             this.childNodes.push(bone);
3279             bone.parentNode = this;
3280         },
3281         /**
3282          * Delete child bone from skeleton.
3283          * @param {enchant.gl.Bone} child
3284          */
3285         removeChild: function(bone) {
3286             var i;
3287             if ((i = this.childNodes.indexOf(bone)) !== -1) {
3288                 this.childNodes.splice(i, 1);
3289             }
3290             bone.parentNode = null;
3291         },
3292         /**
3293          * Set pose.
3294          * @param {*} poses
3295          */
3296         setPoses: function(poses) {
3297             var child;
3298             for (var i = 0, l = this.childNodes.length; i < l; i++) {
3299                 child = this.childNodes[i];
3300                 child.setPoses(poses);
3301             }
3302         },
3303         /**
3304          * Perform pose settlement according to FK.
3305          * Make pose from set pose information.
3306          */
3307         solveFKs: function() {
3308             var child;
3309             for (var i = 0, l = this.childNodes.length; i < l; i++) {
3310                 child = this.childNodes[i];
3311                 child._solveFK();
3312             }
3313         },
3314         /**
3315          * Add IK control information.
3316          * @param {enchant.gl.Bone} effector
3317          * @param {enchant.gl.Bone} target
3318          * @param {enchant.gl.Bone[]} bones
3319          * @param {Number} maxangle
3320          * @param {Number} iteration
3321          * @see enchant.gl.Skeleton#solveIKs
3322          */
3323         addIKControl: function(effector, target, bones, maxangle, iteration) {
3324             this._iks.push(arguments);
3325         },
3326         // by ccd
3327         /**
3328          * Perform pose settlement via IK.
3329          * Base on information added via {@link enchant.gl.Skeleton#addIKControl}
3330          */
3331         solveIKs: function() {
3332             var param;
3333             for (var i = 0, l = this._iks.length; i < l; i++) {
3334                 param = this._iks[i];
3335                 this._solveIK.apply(this, param);
3336             }
3337         },
3338         _solveIK: function(effector, target, bones, maxangle, iteration) {
3339             var len, origin;
3340             vec3.subtract(target._origin, target.parentNode._origin, _tmpinv);
3341             var threshold = vec3.length(_tmpinv) * 0.1;
3342             for (var i = 0; i < iteration; i++) {
3343                 vec3.subtract(target._globalpos, effector._globalpos, _tmpinv);
3344                 len = vec3.length(_tmpinv);
3345                 if (len < threshold) {
3346                     break;
3347                 }
3348                 for (var j = 0, ll = bones.length; j < ll; j++) {
3349                     origin = bones[j];
3350                     this._ccd(effector, target, origin, maxangle, threshold);
3351                 }
3352             }
3353         },
3354         _ccd: function(effector, target, origin, maxangle, threshold) {
3355             vec3.subtract(effector._globalpos, origin._globalpos, _tmpve);
3356             vec3.subtract(target._globalpos, origin._globalpos, _tmpvt);
3357             vec3.cross(_tmpvt, _tmpve, _tmpaxis);
3358             var elen = vec3.length(_tmpve);
3359             var tlen = vec3.length(_tmpvt);
3360             var alen = vec3.length(_tmpaxis);
3361 
3362             if (elen < threshold || tlen < threshold || alen < threshold) {
3363                 return;
3364             }
3365             var rad = Math.acos(vec3.dot(_tmpve, _tmpvt) / elen / tlen);
3366 
3367             if (rad > maxangle) {
3368                 rad = maxangle;
3369             }
3370             vec3.scale(_tmpaxis, Math.sin(rad / 2) / alen, _tmpquat);
3371             _tmpquat[3] = Math.cos(rad / 2);
3372             quat4.inverse(origin.parentNode._globalrot, _tmpinv);
3373             quat4.multiply(_tmpinv, _tmpquat, _tmpquat);
3374             quat4.multiply(_tmpquat, origin._globalrot, _tmpquat);
3375 
3376 
3377             if (origin.constraint) {
3378                 origin.constraint(_tmpquat);
3379             }
3380 
3381             origin._solve(_tmpquat);
3382         }
3383     });
3384 
3385     var DEFAULT_VERTEX_SHADER_SOURCE = '\n\
3386     attribute vec3 aVertexPosition;\n\
3387     attribute vec4 aVertexColor;\n\
3388     \n\
3389     attribute vec3 aNormal;\n\
3390     attribute vec2 aTextureCoord;\n\
3391     \n\
3392     uniform mat4 uModelMat;\n\
3393     uniform mat4 uRotMat;\n\
3394     uniform mat4 uCameraMat;\n\
3395     uniform mat4 uProjMat;\n\
3396     uniform mat3 uNormMat;\n\
3397     uniform float uUseCamera;\n\
3398     \n\
3399     varying vec2 vTextureCoord;\n\
3400     varying vec4 vColor;\n\
3401     varying vec3 vNormal;\n\
3402     \n\
3403     void main() {\n\
3404         vec4 p = uModelMat * vec4(aVertexPosition, 1.0);\n\
3405         gl_Position = uProjMat * (uCameraMat * uUseCamera) * p + uProjMat * p * (1.0 - uUseCamera);\n\
3406         vTextureCoord = aTextureCoord;\n\
3407         vColor = aVertexColor;\n\
3408         vNormal = uNormMat * aNormal;\n\
3409     }';
3410 
3411     var DEFAULT_FRAGMENT_SHADER_SOURCE = '\n\
3412     precision highp float;\n\
3413     \n\
3414     uniform sampler2D uSampler;\n\
3415     uniform float uUseDirectionalLight;\n\
3416     uniform vec3 uAmbientLightColor;\n\
3417     uniform vec3 uLightColor;\n\
3418     uniform vec3 uLookVec;\n\
3419     uniform vec4 uAmbient;\n\
3420     uniform vec4 uDiffuse;\n\
3421     uniform vec4 uSpecular;\n\
3422     uniform vec4 uEmission;\n\
3423     uniform vec4 uDetectColor;\n\
3424     uniform float uDetectTouch;\n\
3425     uniform float uUseTexture;\n\
3426     uniform float uShininess;\n\
3427     uniform vec3 uLightDirection;\n\
3428     \n\
3429     varying vec2 vTextureCoord;\n\
3430     varying vec4 vColor;\n\
3431     varying vec3 vNormal;\n\
3432     \n\
3433     \n\
3434     void main() {\n\
3435         float pi = 4.0 * atan(1.0);\n\
3436         vec4 texColor = texture2D(uSampler, vTextureCoord);\n\
3437         vec4 baseColor = vColor;\n\
3438         baseColor *= texColor * uUseTexture + vec4(1.0, 1.0, 1.0, 1.0) * (1.0 - uUseTexture);\n\
3439         float alpha = baseColor.a * uDetectColor.a * uDetectTouch + baseColor.a * (1.0 - uDetectTouch);\n\
3440         if (alpha < 0.2) {\n\
3441             discard;\n\
3442         }\n\
3443         else {\n\
3444             vec4 amb = uAmbient * vec4(uAmbientLightColor, 1.0);\n\
3445             vec3 N = normalize(vNormal);\n\
3446             vec3 L = normalize(uLightDirection);\n\
3447             vec3 E = normalize(uLookVec);\n\
3448             vec3 R = reflect(-L, N);\n\
3449             float lamber = max(dot(N, L) , 0.0);\n\
3450             vec4 dif = uDiffuse * lamber;\n\
3451             float s = max(dot(R, -E), 0.0);\n\
3452             vec4 specularColor = (uShininess + 2.0) / (2.0 * pi) * uSpecular * pow(s, uShininess) * sign(lamber);\n\
3453             gl_FragColor = (vec4(((amb + vec4(uLightColor, 1.0) * (dif + specularColor)) * baseColor).rgb, baseColor.a) \
3454                 * uUseDirectionalLight + baseColor * (1.0 - uUseDirectionalLight)) \
3455                 * (1.0 - uDetectTouch) + uDetectColor * uDetectTouch;\n\
3456         }\n\
3457     }';
3458 
3459 }());
3460