1 /**
  2  * The MIT License (MIT)
  3  *
  4  * Copyright (c) 2016 DeNA Co., Ltd.
  5  *
  6  * Permission is hereby granted, free of charge, to any person obtaining a copy
  7  * of this software and associated documentation files (the "Software"), to deal
  8  * in the Software without restriction, including without limitation the rights
  9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  * copies of the Software, and to permit persons to whom the Software is
 11  * furnished to do so, subject to the following conditions:
 12  *
 13  * The above copyright notice and this permission notice shall be included in
 14  * all copies or substantial portions of the Software.
 15  *
 16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22  * SOFTWARE.
 23  */
 24 
 25 /// <reference path="base.js"/>
 26 /// <reference path="renderer.js"/>
 27 /// <reference path="bounding_box.js"/>
 28 /// <reference path="color.js"/>
 29 /// <reference path="counter.js"/>
 30 /// <reference path="config.js"/>
 31 
 32 /**
 33  * A class that implements the createjs.Renderer interface with the WebGL API.
 34  * @param {HTMLCanvasElement} canvas
 35  * @param {Object} context
 36  * @param {createjs.BoundingBox} viewport
 37  * @extends {createjs.Renderer}
 38  * @implements {EventListener}
 39  * @constructor
 40  */
 41 createjs.WebGLRenderer = function(canvas, context, viewport) {
 42   /// <param type="HTMLCanvasElement" name="canvas"/>
 43   /// <param type="Object" name="context"/>
 44   /// <param type="createjs.BoundingBox" name="viewport"/>
 45   createjs.Renderer.call(this, canvas, canvas.width, canvas.height);
 46 
 47   /**
 48    * The rendering context attached to the output <canvas> element.
 49    * @type {createjs.WebGLRenderer.Context}
 50    * @private
 51    */
 52   this.context_ = new createjs.WebGLRenderer.Context(
 53       /** @type {WebGLRenderingContext} */ (context));
 54 
 55   /**
 56    * The horizontal scale that converts an x position of Canvas 2D, i.e.
 57    * [0,width), to one of WebGL, i.e. [-1,1].
 58    * @type {number}
 59    * @private
 60    */
 61   this.scaleX_ = 2 / this.getWidth();
 62 
 63   /**
 64    * The vertical scale that converts a y position of Canvas 2D, i.e.
 65    * [0,height), to one of WebGL, i.e. [-1,1].
 66    * @type {number}
 67    * @private
 68    */
 69   this.scaleY_ = 2 / this.getHeight();
 70 
 71   /**
 72    * The viewport rectangle specified by a game. (This rectangle is used for
 73    * rendering only the specified part of the output <canvas> element.)
 74    * @type {createjs.BoundingBox}
 75    * @private
 76    */
 77   this.viewport_ = viewport;
 78 
 79   // Listen the context events of WebGL.
 80   canvas.addEventListener('webglcontextlost', this, false);
 81   canvas.addEventListener('webglcontextrestored', this, false);
 82   if (createjs.DEBUG) {
 83     document.addEventListener('keyup', this, false);
 84   }
 85 
 86   // Write the context used by this renderer.
 87   canvas.setAttribute('dena-context', createjs.WebGLRenderer.context);
 88 
 89   // Set the given viewport rectangle to the scissor rectangle now so this
 90   // renderer can render only its inside.
 91   if (viewport) {
 92     this.context_.enableClip();
 93     this.context_.updateClip(viewport, this.getHeight());
 94   }
 95 };
 96 createjs.inherits('WebGLRenderer', createjs.WebGLRenderer, createjs.Renderer);
 97 
 98 /**
 99  * The context name for retrieving a WebGLRenderingContext object.
100  * @type {string}
101  */
102 createjs.WebGLRenderer.context = '';
103 
104 /**
105  * An ID assigned to createjs.WebGLRenderer.Context objects.
106  * @type {number}
107  */
108 createjs.WebGLRenderer.id = 0;
109 
110 /**
111  * The clipping rectangle of an object.
112  * @type {createjs.BoundingBox}
113  * @private
114  */
115 createjs.WebGLRenderer.prototype.scissor_ = null;
116 
117 /**
118  * The shader program (and its variables) that draws images onto the drawing
119  * buffer (or an off-screen framebuffer).
120  * @type {createjs.WebGLRenderer.Program}
121  * @private
122  */
123 createjs.WebGLRenderer.prototype.program_ = null;
124 
125 /**
126  * Whether this renderer has render objects.
127  * @type {boolean}
128  * @private
129  */
130 createjs.WebGLRenderer.prototype.dirty_ = false;
131 
132 /**
133  * An off-screen framebuffer that draws masked objects.
134  * @type {createjs.WebGLRenderer.Frame}
135  * @private
136  */
137 createjs.WebGLRenderer.prototype.mask_ = null;
138 
139 if (createjs.DEBUG) {
140   /**
141    * The interval period or the FPS of the 'createjs.Ticker' object.
142    * @type {number}
143    * @private
144    */
145   createjs.WebGLRenderer.ticker_ = 0;
146 }
147 
148 /**
149  * Constants used by WebGL. These constants are copied from the
150  * WebGLRenderingContext interface so the closure compiler can inline them.
151  * (Although it is dirty to use numbers, it is faster to use numbers than to
152  * read object properties.)
153  * @enum {number}
154  * @const
155  */
156 createjs.WebGLRenderer.gl = {
157   /* ClearBufferMask */
158   DEPTH_BUFFER_BIT: 0x00000100,
159   STENCIL_BUFFER_BIT: 0x00000400,
160   COLOR_BUFFER_BIT: 0x00004000,
161 
162   /* BeginMode */
163   POINTS: 0x0000,
164   LINES: 0x0001,
165   LINE_LOOP: 0x0002,
166   LINE_STRIP: 0x0003,
167   TRIANGLES: 0x0004,
168   TRIANGLE_STRIP: 0x0005,
169   TRIANGLE_FAN: 0x0006,
170 
171   /* BlendingFactor */
172   ZERO: 0,
173   ONE: 1,
174   SRC_COLOR: 0x0300,
175   ONE_MINUS_SRC_COLOR: 0x0301,
176   SRC_ALPHA: 0x0302,
177   ONE_MINUS_SRC_ALPHA: 0x0303,
178   DST_ALPHA: 0x0304,
179   ONE_MINUS_DST_ALPHA: 0x0305,
180   DST_COLOR: 0x0306,
181   ONE_MINUS_DST_COLOR: 0x0307,
182   SRC_ALPHA_SATURATE: 0x0308,
183 
184   /* BlendEquationSeparate */
185   FUNC_ADD: 0x8006,
186   BLEND_EQUATION: 0x8009,
187   BLEND_EQUATION_RGB: 0x8009,  /* same as BLEND_EQUATION */
188   BLEND_EQUATION_ALPHA: 0x883D,
189 
190   /* BlendSubtract */
191   FUNC_SUBTRACT: 0x800A,
192   FUNC_REVERSE_SUBTRACT: 0x800B,
193 
194   /* Separate Blend Functions */
195   BLEND_DST_RGB: 0x80C8,
196   BLEND_SRC_RGB: 0x80C9,
197   BLEND_DST_ALPHA: 0x80CA,
198   BLEND_SRC_ALPHA: 0x80CB,
199   CONSTANT_COLOR: 0x8001,
200   ONE_MINUS_CONSTANT_COLOR: 0x8002,
201   CONSTANT_ALPHA: 0x8003,
202   ONE_MINUS_CONSTANT_ALPHA: 0x8004,
203   BLEND_COLOR: 0x8005,
204 
205   /* Buffer Objects */
206   ARRAY_BUFFER: 0x8892,
207   ELEMENT_ARRAY_BUFFER: 0x8893,
208   ARRAY_BUFFER_BINDING: 0x8894,
209   ELEMENT_ARRAY_BUFFER_BINDING: 0x8895,
210 
211   STREAM_DRAW: 0x88E0,
212   STATIC_DRAW: 0x88E4,
213   DYNAMIC_DRAW: 0x88E8,
214 
215   BUFFER_SIZE: 0x8764,
216   BUFFER_USAGE: 0x8765,
217 
218   CURRENT_VERTEX_ATTRIB: 0x8626,
219 
220   /* CullFaceMode */
221   FRONT: 0x0404,
222   BACK: 0x0405,
223   FRONT_AND_BACK: 0x0408,
224 
225   /* DepthFunction */
226   /* NEVER: 0x0200, */
227   /* LESS: 0x0201, */
228   /* EQUAL: 0x0202, */
229   /* LEQUAL: 0x0203, */
230   /* GREATER: 0x0204, */
231   /* NOTEQUAL: 0x0205, */
232   /* GEQUAL: 0x0206, */
233   /* ALWAYS: 0x0207, */
234 
235   /* EnableCap */
236   /* TEXTURE_2D: 0x0DE1, */
237   CULL_FACE: 0x0B44,
238   BLEND: 0x0BE2,
239   DITHER: 0x0BD0,
240   STENCIL_TEST: 0x0B90,
241   DEPTH_TEST: 0x0B71,
242   SCISSOR_TEST: 0x0C11,
243   POLYGON_OFFSET_FILL: 0x8037,
244   SAMPLE_ALPHA_TO_COVERAGE: 0x809E,
245   SAMPLE_COVERAGE: 0x80A0,
246 
247   /* ErrorCode */
248   NO_ERROR: 0,
249   INVALID_ENUM: 0x0500,
250   INVALID_VALUE: 0x0501,
251   INVALID_OPERATION: 0x0502,
252   OUT_OF_MEMORY: 0x0505,
253 
254   /* FrontFaceDirection */
255   CW: 0x0900,
256   CCW: 0x0901,
257 
258   /* GetPName */
259   LINE_WIDTH: 0x0B21,
260   ALIASED_POINT_SIZE_RANGE: 0x846D,
261   ALIASED_LINE_WIDTH_RANGE: 0x846E,
262   CULL_FACE_MODE: 0x0B45,
263   FRONT_FACE: 0x0B46,
264   DEPTH_RANGE: 0x0B70,
265   DEPTH_WRITEMASK: 0x0B72,
266   DEPTH_CLEAR_VALUE: 0x0B73,
267   DEPTH_FUNC: 0x0B74,
268   STENCIL_CLEAR_VALUE: 0x0B91,
269   STENCIL_FUNC: 0x0B92,
270   STENCIL_FAIL: 0x0B94,
271   STENCIL_PASS_DEPTH_FAIL: 0x0B95,
272   STENCIL_PASS_DEPTH_PASS: 0x0B96,
273   STENCIL_REF: 0x0B97,
274   STENCIL_VALUE_MASK: 0x0B93,
275   STENCIL_WRITEMASK: 0x0B98,
276   STENCIL_BACK_FUNC: 0x8800,
277   STENCIL_BACK_FAIL: 0x8801,
278   STENCIL_BACK_PASS_DEPTH_FAIL: 0x8802,
279   STENCIL_BACK_PASS_DEPTH_PASS: 0x8803,
280   STENCIL_BACK_REF: 0x8CA3,
281   STENCIL_BACK_VALUE_MASK: 0x8CA4,
282   STENCIL_BACK_WRITEMASK: 0x8CA5,
283   VIEWPORT: 0x0BA2,
284   SCISSOR_BOX: 0x0C10,
285   /* SCISSOR_TEST: 0x0C11, */
286   COLOR_CLEAR_VALUE: 0x0C22,
287   COLOR_WRITEMASK: 0x0C23,
288   UNPACK_ALIGNMENT: 0x0CF5,
289   PACK_ALIGNMENT: 0x0D05,
290   MAX_TEXTURE_SIZE: 0x0D33,
291   MAX_VIEWPORT_DIMS: 0x0D3A,
292   SUBPIXEL_BITS: 0x0D50,
293   RED_BITS: 0x0D52,
294   GREEN_BITS: 0x0D53,
295   BLUE_BITS: 0x0D54,
296   ALPHA_BITS: 0x0D55,
297   DEPTH_BITS: 0x0D56,
298   STENCIL_BITS: 0x0D57,
299   POLYGON_OFFSET_UNITS: 0x2A00,
300   /* POLYGON_OFFSET_FILL: 0x8037, */
301   POLYGON_OFFSET_FACTOR: 0x8038,
302   TEXTURE_BINDING_2D: 0x8069,
303   SAMPLE_BUFFERS: 0x80A8,
304   SAMPLES: 0x80A9,
305   SAMPLE_COVERAGE_VALUE: 0x80AA,
306   SAMPLE_COVERAGE_INVERT: 0x80AB,
307 
308   /* DataType */
309   BYTE: 0x1400,
310   UNSIGNED_BYTE: 0x1401,
311   SHORT: 0x1402,
312   UNSIGNED_SHORT: 0x1403,
313   INT: 0x1404,
314   UNSIGNED_INT: 0x1405,
315   FLOAT: 0x1406,
316 
317   /* PixelFormat */
318   DEPTH_COMPONENT: 0x1902,
319   ALPHA: 0x1906,
320   RGB: 0x1907,
321   RGBA: 0x1908,
322   LUMINANCE: 0x1909,
323   LUMINANCE_ALPHA: 0x190A,
324 
325   /* PixelType */
326   /* UNSIGNED_BYTE: 0x1401, */
327   UNSIGNED_SHORT_4_4_4_4: 0x8033,
328   UNSIGNED_SHORT_5_5_5_1: 0x8034,
329   UNSIGNED_SHORT_5_6_5: 0x8363,
330 
331   /* Shaders */
332   FRAGMENT_SHADER: 0x8B30,
333   VERTEX_SHADER: 0x8B31,
334   MAX_VERTEX_ATTRIBS: 0x8869,
335   MAX_VERTEX_UNIFORM_VECTORS: 0x8DFB,
336   MAX_VARYING_VECTORS: 0x8DFC,
337   MAX_COMBINED_TEXTURE_IMAGE_UNITS: 0x8B4D,
338   MAX_VERTEX_TEXTURE_IMAGE_UNITS: 0x8B4C,
339   MAX_TEXTURE_IMAGE_UNITS: 0x8872,
340   MAX_FRAGMENT_UNIFORM_VECTORS: 0x8DFD,
341   SHADER_TYPE: 0x8B4F,
342   DELETE_STATUS: 0x8B80,
343   LINK_STATUS: 0x8B82,
344   VALIDATE_STATUS: 0x8B83,
345   ATTACHED_SHADERS: 0x8B85,
346   ACTIVE_UNIFORMS: 0x8B86,
347   ACTIVE_ATTRIBUTES: 0x8B89,
348   SHADING_LANGUAGE_VERSION: 0x8B8C,
349   CURRENT_PROGRAM: 0x8B8D,
350 
351   /* StencilFunction */
352   NEVER: 0x0200,
353   LESS: 0x0201,
354   EQUAL: 0x0202,
355   LEQUAL: 0x0203,
356   GREATER: 0x0204,
357   NOTEQUAL: 0x0205,
358   GEQUAL: 0x0206,
359   ALWAYS: 0x0207,
360 
361   /* StencilOp */
362   /* ZERO: 0, */
363   KEEP: 0x1E00,
364   REPLACE: 0x1E01,
365   INCR: 0x1E02,
366   DECR: 0x1E03,
367   INVERT: 0x150A,
368   INCR_WRAP: 0x8507,
369   DECR_WRAP: 0x8508,
370 
371   /* StringName */
372   VENDOR: 0x1F00,
373   RENDERER: 0x1F01,
374   VERSION: 0x1F02,
375 
376   /* TextureMagFilter */
377   NEAREST: 0x2600,
378   LINEAR: 0x2601,
379 
380   /* TextureMinFilter */
381   /* NEAREST: 0x2600, */
382   /* LINEAR: 0x2601, */
383   NEAREST_MIPMAP_NEAREST: 0x2700,
384   LINEAR_MIPMAP_NEAREST: 0x2701,
385   NEAREST_MIPMAP_LINEAR: 0x2702,
386   LINEAR_MIPMAP_LINEAR: 0x2703,
387 
388   /* TextureParameterName */
389   TEXTURE_MAG_FILTER: 0x2800,
390   TEXTURE_MIN_FILTER: 0x2801,
391   TEXTURE_WRAP_S: 0x2802,
392   TEXTURE_WRAP_T: 0x2803,
393 
394   /* TextureTarget */
395   TEXTURE_2D: 0x0DE1,
396   TEXTURE: 0x1702,
397 
398   TEXTURE_CUBE_MAP: 0x8513,
399   TEXTURE_BINDING_CUBE_MAP: 0x8514,
400   TEXTURE_CUBE_MAP_POSITIVE_X: 0x8515,
401   TEXTURE_CUBE_MAP_NEGATIVE_X: 0x8516,
402   TEXTURE_CUBE_MAP_POSITIVE_Y: 0x8517,
403   TEXTURE_CUBE_MAP_NEGATIVE_Y: 0x8518,
404   TEXTURE_CUBE_MAP_POSITIVE_Z: 0x8519,
405   TEXTURE_CUBE_MAP_NEGATIVE_Z: 0x851A,
406   MAX_CUBE_MAP_TEXTURE_SIZE: 0x851C,
407 
408   /* TextureUnit */
409   TEXTURE0: 0x84C0,
410   TEXTURE1: 0x84C1,
411   TEXTURE2: 0x84C2,
412   TEXTURE3: 0x84C3,
413   TEXTURE4: 0x84C4,
414   TEXTURE5: 0x84C5,
415   TEXTURE6: 0x84C6,
416   TEXTURE7: 0x84C7,
417   TEXTURE8: 0x84C8,
418   TEXTURE9: 0x84C9,
419   TEXTURE10: 0x84CA,
420   TEXTURE11: 0x84CB,
421   TEXTURE12: 0x84CC,
422   TEXTURE13: 0x84CD,
423   TEXTURE14: 0x84CE,
424   TEXTURE15: 0x84CF,
425   TEXTURE16: 0x84D0,
426   TEXTURE17: 0x84D1,
427   TEXTURE18: 0x84D2,
428   TEXTURE19: 0x84D3,
429   TEXTURE20: 0x84D4,
430   TEXTURE21: 0x84D5,
431   TEXTURE22: 0x84D6,
432   TEXTURE23: 0x84D7,
433   TEXTURE24: 0x84D8,
434   TEXTURE25: 0x84D9,
435   TEXTURE26: 0x84DA,
436   TEXTURE27: 0x84DB,
437   TEXTURE28: 0x84DC,
438   TEXTURE29: 0x84DD,
439   TEXTURE30: 0x84DE,
440   TEXTURE31: 0x84DF,
441   ACTIVE_TEXTURE: 0x84E0,
442 
443   /* TextureWrapMode */
444   REPEAT: 0x2901,
445   CLAMP_TO_EDGE: 0x812F,
446   MIRRORED_REPEAT: 0x8370,
447 
448   /* Uniform Types */
449   FLOAT_VEC2: 0x8B50,
450   FLOAT_VEC3: 0x8B51,
451   FLOAT_VEC4: 0x8B52,
452   INT_VEC2: 0x8B53,
453   INT_VEC3: 0x8B54,
454   INT_VEC4: 0x8B55,
455   BOOL: 0x8B56,
456   BOOL_VEC2: 0x8B57,
457   BOOL_VEC3: 0x8B58,
458   BOOL_VEC4: 0x8B59,
459   FLOAT_MAT2: 0x8B5A,
460   FLOAT_MAT3: 0x8B5B,
461   FLOAT_MAT4: 0x8B5C,
462   SAMPLER_2D: 0x8B5E,
463   SAMPLER_CUBE: 0x8B60,
464 
465   /* Vertex Arrays */
466   VERTEX_ATTRIB_ARRAY_ENABLED: 0x8622,
467   VERTEX_ATTRIB_ARRAY_SIZE: 0x8623,
468   VERTEX_ATTRIB_ARRAY_STRIDE: 0x8624,
469   VERTEX_ATTRIB_ARRAY_TYPE: 0x8625,
470   VERTEX_ATTRIB_ARRAY_NORMALIZED: 0x886A,
471   VERTEX_ATTRIB_ARRAY_POINTER: 0x8645,
472   VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: 0x889F,
473 
474   /* Shader Source */
475   COMPILE_STATUS: 0x8B81,
476 
477   /* Shader Precision-Specified Types */
478   LOW_FLOAT: 0x8DF0,
479   MEDIUM_FLOAT: 0x8DF1,
480   HIGH_FLOAT: 0x8DF2,
481   LOW_INT: 0x8DF3,
482   MEDIUM_INT: 0x8DF4,
483   HIGH_INT: 0x8DF5,
484 
485   /* Framebuffer Object. */
486   FRAMEBUFFER: 0x8D40,
487   RENDERBUFFER: 0x8D41,
488 
489   RGBA4: 0x8056,
490   RGB5_A1: 0x8057,
491   RGB565: 0x8D62,
492   DEPTH_COMPONENT16: 0x81A5,
493   STENCIL_INDEX: 0x1901,
494   STENCIL_INDEX8: 0x8D48,
495   DEPTH_STENCIL: 0x84F9,
496 
497   RENDERBUFFER_WIDTH: 0x8D42,
498   RENDERBUFFER_HEIGHT: 0x8D43,
499   RENDERBUFFER_INTERNAL_FORMAT: 0x8D44,
500   RENDERBUFFER_RED_SIZE: 0x8D50,
501   RENDERBUFFER_GREEN_SIZE: 0x8D51,
502   RENDERBUFFER_BLUE_SIZE: 0x8D52,
503   RENDERBUFFER_ALPHA_SIZE: 0x8D53,
504   RENDERBUFFER_DEPTH_SIZE: 0x8D54,
505   RENDERBUFFER_STENCIL_SIZE: 0x8D55,
506 
507   FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 0x8CD0,
508   FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 0x8CD1,
509   FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: 0x8CD2,
510   FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: 0x8CD3,
511 
512   COLOR_ATTACHMENT0: 0x8CE0,
513   DEPTH_ATTACHMENT: 0x8D00,
514   STENCIL_ATTACHMENT: 0x8D20,
515   DEPTH_STENCIL_ATTACHMENT: 0x821A,
516 
517   NONE: 0,
518 
519   FRAMEBUFFER_COMPLETE: 0x8CD5,
520   FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 0x8CD6,
521   FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 0x8CD7,
522   FRAMEBUFFER_INCOMPLETE_DIMENSIONS: 0x8CD9,
523   FRAMEBUFFER_UNSUPPORTED: 0x8CDD,
524 
525   FRAMEBUFFER_BINDING: 0x8CA6,
526   RENDERBUFFER_BINDING: 0x8CA7,
527   MAX_RENDERBUFFER_SIZE: 0x84E8,
528 
529   INVALID_FRAMEBUFFER_OPERATION: 0x0506,
530 
531   /* WebGL-specific enums */
532   UNPACK_FLIP_Y_WEBGL: 0x9240,
533   UNPACK_PREMULTIPLY_ALPHA_WEBGL: 0x9241,
534   CONTEXT_LOST_WEBGL: 0x9242,
535   UNPACK_COLORSPACE_CONVERSION_WEBGL: 0x9243,
536   BROWSER_DEFAULT_WEBGL: 0x9244
537 };
538 
539 /**
540  * An inner class that encapsulates the WebGL API to draw 2D shapes.
541  * @param {WebGLRenderingContext} context
542  * @constructor
543  */
544 createjs.WebGLRenderer.Context = function(context) {
545   /// <param type="WebGLRenderingContext" name="context"/>
546   // This renderer uses premultiplied alpha due to color composition.
547   context.pixelStorei(
548       createjs.WebGLRenderer.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
549 
550   /**
551    * The WebGL rendering context used by this object.
552    * @type {WebGLRenderingContext}
553    * @private
554    */
555   this.context_ = context;
556 
557   /**
558    * An ID assigned to this context.
559    * @type {number}
560    * @private
561    */
562   this.id_ = ++createjs.WebGLRenderer.id;
563 };
564 
565 /**
566  * The WebGLTexture object bound to this context.
567  * @type {WebGLTexture}
568  * @private
569  */
570 createjs.WebGLRenderer.Context.prototype.texture_ = null;
571 
572 /**
573  * Returns the WebGLRenderingContext object associated with this object.
574  * @return {WebGLRenderingContext}
575  * @const
576  */
577 createjs.WebGLRenderer.Context.prototype.getContext_ = function() {
578   /// <returns type="WebGLRenderingContext"/>
579   return this.context_;
580 };
581 
582 /**
583  * Returns the ID assigned to this context. Returning 0 represents this context
584  * does not have a drawing buffer.
585  * @return {number}
586  * @const
587  */
588 createjs.WebGLRenderer.Context.prototype.getId = function() {
589   /// <return type="number"/>
590   return this.id_;
591 };
592 
593 /**
594  * Sets an ID to this context.
595  * @param {number} id
596  * @const
597  */
598 createjs.WebGLRenderer.Context.prototype.setId = function(id) {
599   /// <param type="number" name="id"/>
600   this.id_ = id;
601 };
602 
603 /**
604  * Creates a vertex shader or a fragment shader and compiles it.
605  * @param {number} type
606  * @param {string} source
607  * @return {WebGLShader}
608  * @const
609  */
610 createjs.WebGLRenderer.Context.prototype.createShader = function(type, source) {
611   /// <param type="number" name="type"/>
612   /// <param type="string" name="source"/>
613   /// <returns type="WebGLShader"/>
614   var context = this.getContext_();
615   var shader = context.createShader(type);
616   context.shaderSource(shader, source);
617   context.compileShader(shader);
618   createjs.assert(!!context.getShaderParameter(
619       shader, createjs.WebGLRenderer.gl.COMPILE_STATUS));
620   return shader;
621 };
622 
623 /**
624  * Creates a vertex shader and compiles it.
625  * @param {string} source
626  * @return {WebGLShader}
627  * @const
628  */
629 createjs.WebGLRenderer.Context.prototype.createVertexShader = function(source) {
630   /// <param type="string" name="source"/>
631   /// <returns type="WebGLShader"/>
632   return this.createShader(createjs.WebGLRenderer.gl.VERTEX_SHADER, source);
633 };
634 
635 /**
636  * Creates a fragment shader and compiles it.
637  * @param {string} source
638  * @return {WebGLShader}
639  * @const
640  */
641 createjs.WebGLRenderer.Context.prototype.createFragmentShader =
642     function(source) {
643   /// <param type="string" name="source"/>
644   /// <returns type="WebGLShader"/>
645   return this.createShader(createjs.WebGLRenderer.gl.FRAGMENT_SHADER, source);
646 };
647 
648 /**
649  * Deletes a shader.
650  * @param {WebGLShader} shader
651  * @const
652  */
653 createjs.WebGLRenderer.Context.prototype.deleteShader = function(shader) {
654   this.getContext_().deleteShader(shader);
655 };
656 
657 /**
658  * Creates a shader program.
659  * @param {WebGLShader} vertex
660  * @param {WebGLShader} fragment
661  * @return {WebGLProgram}
662  * @const
663  */
664 createjs.WebGLRenderer.Context.prototype.createProgram =
665     function(vertex, fragment) {
666   /// <param type="WebGLShader" name="vertex"/>
667   /// <param type="WebGLShader" name="fragment"/>
668   /// <returns type="WebGLProgram"/>
669   var context = this.getContext_();
670   var program = context.createProgram();
671   context.attachShader(program, vertex);
672   context.attachShader(program, fragment);
673   context.linkProgram(program);
674   context.useProgram(program);
675   return program;
676 };
677 
678 /**
679  * Deletes a shader program.
680  * @param {WebGLProgram} program
681  * @const
682  */
683 createjs.WebGLRenderer.Context.prototype.deleteProgram = function(program) {
684   /// <param type="WebGLProgram" name="program"/>
685   this.getContext_().deleteProgram(program);
686 };
687 
688 /**
689  * Binds the specified shader program and uses it.
690  * @param {WebGLProgram} program
691  * @const
692  */
693 createjs.WebGLRenderer.Context.prototype.useProgram = function(program) {
694   /// <param type="WebGLProgram" name="program"/>
695   this.getContext_().useProgram(program);
696 };
697 
698 /**
699  * Returns the location to the specified color.
700  * @param {WebGLProgram} program
701  * @param {string} key
702  * @return {WebGLUniformLocation}
703  * @const
704  */
705 createjs.WebGLRenderer.Context.prototype.getColor = function(program, key) {
706   /// <param type="WebGLProgram" name="program"/>
707   /// <param type="string" name="key"/>
708   /// <returns type="WebGLUniformLocation"/>
709   return this.getContext_().getUniformLocation(program, key);
710 };
711 
712 /**
713  * Sets the values of the specified color.
714  * @param {WebGLUniformLocation} color
715  * @param {number} red
716  * @param {number} green
717  * @param {number} blue
718  * @param {number} alpha
719  * @const
720  */
721 createjs.WebGLRenderer.Context.prototype.setColor =
722     function(color, red, green, blue, alpha) {
723   /// <param type="WebGLUniformLocation" name="color"/>
724   /// <param type="number" name="red"/>
725   /// <param type="number" name="green"/>
726   /// <param type="number" name="blue"/>
727   /// <param type="number" name="alpha"/>
728   this.getContext_().uniform4f(color, red, green, blue, alpha);
729 };
730 
731 /**
732  * Returns the location to the specified point.
733  * @param {WebGLProgram} program
734  * @param {string} key
735  * @return {WebGLUniformLocation}
736  * @const
737  */
738 createjs.WebGLRenderer.Context.prototype.getPoint = function(program, key) {
739   /// <param type="WebGLProgram" name="program"/>
740   /// <param type="string" name="key"/>
741   /// <returns type="WebGLUniformLocation"/>
742   return this.getContext_().getUniformLocation(program, key);
743 };
744 
745 /**
746  * Sets the values of the specified point.
747  * @param {WebGLUniformLocation} point
748  * @param {number} x
749  * @param {number} y
750  * @const
751  */
752 createjs.WebGLRenderer.Context.prototype.setPoint = function(point, x, y) {
753   /// <param type="WebGLUniformLocation" name="point"/>
754   /// <param type="number" name="x"/>
755   /// <param type="number" name="y"/>
756   this.getContext_().uniform2f(point, x, y);
757 };
758 
759 /**
760  * Creates an array buffer used by rectangles with the specified values.
761  * @param {Float32Array} points
762  * @return {WebGLBuffer}
763  * @const
764  */
765 createjs.WebGLRenderer.Context.prototype.createRectangleBuffer =
766     function(points) {
767   /// <returns type="WebGLBuffer"/>
768   var buffer = this.getContext_().createBuffer();
769   this.setRectangleBuffer(buffer, points);
770   return buffer;
771 };
772 
773 /**
774  * Deletes a WebGLBuffer object used by rectangles.
775  * @param {WebGLBuffer} buffer
776  * @const
777  */
778 createjs.WebGLRenderer.Context.prototype.deleteRectangleBuffer =
779     function(buffer) {
780   /// <param type="WebGLBuffer" name="buffer"/>
781   this.getContext_().deleteBuffer(buffer);
782 };
783 
784 /**
785  * Sets the specified values to the array buffer.
786  * @param {WebGLBuffer} buffer
787  * @param {Float32Array} points
788  * @const
789  */
790 createjs.WebGLRenderer.Context.prototype.setRectangleBuffer =
791     function(buffer, points) {
792   /// <param type="WebGLBuffer" name="buffer"/>
793   /// <param type="Float32Array" name="points"/>
794   var context = this.getContext_();
795   context.bindBuffer(createjs.WebGLRenderer.gl.ARRAY_BUFFER, buffer);
796   context.bufferData(
797       createjs.WebGLRenderer.gl.ARRAY_BUFFER,
798       points,
799       createjs.WebGLRenderer.gl.STATIC_DRAW);
800 };
801 
802 /**
803  * Retrieves the location to an attribute and assigns it to the WebGLBuffer
804  * object currently bound to this context. (This method expects to be called
805  * after a createRectangleBuffer() call or a setRectangleBuffer() call.)
806  * @param {WebGLProgram} program
807  * @param {string} key
808  * @return {number}
809  * @const
810  */
811 createjs.WebGLRenderer.Context.prototype.getRectangleAttribute =
812     function(program, key) {
813   /// <param type="WebGLProgram" name="program"/>
814   /// <param type="string" name="key"/>
815   /// <returns type="number"/>
816   var context = this.getContext_();
817   var attribute = context.getAttribLocation(program, key);
818   context.enableVertexAttribArray(attribute);
819   context.vertexAttribPointer(
820       attribute, 2, createjs.WebGLRenderer.gl.FLOAT, false, 0, 0);
821   return attribute;
822 };
823 
824 /**
825  * Retrieves the location to the specified transform.
826  * @param {WebGLProgram} program
827  * @param {string} key
828  * @return {WebGLUniformLocation}
829  * @const
830  */
831 createjs.WebGLRenderer.Context.prototype.getTransform = function(program, key) {
832   /// <param type="WebGLProgram" name="program"/>
833   /// <param type="string" name="key"/>
834   /// <returns type="WebGLUniformLocation"/>
835   return this.getContext_().getUniformLocation(program, key);
836 };
837 
838 /**
839  * Sets the values to the specified transform.
840  * @param {WebGLUniformLocation} transform
841  * @param {Float32Array} matrix
842  * @const
843  */
844 createjs.WebGLRenderer.Context.prototype.setTransform =
845     function(transform, matrix) {
846   /// <param type="WebGLUniformLocation" name="transform"/>
847   /// <param type="Float32Array" name="matrix"/>
848   this.getContext_().uniformMatrix3fv(transform, false, matrix);
849 };
850 
851 /**
852  * Retrieves the location to the specified color matrix.
853  * @param {WebGLProgram} program
854  * @param {string} key
855  * @return {WebGLUniformLocation}
856  * @const
857  */
858 createjs.WebGLRenderer.Context.prototype.getColorMatrix =
859     function(program, key) {
860   /// <param type="WebGLProgram" name="program"/>
861   /// <param type="string" name="key"/>
862   /// <returns type="WebGLUniformLocation"/>
863   return this.getContext_().getUniformLocation(program, key);
864 };
865 
866 /**
867  * Sets the values to the specified color matrix.
868  * @param {WebGLUniformLocation} color
869  * @param {Float32Array} matrix
870  * @const
871  */
872 createjs.WebGLRenderer.Context.prototype.setColorMatrix =
873     function(color, matrix) {
874   /// <param type="WebGLUniformLocation" name="color"/>
875   /// <param type="Float32Array" name="matrix"/>
876   this.getContext_().uniformMatrix4fv(color, false, matrix);
877 };
878 
879 /**
880  * Retrieves the texture type for the specified image.
881  * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image
882  * @return {number}
883  * @const
884  */
885 createjs.WebGLRenderer.Context.prototype.getTextureType = function(image) {
886   /// <signature>
887   ///   <param type="HTMLImageElement" name="image"/>
888   ///   <returns type="number"/>
889   /// </signature>
890   /// <signature>
891   ///   <param type="HTMLCanvasElement" name="canvas"/>
892   ///   <returns type="number"/>
893   /// </signature>
894   /// <signature>
895   ///   <param type="HTMLVideoElement" name="video"/>
896   ///   <returns type="number"/>
897   /// </signature>
898   var TYPES = [
899     createjs.WebGLRenderer.gl.UNSIGNED_BYTE,
900     createjs.WebGLRenderer.gl.UNSIGNED_SHORT_4_4_4_4,
901     createjs.WebGLRenderer.gl.UNSIGNED_SHORT_5_5_5_1,
902     createjs.WebGLRenderer.gl.UNSIGNED_SHORT_5_6_5
903   ];
904   var format = image.format_ || 0;
905   return TYPES[format];
906 };
907 
908 /**
909  * Creates a new texture from an HTMLImageElement object, an HTMLCanvasElement
910  * object, or an HTMLVideoElement object.
911  * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image
912  * @return {WebGLTexture}
913  * @const
914  */
915 createjs.WebGLRenderer.Context.prototype.createTexture = function(image) {
916   /// <signature>
917   ///   <param type="HTMLImageElement" name="image"/>
918   ///   <returns type="WebGLTexture"/>
919   /// </signature>
920   /// <signature>
921   ///   <param type="HTMLCanvasElement" name="canvas"/>
922   ///   <returns type="WebGLTexture"/>
923   /// </signature>
924   /// <signature>
925   ///   <param type="HTMLVideoElement" name="video"/>
926   ///   <returns type="WebGLTexture"/>
927   /// </signature>
928   var context = this.getContext_();
929   var texture = context.createTexture();
930   var type = this.getTextureType(image);
931   context.bindTexture(createjs.WebGLRenderer.gl.TEXTURE_2D, texture);
932   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
933                         createjs.WebGLRenderer.gl.TEXTURE_WRAP_S,
934                         createjs.WebGLRenderer.gl.CLAMP_TO_EDGE);
935   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
936                         createjs.WebGLRenderer.gl.TEXTURE_WRAP_T,
937                         createjs.WebGLRenderer.gl.CLAMP_TO_EDGE);
938   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
939                         createjs.WebGLRenderer.gl.TEXTURE_MIN_FILTER,
940                         createjs.WebGLRenderer.gl.LINEAR);
941   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
942                         createjs.WebGLRenderer.gl.TEXTURE_MAG_FILTER,
943                         createjs.WebGLRenderer.gl.LINEAR);
944   context.texImage2D(createjs.WebGLRenderer.gl.TEXTURE_2D,
945                      0,
946                      createjs.WebGLRenderer.gl.RGBA,
947                      createjs.WebGLRenderer.gl.RGBA,
948                      type,
949                      image);
950   this.texture_ = texture;
951   return texture;
952 };
953 
954 /**
955  * Deletes a texture.
956  * @param {WebGLTexture} texture
957  * @const
958  */
959 createjs.WebGLRenderer.Context.prototype.deleteTexture = function(texture) {
960   /// <param type="WebGLTexture" name="texture"/>
961   this.getContext_().deleteTexture(texture);
962 };
963 
964 /**
965  * Binds the specified texture.
966  * @param {WebGLTexture} texture
967  * @const
968  */
969 createjs.WebGLRenderer.Context.prototype.bindTexture = function(texture) {
970   /// <param type="WebGLTexture" name="texture"/>
971   if (this.texture_ === texture) {
972     return;
973   }
974   this.getContext_().bindTexture(createjs.WebGLRenderer.gl.TEXTURE_2D, texture);
975   this.texture_ = texture;
976 };
977 
978 /**
979  * Sets the filters of the texture bound to this context.
980  * @param {boolean} smoothing
981  * @const
982  */
983 createjs.WebGLRenderer.Context.prototype.setFilter = function(smoothing) {
984   /// <param type="boolean" name="filter"/>
985   var context = this.getContext_();
986   var filter = smoothing ?
987       createjs.WebGLRenderer.gl.LINEAR : createjs.WebGLRenderer.gl.NEAREST;
988   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
989                         createjs.WebGLRenderer.gl.TEXTURE_MIN_FILTER,
990                         filter);
991   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
992                         createjs.WebGLRenderer.gl.TEXTURE_MAG_FILTER,
993                         filter);
994 };
995 
996 /**
997  * Updates the image of the texture bound to this context.
998  * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image
999  * @const
1000  */
1001 createjs.WebGLRenderer.Context.prototype.updateTexture = function(image) {
1002   /// <signature>
1003   ///   <param type="HTMLImageElement" name="image"/>
1004   /// </signature>
1005   /// <signature>
1006   ///   <param type="HTMLCanvasElement" name="canvas"/>
1007   /// </signature>
1008   /// <signature>
1009   ///   <param type="HTMLVideoElement" name="video"/>
1010   /// </signature>
1011   var type = this.getTextureType(image);
1012   this.getContext_().texImage2D(createjs.WebGLRenderer.gl.TEXTURE_2D,
1013                                 0,
1014                                 createjs.WebGLRenderer.gl.RGBA,
1015                                 createjs.WebGLRenderer.gl.RGBA,
1016                                 type,
1017                                 image);
1018 };
1019 
1020 /**
1021  * Creates a texture to be bound to a frame buffer.
1022  * @param {number} width
1023  * @param {number} height
1024  * @param {number} type
1025  * @return {WebGLTexture}
1026  * @const
1027  */
1028 createjs.WebGLRenderer.Context.prototype.createFrameTexture =
1029     function(width, height, type) {
1030   /// <param type="number" name="width"/>
1031   /// <param type="number" name="height"/>
1032   /// <param type="number" name="type"/>
1033   /// <returns type="WebGLTexture"/>
1034   var context = this.getContext_();
1035   var texture = context.createTexture();
1036   context.bindTexture(createjs.WebGLRenderer.gl.TEXTURE_2D, texture);
1037   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
1038                         createjs.WebGLRenderer.gl.TEXTURE_WRAP_S,
1039                         createjs.WebGLRenderer.gl.CLAMP_TO_EDGE);
1040   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
1041                         createjs.WebGLRenderer.gl.TEXTURE_WRAP_T,
1042                         createjs.WebGLRenderer.gl.CLAMP_TO_EDGE);
1043   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
1044                         createjs.WebGLRenderer.gl.TEXTURE_MIN_FILTER,
1045                         createjs.WebGLRenderer.gl.LINEAR);
1046   context.texParameteri(createjs.WebGLRenderer.gl.TEXTURE_2D,
1047                         createjs.WebGLRenderer.gl.TEXTURE_MAG_FILTER,
1048                         createjs.WebGLRenderer.gl.LINEAR);
1049   context.texImage2D(createjs.WebGLRenderer.gl.TEXTURE_2D,
1050                      0,
1051                      createjs.WebGLRenderer.gl.RGBA,
1052                      width,
1053                      height,
1054                      0,
1055                      createjs.WebGLRenderer.gl.RGBA,
1056                      type,
1057                      null);
1058   this.texture_ = texture;
1059   return texture;
1060 };
1061 
1062 /**
1063  * Creates a new frame buffer and binds the specified texture to it.
1064  * @param {WebGLTexture} texture
1065  * @return {WebGLFramebuffer}
1066  * @const
1067  */
1068 createjs.WebGLRenderer.Context.prototype.createFramebuffer = function(texture) {
1069   /// <param type="WebGLTexture" name="texture"/>
1070   /// <returns type="WebGLFramebuffer"/>
1071   var context = this.getContext_();
1072   var buffer = context.createFramebuffer();
1073   context.bindFramebuffer(createjs.WebGLRenderer.gl.FRAMEBUFFER, buffer);
1074   context.framebufferTexture2D(createjs.WebGLRenderer.gl.FRAMEBUFFER,
1075                                createjs.WebGLRenderer.gl.COLOR_ATTACHMENT0,
1076                                createjs.WebGLRenderer.gl.TEXTURE_2D,
1077                                texture,
1078                                0);
1079   return buffer;
1080 };
1081 
1082 /**
1083  * Deletes a frame buffer.
1084  * @param {WebGLFramebuffer} buffer
1085  * @const
1086  */
1087 createjs.WebGLRenderer.Context.prototype.deleteFramebuffer = function(buffer) {
1088   /// <param type="WebGLFramebuffer" name="buffer"/>
1089   this.getContext_().deleteFramebuffer(buffer);
1090 };
1091 
1092 /**
1093  * Binds the specified frame buffer.
1094  * @param {WebGLFramebuffer} buffer
1095  * @const
1096  */
1097 createjs.WebGLRenderer.Context.prototype.bindFramebuffer = function(buffer) {
1098   /// <param type="WebGLFramebuffer" name="buffer"/>
1099   var context = this.getContext_();
1100   context.bindFramebuffer(createjs.WebGLRenderer.gl.FRAMEBUFFER, buffer);
1101 };
1102 
1103 /**
1104  * Enables clipping.
1105  * @const
1106  */
1107 createjs.WebGLRenderer.Context.prototype.enableClip = function() {
1108   this.getContext_().enable(createjs.WebGLRenderer.gl.SCISSOR_TEST);
1109 };
1110 
1111 /**
1112  * Updates the clipping rectangle. This method converts the given bounding box
1113  * (in the HTML coordinate) to a scissor rectangle (in the WebGL coordinate) and
1114  * uses the converted rectangle for the scissor test. (WebGL uses the bottom-up
1115  * coordinate system for scissor rectangles, i.e. (0,0) represents the
1116  * bottom-left corner of a scissor rectangle and (width,height) represents its
1117  * top-right corner, respectively.)
1118  * @param {createjs.BoundingBox} clip
1119  * @param {number} height
1120  * @const
1121  */
1122 createjs.WebGLRenderer.Context.prototype.updateClip = function(clip, height) {
1123   /// <param type="createjs.BoundingBox" name="clip"/>
1124   /// <param type="number" name="height"/>
1125   var minX = clip.minX;
1126   var minY = clip.minY;
1127   var maxX = clip.maxX;
1128   var maxY = clip.maxY;
1129   this.getContext_().scissor(minX, height - maxY, maxX - minX, maxY - minY);
1130 };
1131 
1132 /**
1133  * Disables clipping.
1134  * @const
1135  */
1136 createjs.WebGLRenderer.Context.prototype.disableClip = function() {
1137   this.getContext_().disable(createjs.WebGLRenderer.gl.SCISSOR_TEST);
1138 };
1139 
1140 /**
1141  * Clears the drawing buffer (or a framebuffer) bound to this context.
1142  * @const
1143  */
1144 createjs.WebGLRenderer.Context.prototype.clear = function() {
1145   this.getContext_().clear(createjs.WebGLRenderer.gl.COLOR_BUFFER_BIT);
1146 };
1147 
1148 /**
1149  * Draws a rectangle. (This renderer uses a triangle strip as a rectangle.)
1150  * @const
1151  */
1152 createjs.WebGLRenderer.Context.prototype.drawRectangle = function() {
1153   this.getContext_().drawArrays(createjs.WebGLRenderer.gl.TRIANGLE_STRIP, 0, 4);
1154 };
1155 
1156 /**
1157  * Enables color blending and initializes its equations.
1158  * @const
1159  */
1160 createjs.WebGLRenderer.Context.prototype.enableBlend = function() {
1161   var context = this.getContext_();
1162   context.enable(createjs.WebGLRenderer.gl.BLEND);
1163   context.blendEquation(createjs.WebGLRenderer.gl.FUNC_ADD);
1164 };
1165 
1166 /**
1167  * Sets a blending function that emulates the specified composite operation.
1168  * This renderer renders only the region inside of a display object to be
1169  * rendered, i.e. it does not change its outside. This means it is hard to
1170  * emulate composite operations that needs to change the outside of a display
1171  * object, e.g. source-in, source-out, etc.
1172  * @param {number} operation
1173  * @const
1174  */
1175 createjs.WebGLRenderer.Context.prototype.setBlend = function(operation) {
1176   /// <param type="number" name="operation"/>
1177   var BLEND = [
1178     // source-over
1179     createjs.WebGLRenderer.gl.ONE,
1180     createjs.WebGLRenderer.gl.ONE_MINUS_SRC_ALPHA,
1181     // source-atop
1182     createjs.WebGLRenderer.gl.DST_ALPHA,
1183     createjs.WebGLRenderer.gl.ONE,
1184     // source-in (*)
1185     createjs.WebGLRenderer.gl.DST_ALPHA,
1186     createjs.WebGLRenderer.gl.ZERO,
1187     // source-out (*)
1188     createjs.WebGLRenderer.gl.ONE_MINUS_DST_ALPHA,
1189     createjs.WebGLRenderer.gl.ZERO,
1190     // destination-over
1191     createjs.WebGLRenderer.gl.ONE_MINUS_DST_ALPHA,
1192     createjs.WebGLRenderer.gl.ONE,
1193     // destination-atop (*)
1194     createjs.WebGLRenderer.gl.ONE,
1195     createjs.WebGLRenderer.gl.SRC_ALPHA,
1196     // destination-in (*)
1197     createjs.WebGLRenderer.gl.ZERO,
1198     createjs.WebGLRenderer.gl.SRC_ALPHA,
1199     // destination-out
1200     createjs.WebGLRenderer.gl.ZERO,
1201     createjs.WebGLRenderer.gl.ONE_MINUS_SRC_ALPHA,
1202     // lighter
1203     createjs.WebGLRenderer.gl.ONE,
1204     createjs.WebGLRenderer.gl.ONE,
1205     // copy
1206     createjs.WebGLRenderer.gl.ONE,
1207     createjs.WebGLRenderer.gl.ZERO,
1208     // xor
1209     createjs.WebGLRenderer.gl.ONE_MINUS_DST_ALPHA,
1210     createjs.WebGLRenderer.gl.ONE_MINUS_SRC_ALPHA,
1211     // darker (*)
1212     createjs.WebGLRenderer.gl.DST_COLOR,
1213     createjs.WebGLRenderer.gl.ONE,
1214     // multiply (*)
1215     createjs.WebGLRenderer.gl.ZERO,
1216     createjs.WebGLRenderer.gl.SRC_COLOR
1217   ];
1218   operation <<= 1;
1219   this.getContext_().blendFunc(BLEND[operation], BLEND[operation + 1]);
1220 };
1221 
1222 /**
1223  * Sets the viewport rectangle.
1224  * @param {number} width
1225  * @param {number} height
1226  * @const
1227  */
1228 createjs.WebGLRenderer.Context.prototype.setViewport = function(width, height) {
1229   /// <param type="number" name="width"/>
1230   /// <param type="number" name="height"/>
1231   this.getContext_().viewport(0, 0, width, height);
1232 };
1233 
1234 /**
1235  * An inner class that encapsulates a composite alpha used by this renderer.
1236  * This renderer uses a uniform vector (alpha, alpha, alpha, alpha) so it can
1237  * pre-multiply this composite alpha to RGB colors.
1238  * @param {createjs.WebGLRenderer.Context} context
1239  * @param {WebGLProgram} program
1240  * @param {string} key
1241  * @param {number} alpha
1242  * @constructor
1243  */
1244 createjs.WebGLRenderer.Alpha =
1245     function(context, program, key, alpha) {
1246   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1247   /// <param type="WebGLProgram" name="program"/>
1248   /// <param type="string" name="key"/>
1249   /// <param type="number" name="alpha"/>
1250   /**
1251    * The dirty flag.
1252    * @type {boolean}
1253    * @private
1254    */
1255   this.dirty_ = true;
1256 
1257   /**
1258    * The uniform location representing this color.
1259    * @type {WebGLUniformLocation}
1260    * @private
1261    */
1262   this.color_ = context.getColor(program, key);
1263 
1264   /**
1265    * The alpha component.
1266    * @type {number}
1267    * @private
1268    */
1269   this.alpha_ = alpha;
1270 };
1271 
1272 /**
1273  * Changes the alpha value of this color.
1274  * @param {number} alpha
1275  * @const
1276  */
1277 createjs.WebGLRenderer.Alpha.prototype.setAlpha = function(alpha) {
1278   /// <param type="number" name="alpha"/>
1279   if (this.alpha_ != alpha) {
1280     this.dirty_ = true;
1281     this.alpha_ = alpha;
1282   }
1283 };
1284 
1285 /**
1286  * Binds this color to the specified context.
1287  * @param {createjs.WebGLRenderer.Context} context
1288  */
1289 createjs.WebGLRenderer.Alpha.prototype.bindContext = function(context) {
1290   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1291   if (this.dirty_) {
1292     this.dirty_ = false;
1293     context.setColor(
1294         this.color_, this.alpha_, this.alpha_, this.alpha_, this.alpha_);
1295   }
1296 };
1297 
1298 /**
1299  * An inner class that encapsulates a point used by this renderer. This renderer
1300  * uses a uniform vector (x, y) to represent a point.
1301  * @param {createjs.WebGLRenderer.Context} context
1302  * @param {WebGLProgram} program
1303  * @param {string} key
1304  * @param {number} x
1305  * @param {number} y
1306  * @constructor
1307  */
1308 createjs.WebGLRenderer.Vector = function(context, program, key, x, y) {
1309   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1310   /// <param type="WebGLProgram" name="program"/>
1311   /// <param type="string" name="key"/>
1312   /// <param type="number" name="x"/>
1313   /// <param type="number" name="y"/>
1314   /**
1315    * The dirty flag.
1316    * @type {boolean}
1317    * @private
1318    */
1319   this.dirty_ = true;
1320 
1321   /**
1322    * The uniform location representing this vector.
1323    * @type {WebGLUniformLocation}
1324    * @private
1325    */
1326   this.point_ = context.getPoint(program, key);
1327 
1328   /**
1329    * The x coordinate.
1330    * @type {number}
1331    * @private
1332    */
1333   this.x_ = x;
1334 
1335   /**
1336    * The y coordinate.
1337    * @type {number}
1338    * @private
1339    */
1340   this.y_ = y;
1341 };
1342 
1343 /**
1344  * Changes this point.
1345  * @param {number} x
1346  * @param {number} y
1347  */
1348 createjs.WebGLRenderer.Vector.prototype.set = function(x, y) {
1349   /// <param type="number" name="x"/>
1350   /// <param type="number" name="y"/>
1351   if (this.x_ != x || this.y_ != y) {
1352     this.dirty_ = true;
1353     this.x_ = x;
1354     this.y_ = y;
1355   }
1356 };
1357 
1358 /**
1359  * Binds this point to the specified context.
1360  * @param {createjs.WebGLRenderer.Context} context
1361  */
1362 createjs.WebGLRenderer.Vector.prototype.bindContext = function(context) {
1363   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1364   if (this.dirty_) {
1365     this.dirty_ = false;
1366     context.setPoint(this.point_, this.x_, this.y_);
1367   }
1368 };
1369 
1370 /**
1371  * An inner class that encapsulates a rectangle used by this renderer. This
1372  * renderer uses a couple of triangles (0,0)-(width,0)-(0,height) and
1373  * (width,0)-(0,height)-(width,height) to represent a rectangle.
1374  *       (0,0) +--+ (width,0)
1375  *             | /|
1376  *             |/ |
1377  *  (0,height) +--+ (width,height)
1378  * @param {createjs.WebGLRenderer.Context} context
1379  * @param {WebGLProgram} program
1380  * @param {string} key
1381  * @param {number} width
1382  * @param {number} height
1383  * @constructor
1384  */
1385 createjs.WebGLRenderer.Rectangle =
1386     function(context, program, key, width, height) {
1387   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1388   /// <param type="WebGLProgram" name="program"/>
1389   /// <param type="string" name="key"/>
1390   /// <param type="number" name="width"/>
1391   /// <param type="number" name="height"/>
1392   /**
1393    * An array representing this triable strip.
1394    * @type {Float32Array}
1395    * @private
1396    */
1397   this.points_ = new Float32Array([
1398     0, 0,
1399     width, 0,
1400     0, height,
1401     width, height
1402   ]);
1403 
1404   /**
1405    * The WebGL buffer (or GPU memory) stores the above array.
1406    * @type {WebGLBuffer}
1407    * @private
1408    */
1409   this.buffer_ = context.createRectangleBuffer(this.points_);
1410 
1411   /**
1412    * The attribute representing this rectangle.
1413    * @type {number}
1414    * @private
1415    */
1416   this.attribute_ = context.getRectangleAttribute(program, key);
1417 };
1418 
1419 /**
1420  * Deletes all resources used by this rectangle.
1421  * @param {createjs.WebGLRenderer.Context} context
1422  * @const
1423  */
1424 createjs.WebGLRenderer.Rectangle.prototype.destroy = function(context) {
1425   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1426   context.deleteRectangleBuffer(this.buffer_);
1427 };
1428 
1429 /**
1430  * Sets this rectangle.
1431  * @param {number} x
1432  * @param {number} y
1433  * @param {number} width
1434  * @param {number} height
1435  * @const
1436  */
1437 createjs.WebGLRenderer.Rectangle.prototype.set = function(x, y, width, height) {
1438   /// <param type="number" name="x"/>
1439   /// <param type="number" name="y"/>
1440   /// <param type="number" name="width"/>
1441   /// <param type="number" name="height"/>
1442   var minX = x;
1443   var minY = y;
1444   var maxX = x + width;
1445   var maxY = y + height;
1446   this.points_[0] = minX;
1447   this.points_[1] = minY;
1448   this.points_[2] = maxX;
1449   this.points_[3] = minY;
1450   this.points_[4] = minX;
1451   this.points_[5] = maxY;
1452   this.points_[6] = maxX;
1453   this.points_[7] = maxY;
1454 };
1455 
1456 /**
1457  * Binds this rectangle to the specified context.
1458  * @param {createjs.WebGLRenderer.Context} context
1459  */
1460 createjs.WebGLRenderer.Rectangle.prototype.bindContext = function(context) {
1461   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1462   context.setRectangleBuffer(this.buffer_, this.points_);
1463 };
1464 
1465 /**
1466  * An inner class that encapsulates an affine transform used by this renderer.
1467  * This renderer uses a 3x3 matrix listed below to apply an affine
1468  * transform used by the Canvas 2D API in its vertex shader. (This class uses
1469  * transposed matrices because WebGL uses them by default.)
1470  *   | a  b  0 |
1471  *   | c  d  0 |
1472  *   | tx ty 1 |
1473  * @param {createjs.WebGLRenderer.Context} context
1474  * @param {WebGLProgram} program
1475  * @param {string} key
1476  * @constructor
1477  */
1478 createjs.WebGLRenderer.Transform = function(context, program, key) {
1479   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1480   /// <param type="WebGLProgram" name="program"/>
1481   /// <param type="string" name="key"/>
1482   /**
1483    * The uniform location representing this transform.
1484    * @type {WebGLUniformLocation}
1485    * @private
1486    */
1487   this.transform_ = context.getTransform(program, key);
1488 
1489   /**
1490    * The transformation matrix.
1491    * @type {Float32Array}
1492    * @private
1493    */
1494   this.matrix_ = new Float32Array([
1495     1, 0, 0,
1496     0, 1, 0,
1497     0, 0, 1
1498   ]);
1499 };
1500 
1501 /**
1502  * Sets this transform.
1503  * @param {number} a
1504  * @param {number} b
1505  * @param {number} c
1506  * @param {number} d
1507  * @param {number} tx
1508  * @param {number} ty
1509  */
1510 createjs.WebGLRenderer.Transform.prototype.set = function(a, b, c, d, tx, ty) {
1511   /// <param type="number" name="a"/>
1512   /// <param type="number" name="b"/>
1513   /// <param type="number" name="c"/>
1514   /// <param type="number" name="d"/>
1515   /// <param type="number" name="tx"/>
1516   /// <param type="number" name="ty"/>
1517   this.matrix_[0] = a;
1518   this.matrix_[1] = b;
1519   this.matrix_[2] = 0;
1520   this.matrix_[3] = c;
1521   this.matrix_[4] = d;
1522   this.matrix_[5] = 0;
1523   this.matrix_[6] = tx;
1524   this.matrix_[7] = ty;
1525   this.matrix_[8] = 1;
1526 };
1527 
1528 /**
1529  * Binds this transform to the specified context.
1530  * @param {createjs.WebGLRenderer.Context} context
1531  * @const
1532  */
1533 createjs.WebGLRenderer.Transform.prototype.bindContext = function(context) {
1534   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1535   context.setTransform(this.transform_, this.matrix_);
1536 };
1537 
1538 /**
1539  * An inner class that encapsulates a color-transform matrix used by a
1540  * color-matrix filter. This matrix is a transposed 4x4 matrix as listed below.
1541  * (The uniformMatrix4fv() method needs a transposed matrix on Chrome and
1542  * Firefox.)
1543  *   | m00 m10 m20 m30 |
1544  *   | m01 m11 m21 m31 |
1545  *   | m02 m12 m22 m32 |
1546  *   | m03 m13 m23 m33 |
1547  * @param {createjs.WebGLRenderer.Context} context
1548  * @param {WebGLProgram} program
1549  * @param {string} key
1550  * @constructor
1551  */
1552 createjs.WebGLRenderer.ColorMatrix = function(context, program, key) {
1553   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1554   /// <param type="WebGLProgram" name="program"/>
1555   /// <param type="string" name="key"/>
1556   /**
1557    * The dirty flag.
1558    * @type {boolean}
1559    * @private
1560    */
1561   this.dirty_ = true;
1562 
1563   /**
1564    * The OpenGL attribute representing this matrix.
1565    * @type {WebGLUniformLocation}
1566    * @private
1567    */
1568   this.transform_ = context.getColorMatrix(program, key);
1569 
1570   /**
1571    * The values of this matrix.
1572    * @type {Float32Array}
1573    * @private
1574    */
1575   this.matrix_ = new Float32Array([
1576     1, 0, 0, 0,
1577     0, 1, 0, 0,
1578     0, 0, 1, 0,
1579     0, 0, 0, 1
1580   ]);
1581 };
1582 
1583 /**
1584  * Sets the values of this matrix. This method transposes the top-left 3x3
1585  * sub-matrix of the input matrix and copies its values. (The input matrix is a
1586  * matrix used by a color-matrix filter, i.e. a 5x5 matrix.)
1587  * @param {Array.<number>} matrix
1588  * @const
1589  */
1590 createjs.WebGLRenderer.ColorMatrix.prototype.set = function(matrix) {
1591   /// <param type="Array" elementType="number" name="matrix"/>
1592   this.dirty_ = true;
1593   this.matrix_[0 * 4 + 0] = matrix[0 * 5 + 0];
1594   this.matrix_[0 * 4 + 1] = matrix[1 * 5 + 0];
1595   this.matrix_[0 * 4 + 2] = matrix[2 * 5 + 0];
1596   // this.matrix_[0 * 4 + 3] = matrix[3 * 5 + 0];
1597   this.matrix_[1 * 4 + 0] = matrix[0 * 5 + 1];
1598   this.matrix_[1 * 4 + 1] = matrix[1 * 5 + 1];
1599   this.matrix_[1 * 4 + 2] = matrix[2 * 5 + 1];
1600   // this.matrix_[1 * 4 + 3] = matrix[3 * 5 + 1];
1601   this.matrix_[2 * 4 + 0] = matrix[0 * 5 + 2];
1602   this.matrix_[2 * 4 + 1] = matrix[1 * 5 + 2];
1603   this.matrix_[2 * 4 + 2] = matrix[2 * 5 + 2];
1604   // this.matrix_[2 * 4 + 3] = matrix[3 * 5 + 2];
1605   // this.matrix_[3 * 4 + 0] = matrix[0 * 5 + 3];
1606   // this.matrix_[3 * 4 + 1] = matrix[1 * 5 + 3];
1607   // this.matrix_[3 * 4 + 2] = matrix[2 * 5 + 3];
1608   // this.matrix_[3 * 4 + 3] = matrix[3 * 5 + 3];
1609 };
1610 
1611 /**
1612  * Resets this matrix to the initial one, i.e. the identify matrix.
1613  * @const
1614  */
1615 createjs.WebGLRenderer.ColorMatrix.prototype.reset = function() {
1616   this.matrix_[0 * 4 + 0] = 1;
1617   this.matrix_[0 * 4 + 1] = 0;
1618   this.matrix_[0 * 4 + 2] = 0;
1619   // this.matrix_[0 * 4 + 3] = 0;
1620   this.matrix_[1 * 4 + 0] = 0;
1621   this.matrix_[1 * 4 + 1] = 1;
1622   this.matrix_[1 * 4 + 2] = 0;
1623   // this.matrix_[1 * 4 + 3] = 0;
1624   this.matrix_[2 * 4 + 0] = 0;
1625   this.matrix_[2 * 4 + 1] = 0;
1626   this.matrix_[2 * 4 + 2] = 1;
1627   // this.matrix_[2 * 4 + 3] = 0;
1628   // this.matrix_[3 * 4 + 0] = 0;
1629   // this.matrix_[3 * 4 + 1] = 0;
1630   // this.matrix_[3 * 4 + 2] = 0;
1631   // this.matrix_[3 * 4 + 3] = 1;
1632 };
1633 
1634 /**
1635  * Binds this transform to the specified context.
1636  * @param {createjs.WebGLRenderer.Context} context
1637  * @const
1638  */
1639 createjs.WebGLRenderer.ColorMatrix.prototype.bindContext = function(context) {
1640   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1641   if (this.dirty_) {
1642     this.dirty_ = false;
1643     context.setColorMatrix(this.transform_, this.matrix_);
1644   }
1645 };
1646 
1647 /**
1648  * An inner class that encapsulates a color offset used by a color-matrix
1649  * filter. This renderer uses a uniform vector (red, green, blue, 0) to
1650  * represent a color.
1651  * @param {createjs.WebGLRenderer.Context} context
1652  * @param {WebGLProgram} program
1653  * @param {string} key
1654  * @param {number} red
1655  * @param {number} green
1656  * @param {number} blue
1657  * @constructor
1658  */
1659 createjs.WebGLRenderer.Color =
1660     function(context, program, key, red, green, blue) {
1661   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1662   /// <param type="WebGLProgram" name="program"/>
1663   /// <param type="string" name="key"/>
1664   /// <param type="number" name="red"/>
1665   /// <param type="number" name="green"/>
1666   /// <param type="number" name="blue"/>
1667   /**
1668    * The dirty flag.
1669    * @type {boolean}
1670    * @private
1671    */
1672   this.dirty_ = true;
1673 
1674   /**
1675    * The uniform location representing this color.
1676    * @type {WebGLUniformLocation}
1677    * @private
1678    */
1679   this.color_ = context.getColor(program, key);
1680 
1681   /**
1682    * The red component.
1683    * @type {number}
1684    * @private
1685    */
1686   this.red_ = red;
1687 
1688   /**
1689    * The green component.
1690    * @type {number}
1691    * @private
1692    */
1693   this.green_ = green;
1694 
1695   /**
1696    * The blue component.
1697    * @type {number}
1698    * @private
1699    */
1700   this.blue_ = blue;
1701 };
1702 
1703 /**
1704  * Changes this color.
1705  * @param {number} red
1706  * @param {number} green
1707  * @param {number} blue
1708  * @const
1709  */
1710 createjs.WebGLRenderer.Color.prototype.set = function(red, green, blue) {
1711   /// <param type="number" name="red"/>
1712   /// <param type="number" name="green"/>
1713   /// <param type="number" name="blue"/>
1714   if (this.red_ != red || this.green_ != green || this.blue_ != blue) {
1715     this.dirty_ = true;
1716     this.red_ = red;
1717     this.green_ = green;
1718     this.blue_ = blue;
1719   }
1720 };
1721 
1722 /**
1723  * Binds this color to the specified context.
1724  * @param {createjs.WebGLRenderer.Context} context
1725  */
1726 createjs.WebGLRenderer.Color.prototype.bindContext = function(context) {
1727   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1728   if (this.dirty_) {
1729     this.dirty_ = false;
1730     context.setColor(this.color_, this.red_, this.green_, this.blue_, 0);
1731   }
1732 };
1733 
1734 /**
1735  * An inner class that blends colors used by this renderer.
1736  * @param {createjs.WebGLRenderer.Context} context
1737  * @constructor
1738  */
1739 createjs.WebGLRenderer.Blend = function(context) {
1740   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1741   /**
1742    * The dirty flag.
1743    * @type {boolean}
1744    * @private
1745    */
1746   this.dirty_ = true;
1747 
1748   /**
1749    * The composition ID.
1750    * @type {number}
1751    * @private
1752    */
1753   this.operation_ = createjs.Renderer.Composition.SOURCE_OVER;
1754 
1755   // Enable blending now to avoid enabling it every time when changing blend
1756   // functions. (This renderer always use blending with the add equation.)
1757   context.enableBlend();
1758 };
1759 
1760 /**
1761  * Sets the color-blend operation.
1762  * @param {number} operation
1763  * @const
1764  */
1765 createjs.WebGLRenderer.Blend.prototype.setComposition = function(operation) {
1766   /// <param type="number" name="operation"/>
1767   if (this.operation_ != operation) {
1768     this.dirty_ = true;
1769     this.operation_ = operation;
1770   }
1771 };
1772 
1773 /**
1774  * Binds this color-blending operation to the specified context.
1775  * @param {createjs.WebGLRenderer.Context} context
1776  * @const
1777  */
1778 createjs.WebGLRenderer.Blend.prototype.bindContext = function(context) {
1779   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1780   if (this.dirty_) {
1781     this.dirty_ = false;
1782     context.setBlend(this.operation_);
1783   }
1784 };
1785 
1786 /**
1787  * An inner class that encapsulates a frame buffer with an attached texture.
1788  * @param {createjs.WebGLRenderer.Context} context
1789  * @param {number} width
1790  * @param {number} height
1791  * @param {number} mask
1792  * @constructor
1793  */
1794 createjs.WebGLRenderer.Frame = function(context, width, height, mask) {
1795   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1796   /// <param type="number" name="width"/>
1797   /// <param type="number" name="height"/>
1798   /// <param type="number" name="mask"/>
1799   /**
1800    * The texture that stores the pixels of this framebuffer.
1801    * @type {WebGLTexture}
1802    * @private
1803    */
1804   this.texture_ = context.createFrameTexture(width, height, mask);
1805 
1806   /**
1807    * The framebuffer.
1808    * @type {WebGLFramebuffer}
1809    * @private
1810    */
1811   this.buffer_ = context.createFramebuffer(this.texture_);
1812 };
1813 
1814 /**
1815  * Returns the texture associated with this frame buffer.
1816  * @return {WebGLTexture}
1817  * @const
1818  */
1819 createjs.WebGLRenderer.Frame.prototype.getTexture = function() {
1820   /// <returns type="WebGLTexture"/>
1821   return this.texture_;
1822 };
1823 
1824 /**
1825  * Returns the frame buffer itself.
1826  * @return {WebGLFramebuffer}
1827  * @const
1828  */
1829 createjs.WebGLRenderer.Frame.prototype.getBuffer = function() {
1830   /// <returns type="WebGLFramebuffer"/>
1831   return this.buffer_;
1832 };
1833 
1834 /**
1835  * Deletes the resources owned by this frame buffer.
1836  * @param {createjs.WebGLRenderer.Context} context
1837  * @const
1838  */
1839 createjs.WebGLRenderer.Frame.prototype.destroy = function(context) {
1840   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1841   context.deleteFramebuffer(this.buffer_);
1842   context.deleteTexture(this.texture_);
1843   if (createjs.DEBUG) {
1844     this.buffer_ = null;
1845     this.texture_ = null;
1846   }
1847 };
1848 
1849 /**
1850  * An inner class that encapsulates a vertex shader and a fragment shader used
1851  * by this renderer.
1852  * @param {createjs.WebGLRenderer.Context} context
1853  * @param {string} vertex
1854  * @param {string} fragment
1855  * @constructor
1856  */
1857 createjs.WebGLRenderer.Shaders = function(context, vertex, fragment) {
1858   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1859   /// <param type="string" name="vertex"/>
1860   /// <param type="string" name="fragment"/>
1861   /**
1862    * @const {WebGLShader}
1863    * @private
1864    */
1865   this.vertex_ = context.createVertexShader(vertex);
1866 
1867   /**
1868    * @const {WebGLShader}
1869    * @private
1870    */
1871   this.fragment_ = context.createFragmentShader(fragment);
1872 };
1873 
1874 /**
1875  * Deletes the vertex shader and the fragment shader owned by this object.
1876  * @param {createjs.WebGLRenderer.Context} context
1877  * @const
1878  */
1879 createjs.WebGLRenderer.Shaders.prototype.destroy = function(context) {
1880   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1881   context.deleteShader(this.vertex_);
1882   context.deleteShader(this.fragment_);
1883 };
1884 
1885 /**
1886  * Returns the vertex shader owned by this object.
1887  * @return {WebGLShader}
1888  * @const
1889  */
1890 createjs.WebGLRenderer.Shaders.prototype.getVertex = function() {
1891   /// <returns type="WebGLShader"/>
1892   return this.vertex_;
1893 };
1894 
1895 /**
1896  * Returns the vertex shader owned by this object.
1897  * @return {WebGLShader}
1898  * @const
1899  */
1900 createjs.WebGLRenderer.Shaders.prototype.getFragment = function() {
1901   /// <returns type="WebGLShader"/>
1902   return this.fragment_;
1903 };
1904 
1905 /**
1906  * An inner class that encapsulates the shader program and its parameters used
1907  * by this renderer.
1908  * @param {createjs.WebGLRenderer.Context} context
1909  * @param {number} scaleX
1910  * @param {number} scaleY
1911  * @constructor
1912  */
1913 createjs.WebGLRenderer.Program = function(context, scaleX, scaleY) {
1914   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
1915   /// <param type="number" name="scaleX"/>
1916   /// <param type="number" name="scaleY"/>
1917   var POSITION = 'p';
1918   var TEXTURE = 't';
1919   var SCREEN = 's';
1920   var TRANSFORM = 'x';
1921   var UVPOINT = 'u';
1922   var COLOR = 'c';
1923   var IMAGE = 'i';
1924   var MATRIX = 'm';
1925   var OFFSET = 'o';
1926   var PIXEL = 'v';
1927   var VERTEX =
1928     'attribute vec2 ' + POSITION + ';' +
1929     'attribute vec2 ' + TEXTURE + ';' +
1930     'uniform vec2 ' + SCREEN + ';' +
1931     'uniform mat3 ' + TRANSFORM + ';' +
1932     'varying vec2 ' + UVPOINT + ';' +
1933     'void main(){' +
1934       'vec3 v=' + TRANSFORM + '*' +
1935           'vec3(' + POSITION + '[0],' + POSITION + '[1],1);' +
1936       'gl_Position=vec4(' +
1937           'v[0]*' + SCREEN + '[0]-1.0,' +
1938           'v[1]*' + SCREEN + '[1]+1.0,' +
1939           '0,' +
1940           '1);' +
1941       UVPOINT + '=' + TEXTURE + ';' +
1942     '}';
1943   var FRAGMENT =
1944     'precision mediump float;' +
1945     'varying vec2 ' + UVPOINT + ';' +
1946     'uniform vec4 ' + COLOR + ';' +
1947     'uniform mat4 ' + MATRIX + ';' +
1948     'uniform vec4 ' + OFFSET + ';' +
1949     'uniform sampler2D ' + IMAGE + ';' +
1950     'void main(){' +
1951       'vec4 ' + PIXEL + '=texture2D(' + IMAGE + ',' + UVPOINT + ');' +
1952       'gl_FragColor=' + COLOR + '*' +
1953           '(' + MATRIX + '*' + PIXEL + '+' + OFFSET + '*' + PIXEL + '[3]);' +
1954     '}';
1955 
1956   /**
1957    * The rendering context that owns this program.
1958    * @type {createjs.WebGLRenderer.Context}
1959    * @private
1960    */
1961   this.context_ = context;
1962 
1963   /**
1964    * The vertex shader and the fragment shader. (This program uses one vertex
1965    * shader and one fragment shader.)
1966    * @type {createjs.WebGLRenderer.Shaders}
1967    * @private
1968    */
1969   this.shaders_ = new createjs.WebGLRenderer.Shaders(
1970       context, VERTEX, FRAGMENT);
1971 
1972   /**
1973    * The shader program.
1974    * @type {WebGLProgram}
1975    * @private
1976    */
1977   this.program_ = context.createProgram(this.shaders_.getVertex(),
1978                                         this.shaders_.getFragment());
1979 
1980   /**
1981    * The vector representing the output <canvas> element of this program.
1982    * @type {createjs.WebGLRenderer.Vector}
1983    * @private
1984    */
1985   this.screen_ = new createjs.WebGLRenderer.Vector(
1986       context, this.program_, SCREEN, scaleX, -scaleY);
1987 
1988   /**
1989    * The affine transform used by CreateJS.
1990    * @type {createjs.WebGLRenderer.Transform}
1991    * @private
1992    */
1993   this.transform_ = new createjs.WebGLRenderer.Transform(
1994       context, this.program_, TRANSFORM);
1995 
1996   /**
1997    * The destination rectangle.
1998    * @type {createjs.WebGLRenderer.Rectangle}
1999    * @private
2000    */
2001   this.position_ = new createjs.WebGLRenderer.Rectangle(
2002       context, this.program_, POSITION, 0, 0);
2003 
2004   /**
2005    * The source rectangle.
2006    * @type {createjs.WebGLRenderer.Rectangle}
2007    * @private
2008    */
2009   this.texture_ = new createjs.WebGLRenderer.Rectangle(
2010       context, this.program_, TEXTURE, 1, 1);
2011 
2012   /**
2013    * The alpha-composition value.
2014    * @type {createjs.WebGLRenderer.Alpha}
2015    * @private
2016    */
2017   this.alpha_ = new createjs.WebGLRenderer.Alpha(
2018       context, this.program_, COLOR, 1);
2019 
2020   /**
2021    * The color matrix.
2022    * @type {createjs.WebGLRenderer.ColorMatrix}
2023    * @private
2024    */
2025   this.matrix_ = new createjs.WebGLRenderer.ColorMatrix(
2026       context, this.program_, MATRIX);
2027 
2028   /**
2029    * The color offset.
2030    * @type {createjs.WebGLRenderer.Color}
2031    * @private
2032    */
2033   this.offset_ = new createjs.WebGLRenderer.Color(
2034       context, this.program_, OFFSET, 0, 0, 0);
2035 
2036   /**
2037    * The blending operation.
2038    * @type {createjs.WebGLRenderer.Blend}
2039    * @private
2040    */
2041   this.blend_ = new createjs.WebGLRenderer.Blend(context);
2042 
2043   if (createjs.DEBUG) {
2044     /**
2045      * The images that have their textures created by this program.
2046      * @type {Object.<string,number>}
2047      * @private
2048      */
2049     this.ids_ = {};
2050   }
2051 };
2052 
2053 /**
2054  * Returns the rendering context who owns this program.
2055  * @return {createjs.WebGLRenderer.Context}
2056  * @private
2057  */
2058 createjs.WebGLRenderer.Program.prototype.getContext_ = function() {
2059   /// <returns type="createjs.WebGLRenderer.Context"/>
2060   return this.context_;
2061 };
2062 
2063 /**
2064  * Binds the texture attached to the specified image to this context. This
2065  * method creates a new one if the specified image does not have a texture. (It
2066  * is very slow to create a texture from an image. To avoid creating textures
2067  * every time when this renderer renders the image, this method caches the
2068  * created textures and re-uses them.)
2069  * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image
2070  * @private
2071  */
2072 createjs.WebGLRenderer.Program.prototype.bindImage_ = function(image) {
2073   /// <param type="HTMLImageElement" name="image"/>
2074   // Try creating a cache for this image and return if the cache() method
2075   // actually creates one and binds it to this context.
2076   if (this.cache(image)) {
2077     return;
2078   }
2079   var context = this.getContext_();
2080   context.bindTexture(/** @type {WebGLTexture} */ (image.texture_));
2081   if (image.dirty_) {
2082     image.dirty_ = false;
2083     context.updateTexture(image);
2084   }
2085 };
2086 
2087 /**
2088  * Draws the texture bound to this program.
2089  * @private
2090  */
2091 createjs.WebGLRenderer.Program.prototype.drawTexture_ = function() {
2092   var context = this.getContext_();
2093   this.transform_.bindContext(context);
2094   this.position_.bindContext(context);
2095   this.texture_.bindContext(context);
2096   this.alpha_.bindContext(context);
2097   this.matrix_.bindContext(context);
2098   this.offset_.bindContext(context);
2099   this.blend_.bindContext(context);
2100   context.drawRectangle();
2101 };
2102 
2103 /**
2104  * Deletes the resources owned by this program.
2105  * @param {createjs.WebGLRenderer.Context} context
2106  * @const
2107  */
2108 createjs.WebGLRenderer.Program.prototype.destroy = function(context) {
2109   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
2110   this.position_.destroy(context);
2111   this.texture_.destroy(context);
2112   context.deleteProgram(this.program_);
2113   this.shaders_.destroy(context);
2114   if (createjs.DEBUG) {
2115     this.position_ = null;
2116     this.texture_ = null;
2117     this.shaders_ = null;
2118     this.program_ = null;
2119     this.context_ = null;
2120   }
2121 };
2122 
2123 /**
2124  * Sets the specified transform.
2125  * @param {number} a
2126  * @param {number} b
2127  * @param {number} c
2128  * @param {number} d
2129  * @param {number} tx
2130  * @param {number} ty
2131  * @const
2132  */
2133 createjs.WebGLRenderer.Program.prototype.setTransform =
2134     function(a, b, c, d, tx, ty) {
2135   /// <param type="number" name="a"/>
2136   /// <param type="number" name="b"/>
2137   /// <param type="number" name="c"/>
2138   /// <param type="number" name="d"/>
2139   /// <param type="number" name="tx"/>
2140   /// <param type="number" name="ty"/>
2141   this.transform_.set(a, b, c, d, tx, ty);
2142 };
2143 
2144 /**
2145  * Sets the alpha value.
2146  * @param {number} alpha
2147  * @const
2148  */
2149 createjs.WebGLRenderer.Program.prototype.setAlpha = function(alpha) {
2150   /// <param type="number" name="alpha"/>
2151   this.alpha_.setAlpha(alpha);
2152 };
2153 
2154 /**
2155  * Sets the color matrix used by the color-matrix filter.
2156  * @param {Array.<number>} matrix
2157  * @const
2158  */
2159 createjs.WebGLRenderer.Program.prototype.setColorMatrix = function(matrix) {
2160   /// <param type="Array" elementType="number" name="matrix"/>
2161   if (matrix) {
2162     var COLOR_SCALE = 1 / 255;
2163     this.matrix_.set(matrix);
2164     this.offset_.set(matrix[0 * 5 + 4] * COLOR_SCALE,
2165                      matrix[1 * 5 + 4] * COLOR_SCALE,
2166                      matrix[2 * 5 + 4] * COLOR_SCALE);
2167   } else {
2168     this.matrix_.reset();
2169     this.offset_.set(0, 0, 0);
2170   }
2171 };
2172 
2173 /**
2174  * Sets the composition value.
2175  * @param {number} operation
2176  * @const
2177  */
2178 createjs.WebGLRenderer.Program.prototype.setComposition = function(operation) {
2179   /// <param type="number" name="operation"/>
2180   this.blend_.setComposition(operation);
2181 };
2182 
2183 /**
2184  * Draws the specified image.
2185  * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image
2186  * @param {number} x
2187  * @param {number} y
2188  * @param {number} width
2189  * @param {number} height
2190  * @const
2191  */
2192 createjs.WebGLRenderer.Program.prototype.drawImage =
2193     function(image, x, y, width, height) {
2194   /// <param type="HTMLImageElement" name="image"/>
2195   /// <param type="number" name="x"/>
2196   /// <param type="number" name="y"/>
2197   /// <param type="number" name="width"/>
2198   /// <param type="number" name="height"/>
2199   this.position_.set(x, y, width, height);
2200   this.texture_.set(0, 0, 1, 1);
2201 
2202   // Bind the given image and draw it.
2203   this.bindImage_(image);
2204   this.drawTexture_();
2205 };
2206 
2207 /**
2208  * Draws the specified part of an image.
2209  * @param {HTMLImageElement|HTMLCanvasElement} image
2210  * @param {number} srcX
2211  * @param {number} srcY
2212  * @param {number} srcWidth
2213  * @param {number} srcHeight
2214  * @param {number} x
2215  * @param {number} y
2216  * @param {number} width
2217  * @param {number} height
2218  * @const
2219  */
2220 createjs.WebGLRenderer.Program.prototype.drawPartial =
2221     function(image, srcX, srcY, srcWidth, srcHeight, x, y, width, height) {
2222   /// <param type="HTMLImageElement" name="image"/>
2223   /// <param type="number" name="srcX"/>
2224   /// <param type="number" name="srcY"/>
2225   /// <param type="number" name="srcWidth"/>
2226   /// <param type="number" name="srcHeight"/>
2227   /// <param type="number" name="x"/>
2228   /// <param type="number" name="y"/>
2229   /// <param type="number" name="width"/>
2230   /// <param type="number" name="height"/>
2231   this.position_.set(x, y, width, height);
2232   var scaleX = 1 / image.width;
2233   var scaleY = 1 / image.height;
2234   this.texture_.set(
2235       srcX * scaleX, srcY * scaleY, srcWidth * scaleX, srcHeight * scaleY);
2236 
2237   // Bind the given image and draw it.
2238   this.bindImage_(image);
2239   this.drawTexture_();
2240 };
2241 
2242 /**
2243  * Creates a cache texture for the specified image and attaches it to the image.
2244  * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image
2245  * @return {boolean}
2246  * @const
2247  */
2248 createjs.WebGLRenderer.Program.prototype.cache = function(image) {
2249   /// <param type="HTMLImageElement" name="image"/>
2250   /// <returns type="boolean"/>
2251   var context = this.getContext_();
2252   var texture = /** @type {WebGLTexture} */ (image.texture_);
2253   var tid = /** @type {number} */ (image.tid_);
2254   if (texture && tid == context.getId()) {
2255     return false;
2256   }
2257   // Create a texture and attach it to the given image. Also attach an ID of the
2258   // context that creates this texture to release the texture when the context
2259   // is lost.
2260   if (createjs.DEBUG) {
2261     if (!this.ids_[image.id]) {
2262       this.ids_[image.id] = 0;
2263     }
2264     this.ids_[image.id]++;
2265   }
2266   texture = context.createTexture(image);
2267   image.texture_ = texture;
2268   image.tid_ = context.getId();
2269   return true;
2270 };
2271 
2272 /**
2273  * Deletes the cache texture attached to the specified image.
2274  * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image
2275  * @const
2276  */
2277 createjs.WebGLRenderer.Program.prototype.uncache = function(image) {
2278   /// <param type="HTMLImageElement" name="image"/>
2279   var texture = /** @type {WebGLTexture} */ (image.texture_);
2280   image.texture_ = null;
2281   var context = this.getContext_();
2282   if (texture && context) {
2283     context.deleteTexture(texture);
2284     if (createjs.DEBUG) {
2285       --this.ids_[image.id];
2286     }
2287   }
2288 };
2289 
2290 /**
2291  * Draws the specified frame buffer.
2292  * @param {createjs.WebGLRenderer.Frame} frame
2293  * @param {number} width
2294  * @param {number} height
2295  * @param {number} composition
2296  * @private
2297  * @const
2298  */
2299 createjs.WebGLRenderer.Program.prototype.drawFrame =
2300     function(frame, width, height, composition) {
2301   /// <param type="createjs.WebGLRenderer.Frame" name="frame"/>
2302   /// <param type="number" name="width"/>
2303   /// <param type="number" name="height"/>
2304   /// <param type="number" name="composition"/>
2305 
2306   // Reset all variables used by the shader program. The texture of a frame
2307   // buffer is an OpenGL texture and its origin is its bottom-left corner. On
2308   // the other hand, this program is for rendering HTML objects and assumes
2309   // their origins are their top-left corners. This code applies the following
2310   // affine transformation (a vertical flip) to absorb this coordinate
2311   // difference.
2312   //   | 1 0      0 |
2313   //   | 0 -1     0 |
2314   //   | 0 height 1 |
2315   this.position_.set(0, 0, width, height);
2316   this.texture_.set(0, 0, 1, 1);
2317   this.setTransform(1, 0, 0, -1, 0, height);
2318   this.setAlpha(1);
2319   this.setComposition(composition);
2320 
2321   // Bind the given frame buffer and draw it.
2322   this.getContext_().bindTexture(frame.getTexture());
2323   this.drawTexture_();
2324 };
2325 
2326 /**
2327  * Starts drawing to the drawing buffer with this program.
2328  * @param {number} scaleX
2329  * @param {number} scaleY
2330  * @private
2331  */
2332 createjs.WebGLRenderer.Program.prototype.beginPaint_ =
2333     function(scaleX, scaleY) {
2334   /// <param type="number" name="scaleX"/>
2335   /// <param type="number" name="scaleY"/>
2336   this.screen_.set(scaleX, -scaleY);
2337   this.screen_.bindContext(this.getContext_());
2338 };
2339 
2340 /**
2341  * Ends drawing to the drawing buffer with this program.
2342  * @private
2343  */
2344 createjs.WebGLRenderer.Program.prototype.endPaint_ = function() {
2345 };
2346 
2347 /**
2348  * Returns the rendering context attached to this renderer.
2349  * @return {createjs.WebGLRenderer.Context}
2350  * @private
2351  */
2352 createjs.WebGLRenderer.prototype.getContext_ = function() {
2353   /// <returns type="createjs.WebGLRenderer.Context"/>
2354   return this.context_;
2355 };
2356 
2357 /**
2358  * Returns the shader program used for drawing images or canvases.
2359  * @return {createjs.WebGLRenderer.Program}
2360  * @private
2361  */
2362 createjs.WebGLRenderer.prototype.getProgram_ = function() {
2363   /// <returns type="createjs.WebGLRenderer.Program"/>
2364   if (!this.program_) {
2365     this.program_ = new createjs.WebGLRenderer.Program(
2366         this.context_, this.scaleX_, this.scaleY_);
2367   }
2368   return this.program_;
2369 };
2370 
2371 /**
2372  * Returns the framebuffer used for rendering a masked object.
2373  * @param {createjs.WebGLRenderer.Context} context
2374  * @return {createjs.WebGLRenderer.Frame}
2375  * @private
2376  * @const
2377  */
2378 createjs.WebGLRenderer.prototype.getMask_ = function(context) {
2379   /// <param type="createjs.WebGLRenderer.Frame" name="context"/>
2380   /// <returns type="createjs.WebGLRenderer.Frame"/>
2381   if (!this.mask_) {
2382     this.mask_ = new createjs.WebGLRenderer.Frame(
2383         context,
2384         this.getWidth(),
2385         this.getHeight(),
2386         createjs.WebGLRenderer.gl.UNSIGNED_SHORT_4_4_4_4);
2387   } else {
2388     context.bindFramebuffer(this.mask_.getBuffer());
2389   }
2390   context.clear();
2391   return this.mask_;
2392 };
2393 
2394 /**
2395  * Draws a masked object to the drawing buffer. This method copies the pixels of
2396  * the off-screen framebuffer used for rendering masked objects to the drawing
2397  * buffer.
2398  * @param {createjs.WebGLRenderer.Frame} frame
2399  * @param {number} width
2400  * @param {number} height
2401  * @param {number} composition
2402  * @private
2403  */
2404 createjs.WebGLRenderer.prototype.drawMask_ =
2405     function(frame, width, height, composition) {
2406   /// <param type="createjs.WebGLRenderer.Frame" name="frame"/>
2407   /// <param type="number" name="width"/>
2408   /// <param type="number" name="height"/>
2409   /// <param type="number" name="composition"/>
2410   this.program_.drawFrame(
2411       frame, width, height, createjs.Renderer.Composition.SOURCE_OVER);
2412 };
2413 
2414 /**
2415  * Changes the scissor rectangle. This renderer uses two scissor rectangles:
2416  * * A viewport rectangle used by a game to render only the specified part of
2417  *   the output <canvas> element, and;
2418  * * A bounding box of a mask.
2419  * This method automatically enables the scissor test and sets the specified
2420  * rectangle. (A scissor test is not so fast on some Android 4.0 devices and
2421  * this renderer uses it only when it has to.)
2422  * @param {createjs.WebGLRenderer.Context} context
2423  * @param {createjs.BoundingBox} scissor
2424  * @param {number} height
2425  * @private
2426  */
2427 createjs.WebGLRenderer.prototype.updateScissor_ =
2428     function(context, scissor, height) {
2429   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
2430   /// <param type="createjs.BoundingBox" name="scissor"/>
2431   /// <param type="number" name="height"/>
2432   if (this.scissor_ && this.scissor_.isEqual(scissor)) {
2433     return;
2434   }
2435   // Enable the scissor test when this renderer has not enabled it, i.e. this
2436   // renderer does not have either a scissor rectangle or a clipping rectangle.
2437   if (!this.scissor_ && !this.viewport_) {
2438     context.enableClip();
2439   }
2440   this.scissor_ = scissor;
2441   context.updateClip(scissor, height);
2442 };
2443 
2444 /**
2445  * Destroys the scissor rectangle. This method also restores the scissor
2446  * rectangle to the viewport rectangle.
2447  * @param {createjs.WebGLRenderer.Context} context
2448  * @param {number} height
2449  * @private
2450  */
2451 createjs.WebGLRenderer.prototype.destroyScissor_ = function(context, height) {
2452   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
2453   /// <param type="number" name="height"/>
2454   if (this.scissor_) {
2455     if (!this.viewport_) {
2456       context.disableClip();
2457     } else {
2458       context.updateClip(this.viewport_, height);
2459     }
2460     this.scissor_ = null;
2461   }
2462 };
2463 
2464 /**
2465  * Draws a render object to the output framebuffer.
2466  * @param {createjs.WebGLRenderer.Context} context
2467  * @param {number} width
2468  * @param {number} height
2469  * @param {createjs.Renderer.RenderObject} object
2470  * @private
2471  */
2472 createjs.WebGLRenderer.prototype.drawObject_ =
2473     function(context, width, height, object) {
2474   /// <param type="createjs.WebGLRenderer.Context" name="context"/>
2475   /// <param type="number" name="width"/>
2476   /// <param type="number" name="height"/>
2477   /// <param type="createjs.Renderer.RenderObject" name="object"/>
2478   if (createjs.DEBUG) {
2479     ++createjs.Counter.paintedObjects;
2480   }
2481   var scissor = object.getClip();
2482   if (!scissor || !scissor.getMethod()) {
2483     this.destroyScissor_(context, height);
2484   } else if (!scissor.getShape()) {
2485     this.updateScissor_(context, scissor.getBox(), height);
2486   } else {
2487     // It is tricky to draw a masked object. This code draws a masked object
2488     // with the steps listed below.
2489     // 1. Get an empty frame buffer used for composing a render object with a
2490     //    mask;
2491     // 2. Enable a scissor test with the bounding box of the mask to prevent
2492     //    the render object from being rendered outside of the mask;
2493     // 3. Draw the render object with the SOURCE_OVER operation;
2494     // 4. Draw the mask bitmap (a bitmap filled in white) with the
2495     //    DESTINATION-IN operation to get the intersection between the render
2496     //    object and the mask, and;
2497     // 5. Draw the frame buffer to this frame buffer.
2498     var frame = this.getMask_(context);
2499     if (!this.scissor_) {
2500       context.enableClip();
2501     }
2502     context.updateClip(scissor.getBox(), height);
2503     object.beginPaintObject(this);
2504     object.paintObject(this);
2505     var shape = scissor.getShape();
2506     shape.beginPaintObject(this);
2507     shape.paintObject(this);
2508     if (!this.scissor_) {
2509       context.disableClip();
2510     } else {
2511       context.updateClip(this.scissor_, height);
2512     }
2513     context.bindFramebuffer(null);
2514     this.drawMask_(frame, width, height, scissor.getComposition());
2515     return;
2516   }
2517   object.beginPaintObject(this);
2518   object.paintObject(this);
2519 };
2520 
2521 /** @override */
2522 createjs.WebGLRenderer.prototype.destroy = function() {
2523   var canvas = this.getCanvas();
2524   if (canvas) {
2525     canvas.removeEventListener('webglcontextlost', this, false);
2526     canvas.removeEventListener('webglcontextrestored', this, false);
2527     if (createjs.DEBUG) {
2528       document.removeEventListener('keyup', this, false);
2529     }
2530   }
2531   var context = this.getContext_();
2532   if (context) {
2533     if (this.mask_) {
2534       this.mask_.destroy(context);
2535       this.mask_ = null;
2536     }
2537     var layer = this.layer_;
2538     if (layer) {
2539       layer.destroy(context);
2540       this.layer_ = null;
2541     }
2542     var program = this.program_;
2543     if (program) {
2544       program.destroy(context);
2545       this.program_ = null;
2546     }
2547   }
2548 };
2549 
2550 /** @override */
2551 createjs.WebGLRenderer.prototype.setTransformation =
2552     function(a, b, c, d, tx, ty) {
2553   /// <param type="number" name="a"/>
2554   /// <param type="number" name="b"/>
2555   /// <param type="number" name="c"/>
2556   /// <param type="number" name="d"/>
2557   /// <param type="number" name="tx"/>
2558   /// <param type="number" name="ty"/>
2559   this.getProgram_().setTransform(a, b, c, d, tx, ty);
2560 };
2561 
2562 /** @override */
2563 createjs.WebGLRenderer.prototype.setAlpha = function(alpha) {
2564   /// <param type="number" name="alpha"/>
2565   this.getProgram_().setAlpha(alpha);
2566 };
2567 
2568 /** @override */
2569 createjs.WebGLRenderer.prototype.setColorMatrix = function(matrix) {
2570   /// <param type="Array" elementType="number" name="matrix"/>
2571   this.getProgram_().setColorMatrix(matrix);
2572 };
2573 
2574 /** @override */
2575 createjs.WebGLRenderer.prototype.setComposition = function(operation) {
2576   /// <param type="number" name="operation"/>
2577   this.getProgram_().setComposition(operation);
2578 };
2579 
2580 /** @override */
2581 createjs.WebGLRenderer.prototype.drawCanvas =
2582     function(canvas, x, y, width, height) {
2583   /// <param type="HTMLCanvasElement" name="canvas"/>
2584   /// <param type="number" name="x"/>
2585   /// <param type="number" name="y"/>
2586   /// <param type="number" name="width"/>
2587   /// <param type="number" name="height"/>
2588   this.getProgram_().drawImage(canvas, x, y, width, height);
2589 };
2590 
2591 /** @override */
2592 createjs.WebGLRenderer.prototype.getExtensions = function() {
2593   /// <returns type="number"/>
2594   if (createjs.UserAgent.isMSIE()) {
2595     return 0;
2596   }
2597   return createjs.Renderer.Extension.VIDEO;
2598 };
2599 
2600 /** @override */
2601 createjs.WebGLRenderer.prototype.drawVideo =
2602     function (video, x, y, width, height) {
2603   /// <param type="HTMLVideoElement" name="video"/>
2604   /// <param type="number" name="x"/>
2605   /// <param type="number" name="y"/>
2606   /// <param type="number" name="width"/>
2607   /// <param type="number" name="height"/>
2608   this.getProgram_().drawImage(video, x, y, width, height);
2609 };
2610 
2611 /** @override */
2612 createjs.WebGLRenderer.prototype.drawPartial =
2613     function(image, srcX, srcY, srcWidth, srcHeight, x, y, width, height) {
2614   /// <param type="HTMLImageElement" name="image"/>
2615   /// <param type="number" name="srcX"/>
2616   /// <param type="number" name="srcY"/>
2617   /// <param type="number" name="srcWidth"/>
2618   /// <param type="number" name="srcHeight"/>
2619   /// <param type="number" name="x"/>
2620   /// <param type="number" name="y"/>
2621   /// <param type="number" name="width"/>
2622   /// <param type="number" name="height"/>
2623   this.getProgram_().drawPartial(
2624       image, srcX, srcY, srcWidth, srcHeight, x, y, width, height);
2625 };
2626 
2627 /** @override */
2628 createjs.WebGLRenderer.prototype.addObject = function(object) {
2629   /// <param type="createjs.Renderer.RenderObject" name="object"/>
2630   var context = this.getContext_();
2631   if (context.getId()) {
2632     this.drawObject_(
2633           context, this.getWidth(), this.getHeight(), object);
2634     this.dirty_ = true;
2635     if (createjs.DEBUG) {
2636       ++createjs.Counter.visibleObjects;
2637     }
2638   }
2639 };
2640 
2641 /** @override */
2642 createjs.WebGLRenderer.prototype.uncache = function(image) {
2643   /// <param type="HTMLImageElement" name="image"/>
2644   this.getProgram_().uncache(image);
2645 };
2646 
2647 /** @override */
2648 createjs.WebGLRenderer.prototype.begin = function() {
2649   // Synchronize the viewport (and a uniform vector) with the <canvas> width and
2650   // its height.
2651   var canvas = this.getCanvas();
2652   var width = canvas.width;
2653   var height = canvas.height;
2654   if (width != this.getWidth() || height != this.getHeight()) {
2655     this.setWidth(width);
2656     this.setHeight(height);
2657     this.scaleX_ = 2 / width;
2658     this.scaleY_ = 2 / height;
2659     this.getContext_().setViewport(width, height);
2660   }
2661   this.getProgram_().beginPaint_(this.scaleX_, this.scaleY_);
2662 };
2663 
2664 /** @override */
2665 createjs.WebGLRenderer.prototype.paint = function(time) {
2666   /// <param type="number" name="time"/>
2667   // Exit this renderer loses its WebGL context.
2668   if (!this.getContext_().getId()) {
2669     return;
2670   }
2671   // Clear the drawing buffer only when this renderer have to draw a blank
2672   // page. (Some Android 4.1.x browsers needs to trigger DOM reflow in clearing
2673   // the drawing buffer, i.e. it is very slow to manually clear the output
2674   // framebuffer. This renderer clears the output framebuffer only when this
2675   // renderer has to clear it to avoid DOM reflow.)
2676   var program = this.getProgram_();
2677   var context = this.getContext_();
2678   if (!this.dirty_) {
2679     context.clear();
2680     // Trigger DOM reflow on Android 4.1.x browsers that have the bug:
2681     //   <https://code.google.com/p/android/issues/detail?id=39247>.
2682     // This bug happens in clearing the drawing buffer on Android 4.1.x browsers
2683     // that implement WebGL (e.g. Softbank Mobile ARROWS A 101F, ASUS Memo Pad
2684     // ME173X).
2685     this.updateCanvas('webgl');
2686   }
2687   if (this.scissor_) {
2688     context.disableClip();
2689     this.scissor_ = null;
2690   }
2691   program.endPaint_();
2692   this.dirty_ = false;
2693 };
2694 
2695 /** @override */
2696 createjs.WebGLRenderer.prototype.handleEvent = function(event) {
2697   /// <param type="KeyboardEvent" name="event"/>
2698   if (createjs.DEBUG && event.type == 'keyup') {
2699     var keyEvent = /** @type {KeyboardEvent} */ (event);
2700     var keyCode = keyEvent.keyCode;
2701     if (keyCode == createjs.Event.KeyCodes.E) {
2702       if (!createjs.WebGLRenderer.ticker_) {
2703         createjs.WebGLRenderer.ticker_ = createjs.Ticker.getInterval();
2704         createjs.Ticker.setInterval(1000);
2705       } else {
2706         createjs.Ticker.setInterval(createjs.WebGLRenderer.ticker_);
2707         createjs.WebGLRenderer.ticker_ = 0;
2708       }
2709     }
2710     return;
2711   }
2712   createjs.assert(event.type == 'webglcontextlost' ||
2713                   event.type == 'webglcontextrestored');
2714   if (event.type == 'webglcontextlost') {
2715     // Release the shader program and the frame buffers used by this renderer.
2716     // (Textures will be released the next time when this renderer accesses
2717     // them.)
2718     this.layer_ = null;
2719     this.program_ = null;
2720     this.getContext_().setId(0);
2721 
2722     // Wait for a drawing buffer to be restored.
2723     event.preventDefault();
2724   } else {
2725     // Assign a new context ID to recreate the textures created by the released
2726     // context.
2727     this.getContext_().setId(++createjs.WebGLRenderer.id);
2728   }
2729 };
2730