diff --git a/bin/coco-update-createjs b/bin/coco-update-createjs
index 5cd3f9140..b4871f47d 100755
--- a/bin/coco-update-createjs
+++ b/bin/coco-update-createjs
@@ -56,6 +56,8 @@ grunt combine
echo moving to CoCo
cp ~/Desktop/CreateJS/EaselJS/build/output/easeljs-NEXT.combined.js ~/Desktop/coco/vendor/scripts
cp ~/Desktop/CreateJS/EaselJS/build/output/movieclip-NEXT.min.js ~/Desktop/coco/vendor/scripts
+cp ~/Desktop/CreateJS/EaselJS/src/easeljs/display/SpriteStage.js ~/Desktop/coco/vendor/scripts/
+cp ~/Desktop/CreateJS/EaselJS/src/easeljs/display/SpriteContainer.js ~/Desktop/coco/vendor/scripts/
cp ~/Desktop/CreateJS/SoundJS/build/output/soundjs-NEXT.combined.js ~/Desktop/coco/vendor/scripts
cp ~/Desktop/CreateJS/PreloadJS/build/output/preloadjs-NEXT.combined.js ~/Desktop/coco/vendor/scripts
cp ~/Desktop/CreateJS/TweenJS/build/output/tweenjs-NEXT.combined.js ~/Desktop/coco/vendor/scripts
diff --git a/vendor/scripts/SpriteContainer.js b/vendor/scripts/SpriteContainer.js
new file mode 100644
index 000000000..49f31a26f
--- /dev/null
+++ b/vendor/scripts/SpriteContainer.js
@@ -0,0 +1,188 @@
+/*
+* SpriteContainer
+* Visit http://createjs.com/ for documentation, updates and examples.
+*
+* Copyright (c) 2010 gskinner.com, inc.
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+// namespace:
+this.createjs = this.createjs||{};
+
+(function() {
+
+/**
+ * A SpriteContainer is a nestable display list that enables aggressively optimized rendering of bitmap content.
+ * In order to accomplish these optimizations, SpriteContainer enforces a few restrictions on its content.
+ *
+ * Restrictions:
+ * - only Sprite, SpriteContainer, BitmapText and DOMElement are allowed to be added as children.
+ * - a spriteSheet MUST be either be passed into the constructor or defined on the first child added.
+ * - all children (with the exception of DOMElement) MUST use the same spriteSheet.
+ *
+ *
Example
+ * var data = {
+ * images: ["sprites.jpg"],
+ * frames: {width:50, height:50},
+ * animations: {run:[0,4], jump:[5,8,"run"]}
+ * };
+ * var spriteSheet = new createjs.SpriteSheet(data);
+ * var container = new createjs.SpriteContainer(spriteSheet);
+ * container.addChild(spriteInstance, spriteInstance2);
+ * container.x = 100;
+ *
+ * Note: SpriteContainer is not included in the minified version of EaselJS.
+ *
+ * @class SpriteContainer
+ * @extends Container
+ * @constructor
+ * @param {SpriteSheet} [spriteSheet] The spriteSheet to use for this SpriteContainer and its children.
+ **/
+var SpriteContainer = function(spriteSheet) {
+ this.initialize(spriteSheet);
+};
+var p = SpriteContainer.prototype = new createjs.Container();
+
+// public properties:
+
+ /**
+ * The SpriteSheet that this container enforces use of.
+ * @property spriteSheet
+ * @type {SpriteSheet}
+ * @readonly
+ **/
+ p.spriteSheet = null;
+
+// constructor:
+
+ /**
+ * @property Container_initialize
+ * @type Function
+ * @private
+ **/
+ p.Container_initialize = p.initialize;
+
+ /**
+ * Initialization method.
+ * @method initialize
+ * @param {SpriteSheet} spriteSheet Optional. The spriteSheet to use for this SpriteContainer and its children.
+ * @protected
+ */
+ p.initialize = function(spriteSheet) {
+ this.Container_initialize();
+ this.spriteSheet = spriteSheet;
+ };
+
+// public methods:
+
+ /**
+ * Adds a child to the top of the display list.
+ * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed.
+ * The child must have the same spritesheet as this container (unless it's a DOMElement).
+ * If a spritesheet hasn't been defined, this container uses this child's spritesheet.
+ *
+ * Example
+ * container.addChild(bitmapInstance);
+ *
+ * You can also add multiple children at once:
+ *
+ * container.addChild(bitmapInstance, shapeInstance, textInstance);
+ *
+ * @method addChild
+ * @param {DisplayObject} child The display object to add.
+ * @return {DisplayObject} The child that was added, or the last child if multiple children were added.
+ **/
+ p.addChild = function(child) {
+ if (child == null) { return child; }
+ if (arguments.length > 1) {
+ return this.addChildAt.apply(this, Array.prototype.slice.call(arguments).concat([this.children.length]));
+ } else {
+ return this.addChildAt(child, this.children.length);
+ }
+ };
+
+ /**
+ * Adds a child to the display list at the specified index, bumping children at equal or greater indexes up one, and
+ * setting its parent to this Container.
+ * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed.
+ * The child must have the same spritesheet as this container (unless it's a DOMElement).
+ * If a spritesheet hasn't been defined, this container uses this child's spritesheet.
+ *
+ * Example
+ * addChildAt(child1, index);
+ *
+ * You can also add multiple children, such as:
+ *
+ * addChildAt(child1, child2, ..., index);
+ *
+ * The index must be between 0 and numChildren. For example, to add myShape under otherShape in the display list,
+ * you could use:
+ *
+ * container.addChildAt(myShape, container.getChildIndex(otherShape));
+ *
+ * This would also bump otherShape's index up by one. Fails silently if the index is out of range.
+ *
+ * @method addChildAt
+ * @param {DisplayObject} child The display object to add.
+ * @param {Number} index The index to add the child at.
+ * @return {DisplayObject} Returns the last child that was added, or the last child if multiple children were added.
+ **/
+ p.addChildAt = function(child, index) {
+ var l = arguments.length;
+ var indx = arguments[l-1]; // can't use the same name as the index param or it replaces arguments[1]
+ if (indx < 0 || indx > this.children.length) { return arguments[l-2]; }
+ if (l > 2) {
+ for (var i=0; i= 1) {
+ // The child is compatible with SpriteStage/SpriteContainer.
+ } else {
+ console && console.log("Error: You can only add children of type SpriteContainer, Sprite, BitmapText, or DOMElement [" + child.toString() + "]");
+ return child;
+ }
+ if (child._spritestage_compatibility <= 4) {
+ var spriteSheet = child.spriteSheet;
+ if ((!spriteSheet || !spriteSheet._images || spriteSheet._images.length > 1) || (this.spritesheet && spritesheet !== spritesheet)) {
+ console && console.log("Error: A child's spriteSheet must be equal to its parent spriteSheet and only use one image. [" + child.toString() + "]");
+ return child;
+ }
+ this.spriteSheet = spriteSheet;
+ }
+ if (child.parent) { child.parent.removeChild(child); }
+ child.parent = this;
+ this.children.splice(index, 0, child);
+ return child;
+ };
+
+ /**
+ * Returns a string representation of this object.
+ * @method toString
+ * @return {String} a string representation of the instance.
+ **/
+ p.toString = function() {
+ return "[SpriteContainer (name="+ this.name +")]";
+ };
+
+createjs.SpriteContainer = SpriteContainer;
+}());
\ No newline at end of file
diff --git a/vendor/scripts/SpriteStage.js b/vendor/scripts/SpriteStage.js
new file mode 100644
index 000000000..926de4a71
--- /dev/null
+++ b/vendor/scripts/SpriteStage.js
@@ -0,0 +1,1030 @@
+/*
+* SpriteStage
+* Visit http://createjs.com/ for documentation, updates and examples.
+*
+* Copyright (c) 2010 gskinner.com, inc.
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/**
+ * @module EaselJS
+ */
+
+// namespace:
+this.createjs = this.createjs||{};
+
+(function() {
+ "use strict";
+
+// Set which classes are compatible with SpriteStage.
+// The order is important!!! If it's changed/appended, make sure that any logic that
+// checks _spritestage_compatibility accounts for it!
+[createjs.SpriteContainer, createjs.Sprite, createjs.BitmapText, createjs.Bitmap, createjs.DOMElement].forEach(function(_class, index) {
+ _class.prototype._spritestage_compatibility = index + 1;
+});
+
+/**
+ * A sprite stage is the root level {{#crossLink "Container"}}{{/crossLink}} for an aggressively optimized display list. Each time its {{#crossLink "Stage/tick"}}{{/crossLink}}
+ * method is called, it will render its display list to its target canvas. WebGL content is fully compatible with the existing Context2D renderer.
+ * On devices or browsers that don't support WebGL, content will automatically be rendered via canvas 2D.
+ *
+ * Restrictions:
+ * - only Sprite, SpriteContainer, BitmapText, Bitmap and DOMElement are allowed to be added to the display list.
+ * - a child being added (with the exception of DOMElement) MUST have an image or spriteSheet defined on it.
+ * - a child's image/spriteSheet MUST never change while being on the display list.
+ *
+ * Example
+ * This example creates a sprite stage, adds a child to it, then uses {{#crossLink "Ticker"}}{{/crossLink}} to update the child
+ * and redraw the stage using {{#crossLink "SpriteStage/update"}}{{/crossLink}}.
+ *
+ * var stage = new createjs.SpriteStage("canvasElementId", false, false);
+ * stage.updateViewport(800, 600);
+ * var image = new createjs.Bitmap("imagePath.png");
+ * stage.addChild(image);
+ * createjs.Ticker.addEventListener("tick", handleTick);
+ * function handleTick(event) {
+ * image.x += 10;
+ * stage.update();
+ * }
+ *
+ * Note: SpriteStage is not included in the minified version of EaselJS.
+ *
+ * @class SpriteStage
+ * @extends Stage
+ * @constructor
+ * @param {HTMLCanvasElement | String | Object} canvas A canvas object that the SpriteStage will render to, or the string id
+ * of a canvas object in the current document.
+ * @param {Boolean} preserveDrawingBuffer If true, the canvas is NOT auto-cleared by WebGL (spec discourages true). Useful if you want to use p.autoClear = false.
+ * @param {Boolean} antialias Specifies whether or not the browser's WebGL implementation should try to perform antialiasing.
+ **/
+var SpriteStage = function(canvas, preserveDrawingBuffer, antialias) {
+ this.initialize(canvas, preserveDrawingBuffer, antialias);
+};
+var p = SpriteStage.prototype = new createjs.Stage();
+
+// static properties:
+
+ /**
+ * The number of properties defined per vertex in p._verticesBuffer.
+ * x, y, textureU, textureV, alpha
+ * @property NUM_VERTEX_PROPERTIES
+ * @static
+ * @final
+ * @type {Number}
+ * @readonly
+ **/
+ SpriteStage.NUM_VERTEX_PROPERTIES = 5;
+
+ /**
+ * The number of points in a box...obviously :)
+ * @property POINTS_PER_BOX
+ * @static
+ * @final
+ * @type {Number}
+ * @readonly
+ **/
+ SpriteStage.POINTS_PER_BOX = 4;
+
+ /**
+ * The number of vertex properties per box.
+ * @property NUM_VERTEX_PROPERTIES_PER_BOX
+ * @static
+ * @final
+ * @type {Number}
+ * @readonly
+ **/
+ SpriteStage.NUM_VERTEX_PROPERTIES_PER_BOX = SpriteStage.POINTS_PER_BOX * SpriteStage.NUM_VERTEX_PROPERTIES;
+
+ /**
+ * The number of indices needed to define a box using triangles.
+ * 6 indices = 2 triangles = 1 box
+ * @property INDICES_PER_BOX
+ * @static
+ * @final
+ * @type {Number}
+ * @readonly
+ **/
+ SpriteStage.INDICES_PER_BOX = 6;
+
+ /**
+ * The maximum size WebGL allows for element index numbers: 16 bit unsigned integer
+ * @property MAX_INDEX_SIZE
+ * @static
+ * @final
+ * @type {Number}
+ * @readonly
+ **/
+ SpriteStage.MAX_INDEX_SIZE = Math.pow(2, 16);
+
+ /**
+ * The amount used to increment p._maxBoxesPointsPerDraw when the maximum has been reached.
+ * If the maximum size of element index WebGL allows for (SpriteStage.MAX_INDEX_SIZE) was used,
+ * the array size for p._vertices would equal 1280kb and p._indices 192kb. But since mobile phones
+ * with less memory need to be accounted for, the maximum size is somewhat arbitrarily divided by 4,
+ * reducing the array sizes to 320kb and 48kb respectively.
+ * @property MAX_BOXES_POINTS_INCREMENT
+ * @static
+ * @final
+ * @type {Number}
+ * @readonly
+ **/
+ SpriteStage.MAX_BOXES_POINTS_INCREMENT = SpriteStage.MAX_INDEX_SIZE / 4;
+
+// getter / setters:
+ /**
+ * Indicates whether WebGL is being used for rendering. For example, this would be false if WebGL is not
+ * supported in the browser.
+ * @readonly
+ * @property isWebGL
+ * @type {Boolean}
+ **/
+ p._get_isWebGL = function() {
+ return !!this._webGLContext;
+ };
+
+ try {
+ Object.defineProperties(p, {
+ isWebGL: { get: p._get_isWebGL }
+ });
+ } catch (e) {} // TODO: use Log
+
+// private properties:
+
+ /**
+ * Specifies whether or not the canvas is auto-cleared by WebGL. Spec discourages true.
+ * If true, the canvas is NOT auto-cleared by WebGL. Value is ignored if p._alphaEnabled is false.
+ * Useful if you want to use p.autoClear = false.
+ * @property _preserveDrawingBuffer
+ * @protected
+ * @type {Boolean}
+ * @default false
+ **/
+ p._preserveDrawingBuffer = false;
+
+ /**
+ * Specifies whether or not the browser's WebGL implementation should try to perform antialiasing.
+ * @property _antialias
+ * @protected
+ * @type {Boolean}
+ * @default false
+ **/
+ p._antialias = false;
+
+ /**
+ * The width of the canvas element.
+ * @property _viewportWidth
+ * @protected
+ * @type {Number}
+ * @default 0
+ **/
+ p._viewportWidth = 0;
+
+ /**
+ * The height of the canvas element.
+ * @property _viewportHeight
+ * @protected
+ * @type {Number}
+ * @default 0
+ **/
+ p._viewportHeight = 0;
+
+ /**
+ * A 2D projection matrix used to convert WebGL's clipspace into normal pixels.
+ * @property _projectionMatrix
+ * @protected
+ * @type {Float32Array}
+ * @default null
+ **/
+ p._projectionMatrix = null;
+
+ /**
+ * The current WebGL canvas context.
+ * @property _webGLContext
+ * @protected
+ * @type {WebGLRenderingContext}
+ * @default null
+ **/
+ p._webGLContext = null;
+
+ /**
+ * Indicates whether or not an error has been detected when dealing with WebGL.
+ * If the is true, the behavior should be to use Canvas 2D rendering instead.
+ * @property _webGLErrorDetected
+ * @protected
+ * @type {Boolean}
+ * @default false
+ **/
+ p._webGLErrorDetected = false;
+
+ /**
+ * The color to use when the WebGL canvas has been cleared.
+ * @property _clearColor
+ * @protected
+ * @type {Object}
+ * @default null
+ **/
+ p._clearColor = null;
+
+ /**
+ * The maximum number of textures WebGL can work with per draw call.
+ * @property _maxTexturesPerDraw
+ * @protected
+ * @type {Number}
+ * @default 1
+ **/
+ p._maxTexturesPerDraw = 1;
+
+ /**
+ * The maximum total number of boxes points that can be defined per draw call.
+ * @property _maxBoxesPointsPerDraw
+ * @protected
+ * @type {Number}
+ * @default null
+ **/
+ p._maxBoxesPointsPerDraw = null;
+
+ /**
+ * The maximum number of boxes (sprites) that can be drawn in one draw call.
+ * @property _maxBoxesPerDraw
+ * @protected
+ * @type {Number}
+ * @default null
+ **/
+ p._maxBoxesPerDraw = null;
+
+ /**
+ * The maximum number of indices that can be drawn in one draw call.
+ * @property _maxIndicesPerDraw
+ * @protected
+ * @type {Number}
+ * @default null
+ **/
+ p._maxIndicesPerDraw = null;
+
+ /**
+ * The shader program used to draw everything.
+ * @property _shaderProgram
+ * @protected
+ * @type {WebGLProgram}
+ * @default null
+ **/
+ p._shaderProgram = null;
+
+ /**
+ * The vertices data for the current draw call.
+ * @property _vertices
+ * @protected
+ * @type {Float32Array}
+ * @default null
+ **/
+ p._vertices = null;
+
+ /**
+ * The buffer that contains all the vertices data.
+ * @property _verticesBuffer
+ * @protected
+ * @type {WebGLBuffer}
+ * @default null
+ **/
+ p._verticesBuffer = null;
+
+ /**
+ * The indices to the vertices defined in p._vertices.
+ * @property _indices
+ * @protected
+ * @type {Uint16Array}
+ * @default null
+ **/
+ p._indices = null;
+
+ /**
+ * The buffer that contains all the indices data.
+ * @property _indicesBuffer
+ * @protected
+ * @type {WebGLBuffer}
+ * @default null
+ **/
+ p._indicesBuffer = null;
+
+ /**
+ * The current box index being defined for drawing.
+ * @property _currentBoxIndex
+ * @protected
+ * @type {Number}
+ * @default -1
+ **/
+ p._currentBoxIndex = -1;
+
+ /**
+ * The current texture that will be used to draw into the GPU.
+ * @property _drawTexture
+ * @protected
+ * @type {WebGLTexture}
+ * @default null
+ **/
+ p._drawTexture = null;
+
+// constructor:
+
+ /**
+ * @property Stage_initialize
+ * @type Function
+ * @private
+ **/
+ p.Stage_initialize = p.initialize;
+
+ /**
+ * Initialization method.
+ * @method initialize
+ * @param {HTMLCanvasElement | String | Object} canvas A canvas object, or the string id of a canvas object in the current document.
+ * @param {Boolean} preserveDrawingBuffer If true, the canvas is NOT auto-cleared by WebGL (spec discourages true). Useful if you want to use p.autoClear = false.
+ * @param {Boolean} antialias Specifies whether or not the browser's WebGL implementation should try to perform antialiasing.
+ * @protected
+ **/
+ p.initialize = function(canvas, preserveDrawingBuffer, antialias) {
+ this._preserveDrawingBuffer = preserveDrawingBuffer !== undefined ? preserveDrawingBuffer : this._preserveDrawingBuffer;
+ this._antialias = antialias !== undefined ? antialias : this._antialias;
+
+ this.Stage_initialize(canvas);
+ this._initializeWebGL();
+ };
+
+// public methods:
+
+ /**
+ * Adds a child to the top of the display list.
+ * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed.
+ * Children also MUST have either an image or spriteSheet defined on them (unless it's a DOMElement).
+ *
+ * Example
+ * container.addChild(bitmapInstance);
+ *
+ * You can also add multiple children at once:
+ *
+ * container.addChild(bitmapInstance, shapeInstance, textInstance);
+ *
+ * @method addChild
+ * @param {DisplayObject} child The display object to add.
+ * @return {DisplayObject} The child that was added, or the last child if multiple children were added.
+ **/
+ p.addChild = function(child) {
+ if (child == null) { return child; }
+ if (arguments.length > 1) {
+ return this.addChildAt.apply(this, Array.prototype.slice.call(arguments).concat([this.children.length]));
+ } else {
+ return this.addChildAt(child, this.children.length);
+ }
+ };
+
+ /**
+ * Adds a child to the display list at the specified index, bumping children at equal or greater indexes up one, and
+ * setting its parent to this Container.
+ * Only children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement are allowed.
+ * Children also MUST have either an image or spriteSheet defined on them (unless it's a DOMElement).
+ *
+ * Example
+ * addChildAt(child1, index);
+ *
+ * You can also add multiple children, such as:
+ *
+ * addChildAt(child1, child2, ..., index);
+ *
+ * The index must be between 0 and numChildren. For example, to add myShape under otherShape in the display list,
+ * you could use:
+ *
+ * container.addChildAt(myShape, container.getChildIndex(otherShape));
+ *
+ * This would also bump otherShape's index up by one. Fails silently if the index is out of range.
+ *
+ * @method addChildAt
+ * @param {DisplayObject} child The display object to add.
+ * @param {Number} index The index to add the child at.
+ * @return {DisplayObject} Returns the last child that was added, or the last child if multiple children were added.
+ **/
+ p.addChildAt = function(child, index) {
+ var l = arguments.length;
+ var indx = arguments[l-1]; // can't use the same name as the index param or it replaces arguments[1]
+ if (indx < 0 || indx > this.children.length) { return arguments[l-2]; }
+ if (l > 2) {
+ for (var i=0; i= 1) {
+ // The child is compatible with SpriteStage.
+ } else {
+ console && console.log("Error: You can only add children of type SpriteContainer, Sprite, Bitmap, BitmapText, or DOMElement. [" + child.toString() + "]");
+ return child;
+ }
+ if (!child.image && !child.spriteSheet && child._spritestage_compatibility <= 4) {
+ console && console.log("Error: You can only add children that have an image or spriteSheet defined on them. [" + child.toString() + "]");
+ return child;
+ }
+ if (child.parent) { child.parent.removeChild(child); }
+ child.parent = this;
+ this.children.splice(index, 0, child);
+ this._setUpKidTexture(this._webGLContext, child);
+ return child;
+ };
+
+ /**
+ * Each time the update method is called, the stage will tick all descendants (see: {{#crossLink "DisplayObject/tick"}}{{/crossLink}})
+ * and then render the display list to the canvas using WebGL. If WebGL is not supported in the browser, it will default to a 2D context.
+ *
+ * Any parameters passed to `update()` will be passed on to any
+ * {{#crossLink "DisplayObject/tick:event"}}{{/crossLink}} event handlers.
+ *
+ * Some time-based features in EaselJS (for example {{#crossLink "Sprite/framerate"}}{{/crossLink}} require that
+ * a tick event object (or equivalent) be passed as the first parameter to update(). For example:
+ *
+ * Ticker.addEventListener("tick", handleTick);
+ * function handleTick(evtObj) {
+ * // do some work here, then update the stage, passing through the event object:
+ * myStage.update(evtObj);
+ * }
+ *
+ * @method update
+ * @param {*} [params]* Params to include when ticking descendants. The first param should usually be a tick event.
+ **/
+ p.update = function(params) {
+ if (!this.canvas) { return; }
+ if (this.tickOnUpdate) {
+ this.dispatchEvent("tickstart"); // TODO: make cancellable?
+ this._tick((arguments.length ? arguments : null));
+ this.dispatchEvent("tickend");
+ }
+ this.dispatchEvent("drawstart"); // TODO: make cancellable?
+ if (this.autoClear) { this.clear(); }
+ var ctx = this._setWebGLContext();
+ if (ctx) {
+ // Use WebGL.
+ this.draw(ctx, false);
+ } else {
+ // Use 2D.
+ ctx = this.canvas.getContext("2d");
+ ctx.save();
+ this.updateContext(ctx);
+ this.draw(ctx, false);
+ ctx.restore();
+ }
+ this.dispatchEvent("drawend");
+ };
+
+ /**
+ * Clears the target canvas. Useful if {{#crossLink "Stage/autoClear:property"}}{{/crossLink}} is set to `false`.
+ * @method clear
+ **/
+ p.clear = function() {
+ if (!this.canvas) { return; }
+ var ctx = this._setWebGLContext();
+ if (ctx) {
+ // Use WebGL.
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ } else {
+ // Use 2D.
+ ctx = this.canvas.getContext("2d");
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.clearRect(0, 0, this.canvas.width + 1, this.canvas.height + 1);
+ }
+ };
+
+ /**
+ * @property Stage_draw
+ * @type {Function}
+ * @private
+ **/
+ p.Stage_draw = p.draw;
+
+ /**
+ * Draws the stage into the specified context (using WebGL) ignoring its visible, alpha, shadow, and transform.
+ * If WebGL is not supported in the browser, it will default to a 2D context.
+ * Returns true if the draw was handled (useful for overriding functionality).
+ *
+ * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
+ * @method draw
+ * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
+ * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache.
+ * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
+ * into itself).
+ **/
+ p.draw = function(ctx, ignoreCache) {
+ if (ctx === this._webGLContext || ctx instanceof WebGLRenderingContext) {
+ this._drawWebGLKids(this.children, ctx);
+
+ // If there is a remaining texture, draw it:
+ if (this._drawTexture) {
+ this._drawToGPU(ctx);
+ }
+
+ return true;
+ } else {
+ return this.Stage_draw(ctx, ignoreCache);
+ }
+ };
+
+ /**
+ * Update the WebGL viewport. Note that this does NOT update the canvas element's width/height.
+ * @method updateViewport
+ * @param {Number} width
+ * @param {Number} height
+ **/
+ p.updateViewport = function (width, height) {
+ this._viewportWidth = width;
+ this._viewportHeight = height;
+
+ if (this._webGLContext) {
+ this._webGLContext.viewport(0, 0, this._viewportWidth, this._viewportHeight);
+
+ if (!this._projectionMatrix) {
+ this._projectionMatrix = new Float32Array([0, 0, 0, 0, 0, 1, -1, 1, 1]);
+ }
+ this._projectionMatrix[0] = 2 / width;
+ this._projectionMatrix[4] = -2 / height;
+ }
+ };
+
+ /**
+ * Clears an image's texture to free it up for garbage collection.
+ * @method clearImageTexture
+ * @param {Image} image
+ **/
+ p.clearImageTexture = function(image) {
+ image.__easeljs_texture = null;
+ };
+
+ /**
+ * Returns a string representation of this object.
+ * @method toString
+ * @return {String} a string representation of the instance.
+ **/
+ p.toString = function() {
+ return "[SpriteStage (name="+ this.name +")]";
+ };
+
+ // private methods:
+
+ /**
+ * Initializes rendering with WebGL using the current canvas element.
+ * @method _initializeWebGL
+ * @protected
+ **/
+ p._initializeWebGL = function() {
+ this._clearColor = { r: 0.0, g: 0.0, b: 0.0, a: 0.0 };
+
+ this._setWebGLContext();
+ };
+
+ /**
+ * Sets the WebGL context to use for future draws.
+ * @method _setWebGLContext
+ * @return {WebGLRenderingContext} The newly created context.
+ * @protected
+ **/
+ p._setWebGLContext = function() {
+ if (this.canvas) {
+ if (!this._webGLContext || this._webGLContext.canvas !== this.canvas) {
+ // A context hasn't been defined yet,
+ // OR the defined context belongs to a different canvas, so reinitialize.
+ this._initializeWebGLContext();
+ }
+ } else {
+ this._webGLContext = null;
+ }
+ return this._webGLContext;
+ };
+
+ /**
+ * Sets up the WebGL context for rendering.
+ * @method _initializeWebGLContext
+ * @protected
+ **/
+ p._initializeWebGLContext = function() {
+ var options = {
+ depth: false, // Disable the depth buffer as it isn't used.
+ alpha: true, // Make the canvas background transparent.
+ preserveDrawingBuffer: this._preserveDrawingBuffer,
+ antialias: this._antialias,
+ premultipliedAlpha: true // Assume the drawing buffer contains colors with premultiplied alpha.
+ };
+ var ctx = this._webGLContext = this.canvas.getContext("webgl", options) || this.canvas.getContext("experimental-webgl", options);
+
+ if (!ctx) {
+ // WebGL is not supported in this browser.
+ return;
+ }
+
+ // Enforcing 1 texture per draw for now until an optimized implementation for multiple textures is made:
+ this._maxTexturesPerDraw = 1; // ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS);
+
+ // Set the default color the canvas should render when clearing:
+ this._setClearColor(this._clearColor.r, this._clearColor.g, this._clearColor.b, this._clearColor.a);
+
+ // Enable blending and set the blending functions that work with the premultiplied alpha settings:
+ ctx.enable(ctx.BLEND);
+ ctx.blendFuncSeparate(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA, ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA);
+
+ // Do not premultiply textures' alpha channels when loading them in:
+ ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+
+ // Create the shader program that will be used for drawing:
+ this._createShaderProgram(ctx);
+
+ if (this._webGLErrorDetected) {
+ // Error detected during this._createShaderProgram().
+ this._webGLContext = null;
+ return;
+ }
+
+ // Create the vertices and indices buffers.
+ this._createBuffers(ctx);
+
+ // Update the viewport with the initial canvas dimensions:
+ this.updateViewport(this._viewportWidth || this.canvas.width || 0, this._viewportHeight || this.canvas.height || 0);
+ };
+
+ /**
+ * Sets the color to use when the WebGL canvas has been cleared.
+ * @method _setClearColor
+ * @param {Number} r A number between 0 and 1.
+ * @param {Number} g A number between 0 and 1.
+ * @param {Number} b A number between 0 and 1.
+ * @param {Number} a A number between 0 and 1.
+ * @protected
+ **/
+ p._setClearColor = function (r, g, b, a) {
+ this._clearColor.r = r;
+ this._clearColor.g = g;
+ this._clearColor.b = b;
+ this._clearColor.a = a;
+
+ if (this._webGLContext) {
+ this._webGLContext.clearColor(r, g, b, a);
+ }
+ };
+
+ /**
+ * Creates the shader program that's going to be used to draw everything.
+ * @method _createShaderProgram
+ * @param {WebGLRenderingContext} ctx
+ * @protected
+ **/
+ p._createShaderProgram = function(ctx) {
+
+
+ var fragmentShader = this._createShader(ctx, ctx.FRAGMENT_SHADER,
+ "precision mediump float;" +
+
+ "uniform sampler2D uSampler0;" +
+
+ "varying vec3 vTextureCoord;" +
+
+ "void main(void) {" +
+ "vec4 color = texture2D(uSampler0, vTextureCoord.st);" +
+ "gl_FragColor = vec4(color.rgb, color.a * vTextureCoord.z);" +
+ "}"
+ );
+
+ var vertexShader = this._createShader(ctx, ctx.VERTEX_SHADER,
+ "attribute vec2 aVertexPosition;" +
+ "attribute vec3 aTextureCoord;" +
+
+ "uniform mat3 uPMatrix;" +
+
+ "varying vec3 vTextureCoord;" +
+
+ "void main(void) {" +
+ "vTextureCoord = aTextureCoord;" +
+
+ "gl_Position = vec4((uPMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);" +
+ "}"
+ );
+
+ if (this._webGLErrorDetected || !fragmentShader || !vertexShader) { return; }
+
+ var program = ctx.createProgram();
+ ctx.attachShader(program, fragmentShader);
+ ctx.attachShader(program, vertexShader);
+ ctx.linkProgram(program);
+
+ if(!ctx.getProgramParameter(program, ctx.LINK_STATUS)) {
+ // alert("Could not link program. " + ctx.getProgramInfoLog(program));
+ this._webGLErrorDetected = true;
+ return;
+ }
+
+ program.vertexPositionAttribute = ctx.getAttribLocation(program, "aVertexPosition");
+ program.textureCoordAttribute = ctx.getAttribLocation(program, "aTextureCoord");
+
+ program.sampler0uniform = ctx.getUniformLocation(program, "uSampler0");
+
+ ctx.enableVertexAttribArray(program.vertexPositionAttribute);
+ ctx.enableVertexAttribArray(program.textureCoordAttribute);
+
+ program.pMatrixUniform = ctx.getUniformLocation(program, "uPMatrix");
+
+ ctx.useProgram(program);
+
+ this._shaderProgram = program;
+ };
+
+ /**
+ * Creates a shader from the specified string.
+ * @method _createShader
+ * @param {WebGLRenderingContext} ctx
+ * @param {Number} type The type of shader to create.
+ * @param {String} str The definition for the shader.
+ * @return {WebGLShader}
+ * @protected
+ **/
+ p._createShader = function(ctx, type, str) {
+ var shader = ctx.createShader(type);
+ ctx.shaderSource(shader, str);
+ ctx.compileShader(shader);
+
+ if (!ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)) {
+ // alert("Could not compile shader. " + ctx.getShaderInfoLog(shader));
+ this._webGLErrorDetected = true;
+ return null;
+ }
+
+ return shader;
+ };
+
+ /**
+ * Sets up the necessary vertices and indices buffers.
+ * @method _createBuffers
+ * @param {WebGLRenderingContext} ctx
+ * @protected
+ **/
+ p._createBuffers = function(ctx) {
+ this._verticesBuffer = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, this._verticesBuffer);
+
+ var byteCount = SpriteStage.NUM_VERTEX_PROPERTIES * 4; // ctx.FLOAT = 4 bytes
+ ctx.vertexAttribPointer(this._shaderProgram.vertexPositionAttribute, 2, ctx.FLOAT, ctx.FALSE, byteCount, 0);
+ ctx.vertexAttribPointer(this._shaderProgram.textureCoordAttribute, 3, ctx.FLOAT, ctx.FALSE, byteCount, 2 * 4);
+
+ this._indicesBuffer = ctx.createBuffer();
+
+ this._setMaxBoxesPoints(ctx, SpriteStage.MAX_BOXES_POINTS_INCREMENT);
+ };
+
+ /**
+ * Updates the maximum total number of boxes points that can be defined per draw call,
+ * and updates the buffers with the new array length sizes.
+ * @method _setMaxBoxesPoints
+ * @param {WebGLRenderingContext} ctx
+ * @param {Number} value The new this._maxBoxesPointsPerDraw value.
+ * @protected
+ **/
+ p._setMaxBoxesPoints = function (ctx, value) {
+ this._maxBoxesPointsPerDraw = value;
+ this._maxBoxesPerDraw = (this._maxBoxesPointsPerDraw / SpriteStage.POINTS_PER_BOX) | 0;
+ this._maxIndicesPerDraw = this._maxBoxesPerDraw * SpriteStage.INDICES_PER_BOX;
+
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, this._verticesBuffer);
+ this._vertices = new Float32Array(this._maxBoxesPerDraw * SpriteStage.NUM_VERTEX_PROPERTIES_PER_BOX);
+ ctx.bufferData(ctx.ARRAY_BUFFER, this._vertices, ctx.DYNAMIC_DRAW);
+
+ // Set up indices for multiple boxes:
+ this._indices = new Uint16Array(this._maxIndicesPerDraw); // Indices are set once and reused.
+ for (var i = 0, l = this._indices.length; i < l; i += SpriteStage.INDICES_PER_BOX) {
+ var j = i * SpriteStage.POINTS_PER_BOX / SpriteStage.INDICES_PER_BOX;
+
+ // Indices for the 2 triangles that make the box:
+ this._indices[i] = j;
+ this._indices[i + 1] = j + 1;
+ this._indices[i + 2] = j + 2;
+ this._indices[i + 3] = j;
+ this._indices[i + 4] = j + 2;
+ this._indices[i + 5] = j + 3;
+ }
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
+ ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, this._indices, ctx.STATIC_DRAW);
+ };
+
+ /**
+ * Sets up a kid's WebGL texture.
+ * @method _setUpKidTexture
+ * @param {WebGLRenderingContext} ctx The canvas WebGL context object to draw into.
+ * @param {Object} kid The list of kids to draw.
+ * @return {WebGLTexture}
+ * @protected
+ **/
+ p._setUpKidTexture = function (ctx, kid) {
+ if (!ctx) { return null; }
+
+ var image,
+ texture = null;
+
+ if (kid._spritestage_compatibility === 4) {
+ image = kid.image;
+ } else if (kid._spritestage_compatibility <= 3 && kid.spriteSheet && kid.spriteSheet._images) {
+ image = kid.spriteSheet._images[0];
+ }
+
+ if (image) {
+ // Create and use a new texture for this image if it doesn't already have one:
+ texture = image.__easeljs_texture;
+ if (!texture) {
+ texture = image.__easeljs_texture = ctx.createTexture();
+ ctx.bindTexture(ctx.TEXTURE_2D, texture);
+ ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
+ }
+ }
+
+ return texture;
+ };
+
+ /**
+ * Draw all the kids into the WebGL context.
+ * @method _drawWebGLKids
+ * @param {Array} kids The list of kids to draw.
+ * @param {WebGLRenderingContext} ctx The canvas WebGL context object to draw into.
+ * @param {Matrix2D} parentMVMatrix The parent's global transformation matrix.
+ * @protected
+ **/
+ p._drawWebGLKids = function(kids, ctx, parentMVMatrix) {
+ var kid, mtx,
+ snapToPixelEnabled = this.snapToPixelEnabled,
+ image = null,
+ leftSide = 0, topSide = 0, rightSide = 0, bottomSide = 0,
+ vertices = this._vertices,
+ numVertexPropertiesPerBox = SpriteStage.NUM_VERTEX_PROPERTIES_PER_BOX,
+ maxIndexSize = SpriteStage.MAX_INDEX_SIZE,
+ maxBoxIndex = this._maxBoxesPerDraw - 1;
+
+ for (var i = 0, l = kids.length; i < l; i++) {
+ kid = kids[i];
+ if (!kid.isVisible()) { continue; }
+ mtx = kid._matrix;
+
+ // Get the kid's global matrix (relative to the stage):
+ mtx = (parentMVMatrix ? mtx.copy(parentMVMatrix) : mtx.identity())
+ .appendTransform(kid.x, kid.y, kid.scaleX, kid.scaleY, kid.rotation, kid.skewX, kid.skewY, kid.regX, kid.regY);
+
+ // Set default texture coordinates:
+ var uStart = 0, uEnd = 1,
+ vStart = 0, vEnd = 1;
+
+ // Define the untransformed bounding box sides and get the kid's image to use for textures:
+ if (kid._spritestage_compatibility === 4) {
+ image = kid.image;
+
+ leftSide = 0;
+ topSide = 0;
+ rightSide = image.width;
+ bottomSide = image.height;
+ } else if (kid._spritestage_compatibility === 2) {
+ var frame = kid.spriteSheet.getFrame(kid.currentFrame),
+ rect = frame.rect;
+
+ image = frame.image;
+
+ leftSide = -frame.regX;
+ topSide = -frame.regY;
+ rightSide = leftSide + rect.width;
+ bottomSide = topSide + rect.height;
+
+ uStart = rect.x / image.width;
+ vStart = rect.y / image.height;
+ uEnd = uStart + (rect.width / image.width);
+ vEnd = vStart + (rect.height / image.height);
+ } else {
+ image = null;
+
+ // Update BitmapText instances:
+ if (kid._spritestage_compatibility === 3) {
+ // TODO: this might change in the future to use a more general approach.
+ kid._updateText();
+ }
+ }
+
+ // Detect if this kid is a new display branch:
+ if (!parentMVMatrix && kid._spritestage_compatibility <= 4) {
+ // Get the texture for this display branch:
+ var texture = (image || kid.spriteSheet._images[0]).__easeljs_texture;
+
+ // Only use a new texture in the current draw call:
+ if (texture !== this._drawTexture) {
+
+ // Draw to the GPU if a texture is already in use:
+ if (this._drawTexture) {
+ this._drawToGPU(ctx);
+ }
+
+ this._drawTexture = texture;
+
+ ctx.activeTexture(ctx.TEXTURE0);
+ ctx.bindTexture(ctx.TEXTURE_2D, texture);
+ ctx.uniform1i(this._shaderProgram.sampler0uniform, 0);
+ }
+ }
+
+ if (image !== null) {
+ // Set vertices' data:
+
+ var offset = ++this._currentBoxIndex * numVertexPropertiesPerBox,
+ a = mtx.a,
+ b = mtx.b,
+ c = mtx.c,
+ d = mtx.d,
+ tx = mtx.tx,
+ ty = mtx.ty;
+
+ if (snapToPixelEnabled && kid.snapToPixel) {
+ tx = tx + (tx < 0 ? -0.5 : 0.5) | 0;
+ ty = ty + (ty < 0 ? -0.5 : 0.5) | 0;
+ }
+
+ // Positions (calculations taken from Matrix2D.transformPoint):
+ vertices[offset] = leftSide * a + topSide * c + tx;
+ vertices[offset + 1] = leftSide * b + topSide * d + ty;
+ vertices[offset + 5] = leftSide * a + bottomSide * c + tx;
+ vertices[offset + 6] = leftSide * b + bottomSide * d + ty;
+ vertices[offset + 10] = rightSide * a + bottomSide * c + tx;
+ vertices[offset + 11] = rightSide * b + bottomSide * d + ty;
+ vertices[offset + 15] = rightSide * a + topSide * c + tx;
+ vertices[offset + 16] = rightSide * b + topSide * d + ty;
+
+ // Texture coordinates:
+ vertices[offset + 2] = vertices[offset + 7] = uStart;
+ vertices[offset + 12] = vertices[offset + 17] = uEnd;
+ vertices[offset + 3] = vertices[offset + 18] = vStart;
+ vertices[offset + 8] = vertices[offset + 13] = vEnd;
+
+ // Alphas:
+ vertices[offset + 4] = vertices[offset + 9] = vertices[offset + 14] = vertices[offset + 19] = kid.alpha;
+
+ // Draw to the GPU if the maximum number of boxes per a draw has been reached:
+ if (this._currentBoxIndex === maxBoxIndex) {
+ this._drawToGPU(ctx);
+
+ // Set the draw texture again:
+ this._drawTexture = image.__easeljs_texture;
+ ctx.activeTexture(ctx.TEXTURE0);
+ ctx.bindTexture(ctx.TEXTURE_2D, this._drawTexture);
+ ctx.uniform1i(this._shaderProgram.sampler0uniform, 0);
+
+ // If possible, increase the amount of boxes that can be used per draw call:
+ if (this._maxBoxesPointsPerDraw < maxIndexSize) {
+ this._setMaxBoxesPoints(ctx, this._maxBoxesPointsPerDraw + SpriteStage.MAX_BOXES_POINTS_INCREMENT);
+ maxBoxIndex = this._maxBoxesPerDraw - 1;
+ }
+ }
+ }
+
+ // Draw children:
+ if (kid.children) {
+ this._drawWebGLKids(kid.children, ctx, mtx);
+ maxBoxIndex = this._maxBoxesPerDraw - 1;
+ }
+ }
+ };
+
+ /**
+ * Draws all the currently defined boxes to the GPU.
+ * @method _drawToGPU
+ * @param {WebGLRenderingContext} ctx The canvas WebGL context object to draw into.
+ * @protected
+ **/
+ p._drawToGPU = function(ctx) {
+ var numBoxes = this._currentBoxIndex + 1;
+
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, this._verticesBuffer);
+
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
+ ctx.uniformMatrix3fv(this._shaderProgram.pMatrixUniform, false, this._projectionMatrix);
+ ctx.bufferSubData(ctx.ARRAY_BUFFER, 0, this._vertices);
+ ctx.drawElements(ctx.TRIANGLES, numBoxes * SpriteStage.INDICES_PER_BOX, ctx.UNSIGNED_SHORT, 0);
+
+ // Reset draw vars:
+ this._currentBoxIndex = -1;
+ this._drawTexture = null;
+ };
+
+createjs.SpriteStage = SpriteStage;
+}());