diff --git a/Gruntfile.js b/Gruntfile.js index b083b49..5511724 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,6 +22,8 @@ module.exports = function(grunt) { '<%= dirs.src %>/display/Sprite.js', '<%= dirs.src %>/display/MovieClip.js', '<%= dirs.src %>/filters/FilterBlock.js', + '<%= dirs.src %>/filters/ColorMatrixFilter.js', + '<%= dirs.src %>/filters/GreyFilter.js', '<%= dirs.src %>/text/Text.js', '<%= dirs.src %>/text/BitmapText.js', '<%= dirs.src %>/InteractionManager.js', @@ -31,6 +33,7 @@ module.exports = function(grunt) { '<%= dirs.src %>/utils/Detector.js', '<%= dirs.src %>/utils/Polyk.js', '<%= dirs.src %>/renderers/webgl/WebGLShaders.js', + '<%= dirs.src %>/renderers/webgl/PixiShader.js', '<%= dirs.src %>/renderers/webgl/WebGLGraphics.js', '<%= dirs.src %>/renderers/webgl/WebGLRenderer.js', '<%= dirs.src %>/renderers/webgl/WebGLBatch.js', @@ -124,7 +127,8 @@ module.exports = function(grunt) { 'examples/example 11 - RenderTexture', 'examples/example 12 - Spine', 'examples/example 13 - Graphics', - 'examples/example 14 - Masking' + 'examples/example 14 - Masking', + 'examples/example 15 - Filters' ] }, connect: { diff --git a/bin/pixi.dev.js b/bin/pixi.dev.js index a6e7055..6d567a2 100644 --- a/bin/pixi.dev.js +++ b/bin/pixi.dev.js @@ -4,7 +4,7 @@ * Copyright (c) 2012, Mat Groves * http://goodboydigital.com/ * - * Compiled: 2013-07-24 + * Compiled: 2013-09-30 * * Pixi.JS is licensed under the MIT License. * http://www.opensource.org/licenses/mit-license.php @@ -34,19 +34,19 @@ var PIXI = PIXI || {}; * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. * * @class Point - * @constructor + * @constructor * @param x {Number} position of the point * @param y {Number} position of the point */ PIXI.Point = function(x, y) { /** - * @property x + * @property x * @type Number * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -78,10 +78,10 @@ PIXI.Point.prototype.constructor = PIXI.Point; * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. * * @class Rectangle - * @constructor + * @constructor * @param x {Number} The X coord of the upper-left corner of the rectangle * @param y {Number} The Y coord of the upper-left corner of the rectangle - * @param width {Number} The overall wisth of this rectangle + * @param width {Number} The overall width of this rectangle * @param height {Number} The overall height of this rectangle */ PIXI.Rectangle = function(x, y, width, height) @@ -92,21 +92,21 @@ PIXI.Rectangle = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -140,11 +140,11 @@ PIXI.Rectangle.prototype.contains = function(x, y) return false; var x1 = this.x; - if(x > x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y>16)/255,(255&t>>8)/255,(255&t)/255]}function e(t){return[(255&t>>16)/255,(255&t>>8)/255,(255&t)/255]}var i=this,n=n||{};n.Point=function(t,e){this.x=t||0,this.y=e||0},n.Point.prototype.clone=function(){return new n.Point(this.x,this.y)},n.Point.prototype.constructor=n.Point,n.Rectangle=function(t,e,i,r){this.x=t||0,this.y=e||0,this.width=i||0,this.height=r||0},n.Rectangle.prototype.clone=function(){return new n.Rectangle(this.x,this.y,this.width,this.height)},n.Rectangle.prototype.contains=function(t,e){if(0>=this.width||0>=this.height)return!1;var i=this.x;if(t>i&&i+this.width>t){var r=this.y;if(e>r&&r+this.height>e)return!0}return!1},n.Rectangle.prototype.constructor=n.Rectangle,n.Polygon=function(t){if(t instanceof Array||(t=Array.prototype.slice.call(arguments)),"number"==typeof t[0]){for(var e=[],i=0,r=t.length;r>i;i+=2)e.push(new n.Point(t[i],t[i+1]));t=e}this.points=t},n.Polygon.prototype.clone=function(){for(var t=[],e=0;this.points.length>e;e++)t.push(this.points[e].clone());return new n.Polygon(t)},n.Polygon.prototype.contains=function(t,e){for(var i=!1,r=0,n=this.points.length-1;this.points.length>r;n=r++){var s=this.points[r].x,o=this.points[r].y,a=this.points[n].x,h=this.points[n].y,l=o>e!=h>e&&(a-s)*(e-o)/(h-o)+s>t;l&&(i=!i)}return i},n.Polygon.prototype.constructor=n.Polygon,n.Circle=function(t,e,i){this.x=t||0,this.y=e||0,this.radius=i||0},n.Circle.prototype.clone=function(){return new n.Circle(this.x,this.y,this.radius)},n.Circle.prototype.contains=function(t,e){if(0>=this.radius)return!1;var i=this.x-t,r=this.y-e,n=this.radius*this.radius;return i*=i,r*=r,n>=i+r},n.Circle.prototype.constructor=n.Circle,n.Ellipse=function(t,e,i,r){this.x=t||0,this.y=e||0,this.width=i||0,this.height=r||0},n.Ellipse.prototype.clone=function(){return new n.Ellipse(this.x,this.y,this.width,this.height)},n.Ellipse.prototype.contains=function(t,e){if(0>=this.width||0>=this.height)return!1;var i=(t-this.x)/this.width-.5,r=(e-this.y)/this.height-.5;return i*=i,r*=r,.25>i+r},n.Ellipse.getBounds=function(){return new n.Rectangle(this.x,this.y,this.width,this.height)},n.Ellipse.prototype.constructor=n.Ellipse,t(),n.mat3={},n.mat3.create=function(){var t=new n.Matrix(9);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},n.mat3.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},n.mat4={},n.mat4.create=function(){var t=new n.Matrix(16);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},n.mat3.multiply=function(t,e,i){i||(i=t);var r=t[0],n=t[1],s=t[2],o=t[3],a=t[4],h=t[5],l=t[6],u=t[7],c=t[8],p=e[0],d=e[1],f=e[2],v=e[3],m=e[4],g=e[5],x=e[6],b=e[7],y=e[8];return i[0]=p*r+d*o+f*l,i[1]=p*n+d*a+f*u,i[2]=p*s+d*h+f*c,i[3]=v*r+m*o+g*l,i[4]=v*n+m*a+g*u,i[5]=v*s+m*h+g*c,i[6]=x*r+b*o+y*l,i[7]=x*n+b*a+y*u,i[8]=x*s+b*h+y*c,i},n.mat3.clone=function(t){var e=new n.Matrix(9);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e},n.mat3.transpose=function(t,e){if(!e||t===e){var i=t[1],r=t[2],n=t[5];return t[1]=t[3],t[2]=t[6],t[3]=i,t[5]=t[7],t[6]=r,t[7]=n,t}return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],e},n.mat3.toMat4=function(t,e){return e||(e=n.mat4.create()),e[15]=1,e[14]=0,e[13]=0,e[12]=0,e[11]=0,e[10]=t[8],e[9]=t[7],e[8]=t[6],e[7]=0,e[6]=t[5],e[5]=t[4],e[4]=t[3],e[3]=0,e[2]=t[2],e[1]=t[1],e[0]=t[0],e},n.mat4.create=function(){var t=new n.Matrix(16);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},n.mat4.transpose=function(t,e){if(!e||t===e){var i=t[1],r=t[2],n=t[3],s=t[6],o=t[7],a=t[11];return t[1]=t[4],t[2]=t[8],t[3]=t[12],t[4]=i,t[6]=t[9],t[7]=t[13],t[8]=r,t[9]=s,t[11]=t[14],t[12]=n,t[13]=o,t[14]=a,t}return e[0]=t[0],e[1]=t[4],e[2]=t[8],e[3]=t[12],e[4]=t[1],e[5]=t[5],e[6]=t[9],e[7]=t[13],e[8]=t[2],e[9]=t[6],e[10]=t[10],e[11]=t[14],e[12]=t[3],e[13]=t[7],e[14]=t[11],e[15]=t[15],e},n.mat4.multiply=function(t,e,i){i||(i=t);var r=t[0],n=t[1],s=t[2],o=t[3],a=t[4],h=t[5],l=t[6],u=t[7],c=t[8],p=t[9],d=t[10],f=t[11],v=t[12],m=t[13],g=t[14],x=t[15],b=e[0],y=e[1],T=e[2],_=e[3];return i[0]=b*r+y*a+T*c+_*v,i[1]=b*n+y*h+T*p+_*m,i[2]=b*s+y*l+T*d+_*g,i[3]=b*o+y*u+T*f+_*x,b=e[4],y=e[5],T=e[6],_=e[7],i[4]=b*r+y*a+T*c+_*v,i[5]=b*n+y*h+T*p+_*m,i[6]=b*s+y*l+T*d+_*g,i[7]=b*o+y*u+T*f+_*x,b=e[8],y=e[9],T=e[10],_=e[11],i[8]=b*r+y*a+T*c+_*v,i[9]=b*n+y*h+T*p+_*m,i[10]=b*s+y*l+T*d+_*g,i[11]=b*o+y*u+T*f+_*x,b=e[12],y=e[13],T=e[14],_=e[15],i[12]=b*r+y*a+T*c+_*v,i[13]=b*n+y*h+T*p+_*m,i[14]=b*s+y*l+T*d+_*g,i[15]=b*o+y*u+T*f+_*x,i},n.DisplayObject=function(){this.last=this,this.first=this,this.position=new n.Point,this.scale=new n.Point(1,1),this.pivot=new n.Point(0,0),this.rotation=0,this.alpha=1,this.visible=!0,this.hitArea=null,this.buttonMode=!1,this.renderable=!1,this.worldVisible=!1,this.parent=null,this.stage=null,this.childIndex=0,this.worldAlpha=1,this._interactive=!1,this.worldTransform=n.mat3.create(),this.localTransform=n.mat3.create(),this.color=[],this.dynamic=!0,this._sr=0,this._cr=1},n.DisplayObject.prototype.constructor=n.DisplayObject,n.DisplayObject.prototype.setInteractive=function(t){this.interactive=t},Object.defineProperty(n.DisplayObject.prototype,"interactive",{get:function(){return this._interactive},set:function(t){this._interactive=t,this.stage&&(this.stage.dirty=!0)}}),Object.defineProperty(n.DisplayObject.prototype,"mask",{get:function(){return this._mask},set:function(t){this._mask=t,t?this.addFilter(t):this.removeFilter()}}),n.DisplayObject.prototype.addFilter=function(t){if(!this.filter){this.filter=!0;var e=new n.FilterBlock,i=new n.FilterBlock;e.mask=t,i.mask=t,e.first=e.last=this,i.first=i.last=this,e.open=!0;var r,s,o=e,a=e;s=this.first._iPrev,s?(r=s._iNext,o._iPrev=s,s._iNext=o):r=this,r&&(r._iPrev=a,a._iNext=r);var o=i,a=i,r=null,s=null;s=this.last,r=s._iNext,r&&(r._iPrev=a,a._iNext=r),o._iPrev=s,s._iNext=o;for(var h=this,l=this.last;h;)h.last==l&&(h.last=i),h=h.parent;this.first=e,this.__renderGroup&&this.__renderGroup.addFilterBlocks(e,i),t.renderable=!1}},n.DisplayObject.prototype.removeFilter=function(){if(this.filter){this.filter=!1;var t=this.first,e=t._iNext,i=t._iPrev;e&&(e._iPrev=i),i&&(i._iNext=e),this.first=t._iNext;var r=this.last,e=r._iNext,i=r._iPrev;e&&(e._iPrev=i),i._iNext=e;for(var n=r._iPrev,s=this;s.last==r&&(s.last=n,s=s.parent););var o=t.mask;o.renderable=!0,this.__renderGroup&&this.__renderGroup.removeFilterBlocks(t,r)}},n.DisplayObject.prototype.updateTransform=function(){this.rotation!=this.rotationCache&&(this.rotationCache=this.rotation,this._sr=Math.sin(this.rotation),this._cr=Math.cos(this.rotation));var t=this.localTransform,e=this.parent.worldTransform,i=this.worldTransform;t[0]=this._cr*this.scale.x,t[1]=-this._sr*this.scale.y,t[3]=this._sr*this.scale.x,t[4]=this._cr*this.scale.y;var r=this.pivot.x,n=this.pivot.y,s=t[0],o=t[1],a=this.position.x-t[0]*r-n*t[1],h=t[3],l=t[4],u=this.position.y-t[4]*n-r*t[3],c=e[0],p=e[1],d=e[2],f=e[3],v=e[4],m=e[5];t[2]=a,t[5]=u,i[0]=c*s+p*h,i[1]=c*o+p*l,i[2]=c*a+p*u+d,i[3]=f*s+v*h,i[4]=f*o+v*l,i[5]=f*a+v*u+m,this.worldAlpha=this.alpha*this.parent.worldAlpha},n.DisplayObjectContainer=function(){n.DisplayObject.call(this),this.children=[]},n.DisplayObjectContainer.prototype=Object.create(n.DisplayObject.prototype),n.DisplayObjectContainer.prototype.constructor=n.DisplayObjectContainer,n.DisplayObjectContainer.prototype.addChild=function(t){if(void 0!=t.parent&&t.parent.removeChild(t),t.parent=this,t.childIndex=this.children.length,this.children.push(t),this.stage){var e=t;do e.interactive&&(this.stage.dirty=!0),e.stage=this.stage,e=e._iNext;while(e)}var i,r,n=t.first,s=t.last;r=this.filter?this.last._iPrev:this.last,i=r._iNext;for(var o=this,a=r;o;)o.last==a&&(o.last=t.last),o=o.parent;i&&(i._iPrev=s,s._iNext=i),n._iPrev=r,r._iNext=n,this.__renderGroup&&(t.__renderGroup&&t.__renderGroup.removeDisplayObjectAndChildren(t),this.__renderGroup.addDisplayObjectAndChildren(t))},n.DisplayObjectContainer.prototype.addChildAt=function(t,e){if(!(e>=0&&this.children.length>=e))throw Error(t+" The index "+e+" supplied is out of bounds "+this.children.length);if(void 0!=t.parent&&t.parent.removeChild(t),t.parent=this,this.stage){var i=t;do i.interactive&&(this.stage.dirty=!0),i.stage=this.stage,i=i._iNext;while(i)}var r,n,s=t.first,o=t.last;if(e==this.children.length){n=this.last;for(var a=this,h=this.last;a;)a.last==h&&(a.last=t.last),a=a.parent}else n=0==e?this:this.children[e-1].last;r=n._iNext,r&&(r._iPrev=o,o._iNext=r),s._iPrev=n,n._iNext=s,this.children.splice(e,0,t),this.__renderGroup&&(t.__renderGroup&&t.__renderGroup.removeDisplayObjectAndChildren(t),this.__renderGroup.addDisplayObjectAndChildren(t))},n.DisplayObjectContainer.prototype.swapChildren=function(){},n.DisplayObjectContainer.prototype.getChildAt=function(t){if(t>=0&&this.children.length>t)return this.children[t];throw Error(child+" Both the supplied DisplayObjects must be a child of the caller "+this)},n.DisplayObjectContainer.prototype.removeChild=function(t){var e=this.children.indexOf(t);if(-1===e)throw Error(t+" The supplied DisplayObject must be a child of the caller "+this);var i=t.first,r=t.last,n=r._iNext,s=i._iPrev;if(n&&(n._iPrev=s),s._iNext=n,this.last==r)for(var o=i._iPrev,a=this;a.last==r.last&&(a.last=o,a=a.parent););if(r._iNext=null,i._iPrev=null,this.stage){var h=t;do h.interactive&&(this.stage.dirty=!0),h.stage=null,h=h._iNext;while(h)}t.__renderGroup&&t.__renderGroup.removeDisplayObjectAndChildren(t),t.parent=void 0,this.children.splice(e,1)},n.DisplayObjectContainer.prototype.updateTransform=function(){if(this.visible){n.DisplayObject.prototype.updateTransform.call(this);for(var t=0,e=this.children.length;e>t;t++)this.children[t].updateTransform()}},n.blendModes={},n.blendModes.NORMAL=0,n.blendModes.SCREEN=1,n.Sprite=function(t){n.DisplayObjectContainer.call(this),this.anchor=new n.Point,this.texture=t,this.blendMode=n.blendModes.NORMAL,this._width=0,this._height=0,t.baseTexture.hasLoaded?this.updateFrame=!0:(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},n.Sprite.prototype=Object.create(n.DisplayObjectContainer.prototype),n.Sprite.prototype.constructor=n.Sprite,Object.defineProperty(n.Sprite.prototype,"width",{get:function(){return this.scale.x*this.texture.frame.width},set:function(t){this.scale.x=t/this.texture.frame.width,this._width=t}}),Object.defineProperty(n.Sprite.prototype,"height",{get:function(){return this.scale.y*this.texture.frame.height},set:function(t){this.scale.y=t/this.texture.frame.height,this._height=t}}),n.Sprite.prototype.setTexture=function(t){this.texture.baseTexture!=t.baseTexture&&(this.textureChange=!0),this.texture=t,this.updateFrame=!0},n.Sprite.prototype.onTextureUpdate=function(){this._width&&(this.scale.x=this._width/this.texture.frame.width),this._height&&(this.scale.y=this._height/this.texture.frame.height),this.updateFrame=!0},n.Sprite.fromFrame=function(t){var e=n.TextureCache[t];if(!e)throw Error("The frameId '"+t+"' does not exist in the texture cache"+this);return new n.Sprite(e)},n.Sprite.fromImage=function(t){var e=n.Texture.fromImage(t);return new n.Sprite(e)},n.MovieClip=function(t){n.Sprite.call(this,t[0]),this.textures=t,this.animationSpeed=1,this.loop=!0,this.onComplete=null,this.currentFrame=0,this.playing=!1},n.MovieClip.prototype=Object.create(n.Sprite.prototype),n.MovieClip.prototype.constructor=n.MovieClip,n.MovieClip.prototype.stop=function(){this.playing=!1},n.MovieClip.prototype.play=function(){this.playing=!0},n.MovieClip.prototype.gotoAndStop=function(t){this.playing=!1,this.currentFrame=t;var e=0|this.currentFrame+.5;this.setTexture(this.textures[e%this.textures.length])},n.MovieClip.prototype.gotoAndPlay=function(t){this.currentFrame=t,this.playing=!0},n.MovieClip.prototype.updateTransform=function(){if(n.Sprite.prototype.updateTransform.call(this),this.playing){this.currentFrame+=this.animationSpeed;var t=0|this.currentFrame+.5;this.loop||this.textures.length>t?this.setTexture(this.textures[t%this.textures.length]):t>=this.textures.length&&(this.gotoAndStop(this.textures.length-1),this.onComplete&&this.onComplete())}},n.FilterBlock=function(t){this.graphics=t,this.visible=!0,this.renderable=!0},n.Text=function(t,e){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),n.Sprite.call(this,n.Texture.fromCanvas(this.canvas)),this.setText(t),this.setStyle(e),this.updateText(),this.dirty=!1},n.Text.prototype=Object.create(n.Sprite.prototype),n.Text.prototype.constructor=n.Text,n.Text.prototype.setStyle=function(t){t=t||{},t.font=t.font||"bold 20pt Arial",t.fill=t.fill||"black",t.align=t.align||"left",t.stroke=t.stroke||"black",t.strokeThickness=t.strokeThickness||0,t.wordWrap=t.wordWrap||!1,t.wordWrapWidth=t.wordWrapWidth||100,this.style=t,this.dirty=!0},n.Sprite.prototype.setText=function(t){this.text=""+t||" ",this.dirty=!0},n.Text.prototype.updateText=function(){this.context.font=this.style.font;var t=this.text;this.style.wordWrap&&(t=this.wordWrap(this.text));for(var e=t.split(/(?:\r\n|\r|\n)/),i=[],r=0,s=0;e.length>s;s++){var o=this.context.measureText(e[s]).width;i[s]=o,r=Math.max(r,o)}this.canvas.width=r+this.style.strokeThickness;var a=this.determineFontHeight("font: "+this.style.font+";")+this.style.strokeThickness;for(this.canvas.height=a*e.length,this.context.fillStyle=this.style.fill,this.context.font=this.style.font,this.context.strokeStyle=this.style.stroke,this.context.lineWidth=this.style.strokeThickness,this.context.textBaseline="top",s=0;e.length>s;s++){var h=new n.Point(this.style.strokeThickness/2,this.style.strokeThickness/2+s*a);"right"==this.style.align?h.x+=r-i[s]:"center"==this.style.align&&(h.x+=(r-i[s])/2),this.style.stroke&&this.style.strokeThickness&&this.context.strokeText(e[s],h.x,h.y),this.style.fill&&this.context.fillText(e[s],h.x,h.y)}this.updateTexture()},n.Text.prototype.updateTexture=function(){this.texture.baseTexture.width=this.canvas.width,this.texture.baseTexture.height=this.canvas.height,this.texture.frame.width=this.canvas.width,this.texture.frame.height=this.canvas.height,this._width=this.canvas.width,this._height=this.canvas.height,n.texturesToUpdate.push(this.texture.baseTexture)},n.Text.prototype.updateTransform=function(){this.dirty&&(this.updateText(),this.dirty=!1),n.Sprite.prototype.updateTransform.call(this)},n.Text.prototype.determineFontHeight=function(t){var e=n.Text.heightCache[t];if(!e){var i=document.getElementsByTagName("body")[0],r=document.createElement("div"),s=document.createTextNode("M");r.appendChild(s),r.setAttribute("style",t+";position:absolute;top:0;left:0"),i.appendChild(r),e=r.offsetHeight,n.Text.heightCache[t]=e,i.removeChild(r)}return e},n.Text.prototype.wordWrap=function(t){for(var e=function(t,e,i,r,n){var s=Math.floor((r-i)/2)+i;return s==i?1:n>=t.measureText(e.substring(0,s)).width?t.measureText(e.substring(0,s+1)).width>n?s:arguments.callee(t,e,s,r,n):arguments.callee(t,e,i,s,n)},i=function(t,i,r){if(r>=t.measureText(i).width||1>i.length)return i;var n=e(t,i,0,i.length,r);return i.substring(0,n)+"\n"+arguments.callee(t,i.substring(n),r)},r="",n=t.split("\n"),s=0;n.length>s;s++)r+=i(this.context,n[s],this.style.wordWrapWidth)+"\n";return r},n.Text.prototype.destroy=function(t){t&&this.texture.destroy()},n.Text.heightCache={},n.BitmapText=function(t,e){n.DisplayObjectContainer.call(this),this.setText(t),this.setStyle(e),this.updateText(),this.dirty=!1},n.BitmapText.prototype=Object.create(n.DisplayObjectContainer.prototype),n.BitmapText.prototype.constructor=n.BitmapText,n.BitmapText.prototype.setText=function(t){this.text=t||" ",this.dirty=!0},n.BitmapText.prototype.setStyle=function(t){t=t||{},t.align=t.align||"left",this.style=t;var e=t.font.split(" ");this.fontName=e[e.length-1],this.fontSize=e.length>=2?parseInt(e[e.length-2],10):n.BitmapText.fonts[this.fontName].size,this.dirty=!0},n.BitmapText.prototype.updateText=function(){for(var t=n.BitmapText.fonts[this.fontName],e=new n.Point,i=null,r=[],s=0,o=[],a=0,h=this.fontSize/t.size,l=0;this.text.length>l;l++){var u=this.text.charCodeAt(l);if(/(?:\r\n|\r|\n)/.test(this.text.charAt(l)))o.push(e.x),s=Math.max(s,e.x),a++,e.x=0,e.y+=t.lineHeight,i=null;else{var c=t.chars[u];c&&(i&&c[i]&&(e.x+=c.kerning[i]),r.push({texture:c.texture,line:a,charCode:u,position:new n.Point(e.x+c.xOffset,e.y+c.yOffset)}),e.x+=c.xAdvance,i=u)}}o.push(e.x),s=Math.max(s,e.x);var p=[];for(l=0;a>=l;l++){var d=0;"right"==this.style.align?d=s-o[l]:"center"==this.style.align&&(d=(s-o[l])/2),p.push(d)}for(l=0;r.length>l;l++){var f=new n.Sprite(r[l].texture);f.position.x=(r[l].position.x+p[r[l].line])*h,f.position.y=r[l].position.y*h,f.scale.x=f.scale.y=h,this.addChild(f)}this.width=e.x*h,this.height=(e.y+t.lineHeight)*h},n.BitmapText.prototype.updateTransform=function(){if(this.dirty){for(;this.children.length>0;)this.removeChild(this.getChildAt(0));this.updateText(),this.dirty=!1}n.DisplayObjectContainer.prototype.updateTransform.call(this)},n.BitmapText.fonts={},n.InteractionManager=function(t){this.stage=t,this.mouse=new n.InteractionData,this.touchs={},this.tempPoint=new n.Point,this.mouseoverEnabled=!0,this.pool=[],this.interactiveItems=[],this.last=0},n.InteractionManager.prototype.constructor=n.InteractionManager,n.InteractionManager.prototype.collectInteractiveSprite=function(t,e){for(var i=t.children,r=i.length,n=r-1;n>=0;n--){var s=i[n];s.visible&&(s.interactive?(e.interactiveChildren=!0,this.interactiveItems.push(s),s.children.length>0&&this.collectInteractiveSprite(s,s)):(s.__iParent=null,s.children.length>0&&this.collectInteractiveSprite(s,e)))}},n.InteractionManager.prototype.setTarget=function(t){window.navigator.msPointerEnabled&&(t.view.style["-ms-content-zooming"]="none",t.view.style["-ms-touch-action"]="none"),this.target=t,t.view.addEventListener("mousemove",this.onMouseMove.bind(this),!0),t.view.addEventListener("mousedown",this.onMouseDown.bind(this),!0),document.body.addEventListener("mouseup",this.onMouseUp.bind(this),!0),t.view.addEventListener("mouseout",this.onMouseUp.bind(this),!0),t.view.addEventListener("touchstart",this.onTouchStart.bind(this),!0),t.view.addEventListener("touchend",this.onTouchEnd.bind(this),!0),t.view.addEventListener("touchmove",this.onTouchMove.bind(this),!0)},n.InteractionManager.prototype.update=function(){if(this.target){var t=Date.now(),e=t-this.last;if(e=30*e/1e3,!(1>e)){if(this.last=t,this.dirty){this.dirty=!1;for(var i=this.interactiveItems.length,r=0;i>r;r++)this.interactiveItems[r].interactiveChildren=!1;this.interactiveItems=[],this.stage.interactive&&this.interactiveItems.push(this.stage),this.collectInteractiveSprite(this.stage,this.stage)}var n=this.interactiveItems.length;this.target.view.style.cursor="default";for(var r=0;n>r;r++){var s=this.interactiveItems[r];s.visible&&(s.mouseover||s.mouseout||s.buttonMode)&&(s.__hit=this.hitTest(s,this.mouse),this.mouse.target=s,s.__hit?(s.buttonMode&&(this.target.view.style.cursor="pointer"),s.__isOver||(s.mouseover&&s.mouseover(this.mouse),s.__isOver=!0)):s.__isOver&&(s.mouseout&&s.mouseout(this.mouse),s.__isOver=!1))}}}},n.InteractionManager.prototype.onMouseMove=function(t){this.mouse.originalEvent=t||window.event;var e=this.target.view.getBoundingClientRect();this.mouse.global.x=(t.clientX-e.left)*(this.target.width/e.width),this.mouse.global.y=(t.clientY-e.top)*(this.target.height/e.height);var i=this.interactiveItems.length;this.mouse.global;for(var r=0;i>r;r++){var n=this.interactiveItems[r];n.mousemove&&n.mousemove(this.mouse)}},n.InteractionManager.prototype.onMouseDown=function(t){t.preventDefault(),this.mouse.originalEvent=t||window.event;var e=this.interactiveItems.length;this.mouse.global,this.stage;for(var i=0;e>i;i++){var r=this.interactiveItems[i];if((r.mousedown||r.click)&&(r.__mouseIsDown=!0,r.__hit=this.hitTest(r,this.mouse),r.__hit&&(r.mousedown&&r.mousedown(this.mouse),r.__isDown=!0,!r.interactiveChildren)))break}},n.InteractionManager.prototype.onMouseUp=function(t){this.mouse.originalEvent=t||window.event,this.mouse.global;for(var e=this.interactiveItems.length,i=!1,r=0;e>r;r++){var n=this.interactiveItems[r];(n.mouseup||n.mouseupoutside||n.click)&&(n.__hit=this.hitTest(n,this.mouse),n.__hit&&!i?(n.mouseup&&n.mouseup(this.mouse),n.__isDown&&n.click&&n.click(this.mouse),n.interactiveChildren||(i=!0)):n.__isDown&&n.mouseupoutside&&n.mouseupoutside(this.mouse),n.__isDown=!1)}},n.InteractionManager.prototype.hitTest=function(t,e){var i=e.global;if(!t.visible)return!1;var r=t instanceof n.Sprite,s=t.worldTransform,o=s[0],a=s[1],h=s[2],l=s[3],u=s[4],c=s[5],p=1/(o*u+a*-l),d=u*p*i.x+-a*p*i.y+(c*a-h*u)*p,f=o*p*i.y+-l*p*i.x+(-c*o+h*l)*p;if(e.target=t,t.hitArea&&t.hitArea.contains)return t.hitArea.contains(d,f)?(e.target=t,!0):!1;if(r){var v,m=t.texture.frame.width,g=t.texture.frame.height,x=-m*t.anchor.x;if(d>x&&x+m>d&&(v=-g*t.anchor.y,f>v&&v+g>f))return e.target=t,!0}for(var b=t.children.length,y=0;b>y;y++){var T=t.children[y],_=this.hitTest(T,e);if(_)return e.target=t,!0}return!1},n.InteractionManager.prototype.onTouchMove=function(t){this.mouse.originalEvent=t||window.event;for(var e=this.target.view.getBoundingClientRect(),i=t.changedTouches,r=0;i.length>r;r++){var n=i[r],s=this.touchs[n.identifier];s.global.x=(n.clientX-e.left)*(this.target.width/e.width),s.global.y=(n.clientY-e.top)*(this.target.height/e.height)}for(var o=this.interactiveItems.length,r=0;o>r;r++){var a=this.interactiveItems[r];a.touchmove&&a.touchmove(s)}},n.InteractionManager.prototype.onTouchStart=function(t){t.preventDefault(),this.mouse.originalEvent=t||window.event;for(var e=this.target.view.getBoundingClientRect(),i=t.changedTouches,r=0;i.length>r;r++){var s=i[r],o=this.pool.pop();o||(o=new n.InteractionData),this.touchs[s.identifier]=o,o.global.x=(s.clientX-e.left)*(this.target.width/e.width),o.global.y=(s.clientY-e.top)*(this.target.height/e.height);for(var a=this.interactiveItems.length,h=0;a>h;h++){var l=this.interactiveItems[h];if((l.touchstart||l.tap)&&(l.__hit=this.hitTest(l,o),l.__hit&&(l.touchstart&&l.touchstart(o),l.__isDown=!0,l.__touchData=o,!l.interactiveChildren)))break}}},n.InteractionManager.prototype.onTouchEnd=function(t){this.mouse.originalEvent=t||window.event;for(var e=this.target.view.getBoundingClientRect(),i=t.changedTouches,r=0;i.length>r;r++){var n=i[r],s=this.touchs[n.identifier],o=!1;s.global.x=(n.clientX-e.left)*(this.target.width/e.width),s.global.y=(n.clientY-e.top)*(this.target.height/e.height);for(var a=this.interactiveItems.length,h=0;a>h;h++){var l=this.interactiveItems[h],u=l.__touchData;l.__hit=this.hitTest(l,s),u==s&&((l.touchend||l.tap)&&(l.__hit&&!o?(l.touchend&&l.touchend(s),l.__isDown&&l.tap&&l.tap(s),l.interactiveChildren||(o=!0)):l.__isDown&&l.touchendoutside&&l.touchendoutside(s),l.__isDown=!1),l.__touchData=null)}this.pool.push(s),this.touchs[n.identifier]=null}},n.InteractionData=function(){this.global=new n.Point,this.local=new n.Point,this.target,this.originalEvent},n.InteractionData.prototype.getLocalPosition=function(t){var e=t.worldTransform,i=this.global,r=e[0],s=e[1],o=e[2],a=e[3],h=e[4],l=e[5],u=1/(r*h+s*-a);return new n.Point(h*u*i.x+-s*u*i.y+(l*s-o*h)*u,r*u*i.y+-a*u*i.x+(-l*r+o*a)*u)},n.InteractionData.prototype.constructor=n.InteractionData,n.Stage=function(t,e){n.DisplayObjectContainer.call(this),this.worldTransform=n.mat3.create(),this.interactive=e,this.interactionManager=new n.InteractionManager(this),this.dirty=!0,this.__childrenAdded=[],this.__childrenRemoved=[],this.stage=this,this.stage.hitArea=new n.Rectangle(0,0,1e5,1e5),this.setBackgroundColor(t),this.worldVisible=!0},n.Stage.prototype=Object.create(n.DisplayObjectContainer.prototype),n.Stage.prototype.constructor=n.Stage,n.Stage.prototype.updateTransform=function(){this.worldAlpha=1;for(var t=0,e=this.children.length;e>t;t++)this.children[t].updateTransform();this.dirty&&(this.dirty=!1,this.interactionManager.dirty=!0),this.interactive&&this.interactionManager.update()},n.Stage.prototype.setBackgroundColor=function(t){this.backgroundColor=t||0,this.backgroundColorSplit=e(this.backgroundColor);var i=this.backgroundColor.toString(16);i="000000".substr(0,6-i.length)+i,this.backgroundColorString="#"+i},n.Stage.prototype.getMousePosition=function(){return this.interactionManager.mouse.global};for(var s=0,o=["ms","moz","webkit","o"],h=0;o.length>h&&!window.requestAnimationFrame;++h)window.requestAnimationFrame=window[o[h]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[o[h]+"CancelAnimationFrame"]||window[o[h]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(t){var e=(new Date).getTime(),i=Math.max(0,16-(e-s)),r=window.setTimeout(function(){t(e+i)},i);return s=e+i,r}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(t){clearTimeout(t)}),window.requestAnimFrame=window.requestAnimationFrame,"function"!=typeof Function.prototype.bind&&(Function.prototype.bind=function(){var t=Array.prototype.slice;return function(e){function i(){var s=n.concat(t.call(arguments));r.apply(this instanceof i?this:e,s)}var r=this,n=t.call(arguments,1);if("function"!=typeof r)throw new TypeError;return i.prototype=function s(t){return t&&(s.prototype=t),this instanceof s?void 0:new s}(r.prototype),i}}());var l=n.AjaxRequest=function(){var t=["Msxml2.XMLHTTP","Microsoft.XMLHTTP"];if(!window.ActiveXObject)return window.XMLHttpRequest?new XMLHttpRequest:!1;for(var e=0;t.length>e;e++)try{return new ActiveXObject(t[e])}catch(i){}};n.runList=function(t){console.log(">>>>>>>>>"),console.log("_");var e=0,i=t.first;for(console.log(i);i._iNext;)if(e++,i=i._iNext,console.log(i),e>100){console.log("BREAK");break}},n.EventTarget=function(){var t={};this.addEventListener=this.on=function(e,i){void 0===t[e]&&(t[e]=[]),-1===t[e].indexOf(i)&&t[e].push(i)},this.dispatchEvent=this.emit=function(e){for(var i in t[e.type])t[e.type][i](e)},this.removeEventListener=this.off=function(e,i){var r=t[e].indexOf(i);-1!==r&&t[e].splice(r,1)}},n.autoDetectRenderer=function(t,e,i,r){t||(t=800),e||(e=600);var s=function(){try{return!!window.WebGLRenderingContext&&!!document.createElement("canvas").getContext("experimental-webgl")}catch(t){return!1}}();return s?new n.WebGLRenderer(t,e,i,r):new n.CanvasRenderer(t,e,i,r)},n.PolyK={},n.PolyK.Triangulate=function(t){var e=!0,i=t.length>>1;if(3>i)return[];for(var r=[],s=[],o=0;i>o;o++)s.push(o);for(var o=0,a=i;a>3;){var h=s[(o+0)%a],l=s[(o+1)%a],u=s[(o+2)%a],c=t[2*h],p=t[2*h+1],d=t[2*l],f=t[2*l+1],v=t[2*u],m=t[2*u+1],g=!1;if(n.PolyK._convex(c,p,d,f,v,m,e)){g=!0;for(var x=0;a>x;x++){var b=s[x];if(b!=h&&b!=l&&b!=u&&n.PolyK._PointInTriangle(t[2*b],t[2*b+1],c,p,d,f,v,m)){g=!1;break}}}if(g)r.push(h,l,u),s.splice((o+1)%a,1),a--,o=0;else if(o++>3*a){if(!e)return console.log("PIXI Warning: shape too complex to fill"),[];var r=[];s=[];for(var o=0;i>o;o++)s.push(o);o=0,a=i,e=!1}}return r.push(s[0],s[1],s[2]),r},n.PolyK._PointInTriangle=function(t,e,i,r,n,s,o,a){var h=o-i,l=a-r,u=n-i,c=s-r,p=t-i,d=e-r,f=h*h+l*l,v=h*u+l*c,m=h*p+l*d,g=u*u+c*c,x=u*p+c*d,b=1/(f*g-v*v),y=(g*m-v*x)*b,T=(f*x-v*m)*b;return y>=0&&T>=0&&1>y+T},n.PolyK._convex=function(t,e,i,r,n,s,o){return(e-r)*(n-i)+(i-t)*(s-r)>=0==o},n.shaderFragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * vColor;","}"],n.shaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying float vColor;","void main(void) {","gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],n.stripShaderFragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform float alpha;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * alpha;","}"],n.stripShaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying float vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],n.primitiveShaderFragmentSrc=["precision mediump float;","varying vec4 vColor;","void main(void) {","gl_FragColor = vColor;","}"],n.primitiveShaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec4 aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform float alpha;","varying vec4 vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vColor = aColor * alpha;","}"],n.initPrimitiveShader=function(){var t=n.gl,e=n.compileProgram(n.primitiveShaderVertexSrc,n.primitiveShaderFragmentSrc);t.useProgram(e),e.vertexPositionAttribute=t.getAttribLocation(e,"aVertexPosition"),e.colorAttribute=t.getAttribLocation(e,"aColor"),e.projectionVector=t.getUniformLocation(e,"projectionVector"),e.translationMatrix=t.getUniformLocation(e,"translationMatrix"),e.alpha=t.getUniformLocation(e,"alpha"),n.primitiveProgram=e},n.initDefaultShader=function(){var t=this.gl,e=n.compileProgram(n.shaderVertexSrc,n.shaderFragmentSrc);t.useProgram(e),e.vertexPositionAttribute=t.getAttribLocation(e,"aVertexPosition"),e.projectionVector=t.getUniformLocation(e,"projectionVector"),e.textureCoordAttribute=t.getAttribLocation(e,"aTextureCoord"),e.colorAttribute=t.getAttribLocation(e,"aColor"),e.samplerUniform=t.getUniformLocation(e,"uSampler"),n.shaderProgram=e},n.initDefaultStripShader=function(){var t=this.gl,e=n.compileProgram(n.stripShaderVertexSrc,n.stripShaderFragmentSrc);t.useProgram(e),e.vertexPositionAttribute=t.getAttribLocation(e,"aVertexPosition"),e.projectionVector=t.getUniformLocation(e,"projectionVector"),e.textureCoordAttribute=t.getAttribLocation(e,"aTextureCoord"),e.translationMatrix=t.getUniformLocation(e,"translationMatrix"),e.alpha=t.getUniformLocation(e,"alpha"),e.colorAttribute=t.getAttribLocation(e,"aColor"),e.projectionVector=t.getUniformLocation(e,"projectionVector"),e.samplerUniform=t.getUniformLocation(e,"uSampler"),n.stripShaderProgram=e},n.CompileVertexShader=function(t,e){return n._CompileShader(t,e,t.VERTEX_SHADER)},n.CompileFragmentShader=function(t,e){return n._CompileShader(t,e,t.FRAGMENT_SHADER)},n._CompileShader=function(t,e,i){var r=e.join("\n"),n=t.createShader(i);return t.shaderSource(n,r),t.compileShader(n),t.getShaderParameter(n,t.COMPILE_STATUS)?n:(alert(t.getShaderInfoLog(n)),null)},n.compileProgram=function(t,e){var i=n.gl,r=n.CompileFragmentShader(i,e),s=n.CompileVertexShader(i,t),o=i.createProgram();return i.attachShader(o,s),i.attachShader(o,r),i.linkProgram(o),i.getProgramParameter(o,i.LINK_STATUS)||alert("Could not initialise shaders"),o},n.activateDefaultShader=function(){var t=n.gl,e=n.shaderProgram;t.useProgram(e),t.enableVertexAttribArray(e.vertexPositionAttribute),t.enableVertexAttribArray(e.textureCoordAttribute),t.enableVertexAttribArray(e.colorAttribute)},n.activatePrimitiveShader=function(){var t=n.gl;t.disableVertexAttribArray(n.shaderProgram.textureCoordAttribute),t.disableVertexAttribArray(n.shaderProgram.colorAttribute),t.useProgram(n.primitiveProgram),t.enableVertexAttribArray(n.primitiveProgram.vertexPositionAttribute),t.enableVertexAttribArray(n.primitiveProgram.colorAttribute) -},n.WebGLGraphics=function(){},n.WebGLGraphics.renderGraphics=function(t,e){var i=n.gl;t._webGL||(t._webGL={points:[],indices:[],lastIndex:0,buffer:i.createBuffer(),indexBuffer:i.createBuffer()}),t.dirty&&(t.dirty=!1,t.clearDirty&&(t.clearDirty=!1,t._webGL.lastIndex=0,t._webGL.points=[],t._webGL.indices=[]),n.WebGLGraphics.updateGraphics(t)),n.activatePrimitiveShader();var r=n.mat3.clone(t.worldTransform);n.mat3.transpose(r),i.blendFunc(i.ONE,i.ONE_MINUS_SRC_ALPHA),i.uniformMatrix3fv(n.primitiveProgram.translationMatrix,!1,r),i.uniform2f(n.primitiveProgram.projectionVector,e.x,e.y),i.uniform1f(n.primitiveProgram.alpha,t.worldAlpha),i.bindBuffer(i.ARRAY_BUFFER,t._webGL.buffer),i.vertexAttribPointer(n.shaderProgram.vertexPositionAttribute,2,i.FLOAT,!1,0,0),i.vertexAttribPointer(n.primitiveProgram.vertexPositionAttribute,2,i.FLOAT,!1,24,0),i.vertexAttribPointer(n.primitiveProgram.colorAttribute,4,i.FLOAT,!1,24,8),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,t._webGL.indexBuffer),i.drawElements(i.TRIANGLE_STRIP,t._webGL.indices.length,i.UNSIGNED_SHORT,0),n.activateDefaultShader()},n.WebGLGraphics.updateGraphics=function(t){for(var e=t._webGL.lastIndex;t.graphicsData.length>e;e++){var i=t.graphicsData[e];i.type==n.Graphics.POLY?(i.fill&&i.points.length>3&&n.WebGLGraphics.buildPoly(i,t._webGL),i.lineWidth>0&&n.WebGLGraphics.buildLine(i,t._webGL)):i.type==n.Graphics.RECT?n.WebGLGraphics.buildRectangle(i,t._webGL):(i.type==n.Graphics.CIRC||i.type==n.Graphics.ELIP)&&n.WebGLGraphics.buildCircle(i,t._webGL)}t._webGL.lastIndex=t.graphicsData.length;var r=n.gl;t._webGL.glPoints=new Float32Array(t._webGL.points),r.bindBuffer(r.ARRAY_BUFFER,t._webGL.buffer),r.bufferData(r.ARRAY_BUFFER,t._webGL.glPoints,r.STATIC_DRAW),t._webGL.glIndicies=new Uint16Array(t._webGL.indices),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,t._webGL.indexBuffer),r.bufferData(r.ELEMENT_ARRAY_BUFFER,t._webGL.glIndicies,r.STATIC_DRAW)},n.WebGLGraphics.buildRectangle=function(t,i){var r=t.points,s=r[0],o=r[1],a=r[2],h=r[3];if(t.fill){var l=e(t.fillColor),u=t.fillAlpha,c=l[0]*u,p=l[1]*u,d=l[2]*u,f=i.points,v=i.indices,m=f.length/6;f.push(s,o),f.push(c,p,d,u),f.push(s+a,o),f.push(c,p,d,u),f.push(s,o+h),f.push(c,p,d,u),f.push(s+a,o+h),f.push(c,p,d,u),v.push(m,m,m+1,m+2,m+3,m+3)}t.lineWidth&&(t.points=[s,o,s+a,o,s+a,o+h,s,o+h,s,o],n.WebGLGraphics.buildLine(t,i))},n.WebGLGraphics.buildCircle=function(t,i){var r=t.points,s=r[0],o=r[1],a=r[2],h=r[3],l=40,u=2*Math.PI/l;if(t.fill){var c=e(t.fillColor),p=t.fillAlpha,d=c[0]*p,f=c[1]*p,v=c[2]*p,m=i.points,g=i.indices,x=m.length/6;g.push(x);for(var b=0;l+1>b;b++)m.push(s,o,d,f,v,p),m.push(s+Math.sin(u*b)*a,o+Math.cos(u*b)*h,d,f,v,p),g.push(x++,x++);g.push(x-1)}if(t.lineWidth){t.points=[];for(var b=0;l+1>b;b++)t.points.push(s+Math.sin(u*b)*a,o+Math.cos(u*b)*h);n.WebGLGraphics.buildLine(t,i)}},n.WebGLGraphics.buildLine=function(t,i){var r=t.points;if(0!=r.length){var s=new n.Point(r[0],r[1]),o=new n.Point(r[r.length-2],r[r.length-1]);if(s.x==o.x&&s.y==o.y){r.pop(),r.pop(),o=new n.Point(r[r.length-2],r[r.length-1]);var a=o.x+.5*(s.x-o.x),h=o.y+.5*(s.y-o.y);r.unshift(a,h),r.push(a,h)}var l,u,c,p,d,f,v,m,g,x,b,y,T,_,w,A,R,S,C,L,E,P=i.points,B=i.indices,F=r.length/2,G=r.length,I=P.length/6,D=t.lineWidth/2,M=e(t.lineColor),O=t.lineAlpha,W=M[0]*O,U=M[1]*O,k=M[2]*O;l=r[0],u=r[1],c=r[2],p=r[3],v=-(u-p),m=l-c,E=Math.sqrt(v*v+m*m),v/=E,m/=E,v*=D,m*=D,P.push(l-v,u-m,W,U,k,O),P.push(l+v,u+m,W,U,k,O);for(var j=1;F-1>j;j++)l=r[2*(j-1)],u=r[2*(j-1)+1],c=r[2*j],p=r[2*j+1],d=r[2*(j+1)],f=r[2*(j+1)+1],v=-(u-p),m=l-c,E=Math.sqrt(v*v+m*m),v/=E,m/=E,v*=D,m*=D,g=-(p-f),x=c-d,E=Math.sqrt(g*g+x*x),g/=E,x/=E,g*=D,x*=D,T=-m+u-(-m+p),_=-v+c-(-v+l),w=(-v+l)*(-m+p)-(-v+c)*(-m+u),A=-x+f-(-x+p),R=-g+c-(-g+d),S=(-g+d)*(-x+p)-(-g+c)*(-x+f),C=T*R-A*_,0==C&&(C+=1),px=(_*S-R*w)/C,py=(A*w-T*S)/C,L=(px-c)*(px-c)+(py-p)+(py-p),L>19600?(b=v-g,y=m-x,E=Math.sqrt(b*b+y*y),b/=E,y/=E,b*=D,y*=D,P.push(c-b,p-y),P.push(W,U,k,O),P.push(c+b,p+y),P.push(W,U,k,O),P.push(c-b,p-y),P.push(W,U,k,O),G++):(P.push(px,py),P.push(W,U,k,O),P.push(c-(px-c),p-(py-p)),P.push(W,U,k,O));l=r[2*(F-2)],u=r[2*(F-2)+1],c=r[2*(F-1)],p=r[2*(F-1)+1],v=-(u-p),m=l-c,E=Math.sqrt(v*v+m*m),v/=E,m/=E,v*=D,m*=D,P.push(c-v,p-m),P.push(W,U,k,O),P.push(c+v,p+m),P.push(W,U,k,O),B.push(I);for(var j=0;G>j;j++)B.push(I++);B.push(I-1)}},n.WebGLGraphics.buildPoly=function(t,i){var r=t.points;if(!(6>r.length)){for(var s=i.points,o=i.indices,a=r.length/2,h=e(t.fillColor),l=t.fillAlpha,u=h[0]*l,c=h[1]*l,p=h[2]*l,d=n.PolyK.Triangulate(r),f=s.length/6,v=0;d.length>v;v+=3)o.push(d[v]+f),o.push(d[v]+f),o.push(d[v+1]+f),o.push(d[v+2]+f),o.push(d[v+2]+f);for(var v=0;a>v;v++)s.push(r[2*v],r[2*v+1],u,c,p,l)}},n._defaultFrame=new n.Rectangle(0,0,1,1),n.gl,n.WebGLRenderer=function(t,e,i,r){this.transparent=!!r,this.width=t||800,this.height=e||600,this.view=i||document.createElement("canvas"),this.view.width=this.width,this.view.height=this.height;var s=this;this.view.addEventListener("webglcontextlost",function(t){s.handleContextLost(t)},!1),this.view.addEventListener("webglcontextrestored",function(t){s.handleContextRestored(t)},!1),this.batchs=[];try{n.gl=this.gl=this.view.getContext("experimental-webgl",{alpha:this.transparent,antialias:!0,premultipliedAlpha:!1,stencil:!0})}catch(o){throw Error(" This browser does not support webGL. Try using the canvas renderer"+this)}n.initPrimitiveShader(),n.initDefaultShader(),n.initDefaultStripShader(),n.activateDefaultShader();var a=this.gl;n.WebGLRenderer.gl=a,this.batch=new n.WebGLBatch(a),a.disable(a.DEPTH_TEST),a.disable(a.CULL_FACE),a.enable(a.BLEND),a.colorMask(!0,!0,!0,this.transparent),n.projection=new n.Point(400,300),this.resize(this.width,this.height),this.contextLost=!1,this.stageRenderGroup=new n.WebGLRenderGroup(this.gl)},n.WebGLRenderer.prototype.constructor=n.WebGLRenderer,n.WebGLRenderer.getBatch=function(){return 0==n._batchs.length?new n.WebGLBatch(n.WebGLRenderer.gl):n._batchs.pop()},n.WebGLRenderer.returnBatch=function(t){t.clean(),n._batchs.push(t)},n.WebGLRenderer.prototype.render=function(t){if(!this.contextLost){this.__stage!==t&&(this.__stage=t,this.stageRenderGroup.setRenderable(t)),n.WebGLRenderer.updateTextures(),t.updateTransform();var e=this.gl;if(e.colorMask(!0,!0,!0,this.transparent),e.viewport(0,0,this.width,this.height),e.bindFramebuffer(e.FRAMEBUFFER,null),e.clearColor(t.backgroundColorSplit[0],t.backgroundColorSplit[1],t.backgroundColorSplit[2],!this.transparent),e.clear(e.COLOR_BUFFER_BIT),this.stageRenderGroup.backgroundColor=t.backgroundColorSplit,this.stageRenderGroup.render(n.projection),t.interactive&&(t._interactiveEventsAdded||(t._interactiveEventsAdded=!0,t.interactionManager.setTarget(this))),n.Texture.frameUpdates.length>0){for(var i=0;n.Texture.frameUpdates.length>i;i++)n.Texture.frameUpdates[i].updateFrame=!1;n.Texture.frameUpdates=[]}}},n.WebGLRenderer.updateTextures=function(){for(var t=0;n.texturesToUpdate.length>t;t++)this.updateTexture(n.texturesToUpdate[t]);for(var t=0;n.texturesToDestroy.length>t;t++)this.destroyTexture(n.texturesToDestroy[t]);n.texturesToUpdate=[],n.texturesToDestroy=[]},n.WebGLRenderer.updateTexture=function(t){var e=n.gl;t._glTexture||(t._glTexture=e.createTexture()),t.hasLoaded&&(e.bindTexture(e.TEXTURE_2D,t._glTexture),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,t.source),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),t._powerOf2?(e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT)):(e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE)),e.bindTexture(e.TEXTURE_2D,null))},n.WebGLRenderer.prototype.destroyTexture=function(t){var e=this.gl;t._glTexture&&(t._glTexture=e.createTexture(),e.deleteTexture(e.TEXTURE_2D,t._glTexture))},n.WebGLRenderer.prototype.resize=function(t,e){this.width=t,this.height=e,this.view.width=t,this.view.height=e,this.gl.viewport(0,0,this.width,this.height),n.projection.x=this.width/2,n.projection.y=this.height/2},n.WebGLRenderer.prototype.handleContextLost=function(t){t.preventDefault(),this.contextLost=!0},n.WebGLRenderer.prototype.handleContextRestored=function(){this.gl=this.view.getContext("experimental-webgl",{alpha:!0}),this.initShaders();for(var t in n.TextureCache){var e=n.TextureCache[t].baseTexture;e._glTexture=null,n.WebGLRenderer.updateTexture(e)}for(var i=0;this.batchs.length>i;i++)this.batchs[i].restoreLostContext(this.gl),this.batchs[i].dirty=!0;n._restoreBatchs(this.gl),this.contextLost=!1},n._batchs=[],n._getBatch=function(t){return 0==n._batchs.length?new n.WebGLBatch(t):n._batchs.pop()},n._returnBatch=function(t){t.clean(),n._batchs.push(t)},n._restoreBatchs=function(t){for(var e=0;n._batchs.length>e;e++)n._batchs[e].restoreLostContext(t)},n.WebGLBatch=function(t){this.gl=t,this.size=0,this.vertexBuffer=t.createBuffer(),this.indexBuffer=t.createBuffer(),this.uvBuffer=t.createBuffer(),this.colorBuffer=t.createBuffer(),this.blendMode=n.blendModes.NORMAL,this.dynamicSize=1},n.WebGLBatch.prototype.constructor=n.WebGLBatch,n.WebGLBatch.prototype.clean=function(){this.verticies=[],this.uvs=[],this.indices=[],this.colors=[],this.dynamicSize=1,this.texture=null,this.last=null,this.size=0,this.head,this.tail},n.WebGLBatch.prototype.restoreLostContext=function(t){this.gl=t,this.vertexBuffer=t.createBuffer(),this.indexBuffer=t.createBuffer(),this.uvBuffer=t.createBuffer(),this.colorBuffer=t.createBuffer()},n.WebGLBatch.prototype.init=function(t){t.batch=this,this.dirty=!0,this.blendMode=t.blendMode,this.texture=t.texture.baseTexture,this.head=t,this.tail=t,this.size=1,this.growBatch()},n.WebGLBatch.prototype.insertBefore=function(t,e){this.size++,t.batch=this,this.dirty=!0;var i=e.__prev;e.__prev=t,t.__next=e,i?(t.__prev=i,i.__next=t):this.head=t},n.WebGLBatch.prototype.insertAfter=function(t,e){this.size++,t.batch=this,this.dirty=!0;var i=e.__next;e.__next=t,t.__prev=e,i?(t.__next=i,i.__prev=t):this.tail=t},n.WebGLBatch.prototype.remove=function(t){return this.size--,0==this.size?(t.batch=null,t.__prev=null,t.__next=null,void 0):(t.__prev?t.__prev.__next=t.__next:(this.head=t.__next,this.head.__prev=null),t.__next?t.__next.__prev=t.__prev:(this.tail=t.__prev,this.tail.__next=null),t.batch=null,t.__next=null,t.__prev=null,this.dirty=!0,void 0)},n.WebGLBatch.prototype.split=function(t){this.dirty=!0;var e=new n.WebGLBatch(this.gl);e.init(t),e.texture=this.texture,e.tail=this.tail,this.tail=t.__prev,this.tail.__next=null,t.__prev=null;for(var i=0;t;)i++,t.batch=e,t=t.__next;return e.size=i,this.size-=i,e},n.WebGLBatch.prototype.merge=function(t){this.dirty=!0,this.tail.__next=t.head,t.head.__prev=this.tail,this.size+=t.size,this.tail=t.tail;for(var e=t.head;e;)e.batch=this,e=e.__next},n.WebGLBatch.prototype.growBatch=function(){var t=this.gl;this.dynamicSize=1==this.size?1:1.5*this.size,this.verticies=new Float32Array(8*this.dynamicSize),t.bindBuffer(t.ARRAY_BUFFER,this.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,this.verticies,t.DYNAMIC_DRAW),this.uvs=new Float32Array(8*this.dynamicSize),t.bindBuffer(t.ARRAY_BUFFER,this.uvBuffer),t.bufferData(t.ARRAY_BUFFER,this.uvs,t.DYNAMIC_DRAW),this.dirtyUVS=!0,this.colors=new Float32Array(4*this.dynamicSize),t.bindBuffer(t.ARRAY_BUFFER,this.colorBuffer),t.bufferData(t.ARRAY_BUFFER,this.colors,t.DYNAMIC_DRAW),this.dirtyColors=!0,this.indices=new Uint16Array(6*this.dynamicSize);for(var e=this.indices.length/6,i=0;e>i;i++){var r=6*i,n=4*i;this.indices[r+0]=n+0,this.indices[r+1]=n+1,this.indices[r+2]=n+2,this.indices[r+3]=n+0,this.indices[r+4]=n+2,this.indices[r+5]=n+3}t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,this.indices,t.STATIC_DRAW)},n.WebGLBatch.prototype.refresh=function(){this.gl,this.dynamicSizer;r++)i=this.batchs[r],i instanceof n.WebGLBatch?this.batchs[r].render():i instanceof n.TilingSprite?i.visible&&this.renderTilingSprite(i,t):i instanceof n.Strip?i.visible&&this.renderStrip(i,t):i instanceof n.Graphics?i.visible&&i.renderable&&n.WebGLGraphics.renderGraphics(i,t):i instanceof n.FilterBlock&&(i.open?(e.enable(e.STENCIL_TEST),e.colorMask(!1,!1,!1,!1),e.stencilFunc(e.ALWAYS,1,255),e.stencilOp(e.KEEP,e.KEEP,e.REPLACE),n.WebGLGraphics.renderGraphics(i.mask,t),e.colorMask(!0,!0,!0,!1),e.stencilFunc(e.NOTEQUAL,0,255),e.stencilOp(e.KEEP,e.KEEP,e.KEEP)):e.disable(e.STENCIL_TEST))},n.WebGLRenderGroup.prototype.handleFilter=function(){},n.WebGLRenderGroup.prototype.renderSpecific=function(t,e){n.WebGLRenderer.updateTextures();var i=this.gl;this.checkVisibility(t,t.visible),i.uniform2f(n.shaderProgram.projectionVector,e.x,e.y);for(var r,s,o,a,h=t.first;h._iNext&&(h=h._iNext,!h.renderable||!h.__renderGroup););var l=h.batch;if(h instanceof n.Sprite){l=h.batch;var u=l.head;if(u==h)r=0;else for(r=1;u.__next!=h;)r++,u=u.__next}else l=h;for(var c,p=t,d=t;d.children.length>0;)d=d.children[d.children.length-1],d.renderable&&(p=d);if(p instanceof n.Sprite){c=p.batch;var u=c.head;if(u==p)o=0;else for(o=1;u.__next!=p;)o++,u=u.__next}else c=p;if(l==c)return l instanceof n.WebGLBatch?l.render(r,o+1):this.renderSpecial(l,e),void 0;s=this.batchs.indexOf(l),a=this.batchs.indexOf(c),l instanceof n.WebGLBatch?l.render(r):this.renderSpecial(l,e);for(var f=s+1;a>f;f++)renderable=this.batchs[f],renderable instanceof n.WebGLBatch?this.batchs[f].render():this.renderSpecial(renderable,e);c instanceof n.WebGLBatch?c.render(0,o+1):this.renderSpecial(c,e)},n.WebGLRenderGroup.prototype.renderSpecial=function(t,e){if(t instanceof n.TilingSprite)t.visible&&this.renderTilingSprite(t,e);else if(t instanceof n.Strip)t.visible&&this.renderStrip(t,e);else if(t instanceof n.CustomRenderable)t.visible&&t.renderWebGL(this,e);else if(t instanceof n.Graphics)t.visible&&t.renderable&&n.WebGLGraphics.renderGraphics(t,e);else if(t instanceof n.FilterBlock){var i=n.gl;t.open?(i.enable(i.STENCIL_TEST),i.colorMask(!1,!1,!1,!1),i.stencilFunc(i.ALWAYS,1,255),i.stencilOp(i.KEEP,i.KEEP,i.REPLACE),n.WebGLGraphics.renderGraphics(t.mask,e),i.colorMask(!0,!0,!0,!0),i.stencilFunc(i.NOTEQUAL,0,255),i.stencilOp(i.KEEP,i.KEEP,i.KEEP)):i.disable(i.STENCIL_TEST)}},n.WebGLRenderGroup.prototype.checkVisibility=function(t,e){for(var i=t.children,r=0;i.length>r;r++){var n=i[r];n.worldVisible=n.visible&&e,n.textureChange&&(n.textureChange=!1,n.worldVisible&&this.updateTexture(n)),n.children.length>0&&this.checkVisibility(n,n.worldVisible)}},n.WebGLRenderGroup.prototype.updateTexture=function(t){this.removeObject(t);for(var e=t.first;e!=this.root&&(e=e._iPrev,!e.renderable||!e.__renderGroup););for(var i=t.last;i._iNext&&(i=i._iNext,!i.renderable||!i.__renderGroup););this.insertObject(t,e,i)},n.WebGLRenderGroup.prototype.addFilterBlocks=function(t,e){t.__renderGroup=this,e.__renderGroup=this;for(var i=t;i!=this.root&&(i=i._iPrev,!i.renderable||!i.__renderGroup););this.insertAfter(t,i);for(var r=e;r!=this.root&&(r=r._iPrev,!r.renderable||!r.__renderGroup););this.insertAfter(e,r)},n.WebGLRenderGroup.prototype.removeFilterBlocks=function(t,e){this.removeObject(t),this.removeObject(e)},n.WebGLRenderGroup.prototype.addDisplayObjectAndChildren=function(t){t.__renderGroup&&t.__renderGroup.removeDisplayObjectAndChildren(t);for(var e=t.first;e!=this.root.first&&(e=e._iPrev,!e.renderable||!e.__renderGroup););for(var i=t.last;i._iNext&&(i=i._iNext,!i.renderable||!i.__renderGroup););var r=t.first,n=t.last._iNext;do r.__renderGroup=this,r.renderable&&(this.insertObject(r,e,i),e=r),r=r._iNext;while(r!=n)},n.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren=function(t){if(t.__renderGroup==this){t.last;do t.__renderGroup=null,t.renderable&&this.removeObject(t),t=t._iNext;while(t)}},n.WebGLRenderGroup.prototype.insertObject=function(t,e,i){var r=e,s=i;if(t instanceof n.Sprite){var o,a;if(r instanceof n.Sprite){if(o=r.batch,o&&o.texture==t.texture.baseTexture&&o.blendMode==t.blendMode)return o.insertAfter(t,r),void 0}else o=r;if(s)if(s instanceof n.Sprite){if(a=s.batch){if(a.texture==t.texture.baseTexture&&a.blendMode==t.blendMode)return a.insertBefore(t,s),void 0;if(a==o){var h=o.split(s),l=n.WebGLRenderer.getBatch(),u=this.batchs.indexOf(o);return l.init(t),this.batchs.splice(u+1,0,l,h),void 0}}}else a=s;var l=n.WebGLRenderer.getBatch();if(l.init(t),o){var u=this.batchs.indexOf(o);this.batchs.splice(u+1,0,l)}else this.batchs.push(l)}else t instanceof n.TilingSprite?this.initTilingSprite(t):t instanceof n.Strip&&this.initStrip(t),this.insertAfter(t,r)},n.WebGLRenderGroup.prototype.insertAfter=function(t,e){if(e instanceof n.Sprite){var i=e.batch;if(i)if(i.tail==e){var r=this.batchs.indexOf(i);this.batchs.splice(r+1,0,t)}else{var s=i.split(e.__next),r=this.batchs.indexOf(i);this.batchs.splice(r+1,0,t,s)}else this.batchs.push(t)}else{var r=this.batchs.indexOf(e);this.batchs.splice(r+1,0,t)}},n.WebGLRenderGroup.prototype.removeObject=function(t){var e;if(t instanceof n.Sprite){var i=t.batch;if(!i)return;i.remove(t),0==i.size&&(e=i)}else e=t;if(e){var r=this.batchs.indexOf(e);if(-1==r)return;if(0==r||r==this.batchs.length-1)return this.batchs.splice(r,1),e instanceof n.WebGLBatch&&n.WebGLRenderer.returnBatch(e),void 0;if(this.batchs[r-1]instanceof n.WebGLBatch&&this.batchs[r+1]instanceof n.WebGLBatch&&this.batchs[r-1].texture==this.batchs[r+1].texture&&this.batchs[r-1].blendMode==this.batchs[r+1].blendMode)return this.batchs[r-1].merge(this.batchs[r+1]),e instanceof n.WebGLBatch&&n.WebGLRenderer.returnBatch(e),n.WebGLRenderer.returnBatch(this.batchs[r+1]),this.batchs.splice(r,2),void 0;this.batchs.splice(r,1),e instanceof n.WebGLBatch&&n.WebGLRenderer.returnBatch(e)}},n.WebGLRenderGroup.prototype.initTilingSprite=function(t){var e=this.gl;t.verticies=new Float32Array([0,0,t.width,0,t.width,t.height,0,t.height]),t.uvs=new Float32Array([0,0,1,0,1,1,0,1]),t.colors=new Float32Array([1,1,1,1]),t.indices=new Uint16Array([0,1,3,2]),t._vertexBuffer=e.createBuffer(),t._indexBuffer=e.createBuffer(),t._uvBuffer=e.createBuffer(),t._colorBuffer=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,t._vertexBuffer),e.bufferData(e.ARRAY_BUFFER,t.verticies,e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,t._uvBuffer),e.bufferData(e.ARRAY_BUFFER,t.uvs,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,t._colorBuffer),e.bufferData(e.ARRAY_BUFFER,t.colors,e.STATIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,t._indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,t.indices,e.STATIC_DRAW),t.texture.baseTexture._glTexture?(e.bindTexture(e.TEXTURE_2D,t.texture.baseTexture._glTexture),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT),t.texture.baseTexture._powerOf2=!0):t.texture.baseTexture._powerOf2=!0},n.WebGLRenderGroup.prototype.renderStrip=function(t,e){var i=this.gl,r=n.shaderProgram;i.useProgram(n.stripShaderProgram);var s=n.mat3.clone(t.worldTransform);n.mat3.transpose(s),i.uniformMatrix3fv(n.stripShaderProgram.translationMatrix,!1,s),i.uniform2f(n.stripShaderProgram.projectionVector,e.x,e.y),i.uniform1f(n.stripShaderProgram.alpha,t.worldAlpha),t.dirty?(t.dirty=!1,i.bindBuffer(i.ARRAY_BUFFER,t._vertexBuffer),i.bufferData(i.ARRAY_BUFFER,t.verticies,i.STATIC_DRAW),i.vertexAttribPointer(r.vertexPositionAttribute,2,i.FLOAT,!1,0,0),i.bindBuffer(i.ARRAY_BUFFER,t._uvBuffer),i.bufferData(i.ARRAY_BUFFER,t.uvs,i.STATIC_DRAW),i.vertexAttribPointer(r.textureCoordAttribute,2,i.FLOAT,!1,0,0),i.activeTexture(i.TEXTURE0),i.bindTexture(i.TEXTURE_2D,t.texture.baseTexture._glTexture),i.bindBuffer(i.ARRAY_BUFFER,t._colorBuffer),i.bufferData(i.ARRAY_BUFFER,t.colors,i.STATIC_DRAW),i.vertexAttribPointer(r.colorAttribute,1,i.FLOAT,!1,0,0),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,t._indexBuffer),i.bufferData(i.ELEMENT_ARRAY_BUFFER,t.indices,i.STATIC_DRAW)):(i.bindBuffer(i.ARRAY_BUFFER,t._vertexBuffer),i.bufferSubData(i.ARRAY_BUFFER,0,t.verticies),i.vertexAttribPointer(r.vertexPositionAttribute,2,i.FLOAT,!1,0,0),i.bindBuffer(i.ARRAY_BUFFER,t._uvBuffer),i.vertexAttribPointer(r.textureCoordAttribute,2,i.FLOAT,!1,0,0),i.activeTexture(i.TEXTURE0),i.bindTexture(i.TEXTURE_2D,t.texture.baseTexture._glTexture),i.bindBuffer(i.ARRAY_BUFFER,t._colorBuffer),i.vertexAttribPointer(r.colorAttribute,1,i.FLOAT,!1,0,0),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,t._indexBuffer)),i.drawElements(i.TRIANGLE_STRIP,t.indices.length,i.UNSIGNED_SHORT,0),i.useProgram(n.shaderProgram)},n.WebGLRenderGroup.prototype.renderTilingSprite=function(t,e){var i=this.gl;n.shaderProgram;var r=t.tilePosition,s=t.tileScale,o=r.x/t.texture.baseTexture.width,a=r.y/t.texture.baseTexture.height,h=t.width/t.texture.baseTexture.width/s.x,l=t.height/t.texture.baseTexture.height/s.y;t.uvs[0]=0-o,t.uvs[1]=0-a,t.uvs[2]=1*h-o,t.uvs[3]=0-a,t.uvs[4]=1*h-o,t.uvs[5]=1*l-a,t.uvs[6]=0-o,t.uvs[7]=1*l-a,i.bindBuffer(i.ARRAY_BUFFER,t._uvBuffer),i.bufferSubData(i.ARRAY_BUFFER,0,t.uvs),this.renderStrip(t,e)},n.WebGLRenderGroup.prototype.initStrip=function(t){var e=this.gl;this.shaderProgram,t._vertexBuffer=e.createBuffer(),t._indexBuffer=e.createBuffer(),t._uvBuffer=e.createBuffer(),t._colorBuffer=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,t._vertexBuffer),e.bufferData(e.ARRAY_BUFFER,t.verticies,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,t._uvBuffer),e.bufferData(e.ARRAY_BUFFER,t.uvs,e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,t._colorBuffer),e.bufferData(e.ARRAY_BUFFER,t.colors,e.STATIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,t._indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,t.indices,e.STATIC_DRAW)},n.CanvasRenderer=function(t,e,i,r){this.transparent=r,this.width=t||800,this.height=e||600,this.view=i||document.createElement("canvas"),this.context=this.view.getContext("2d"),this.refresh=!0,this.view.width=this.width,this.view.height=this.height,this.count=0},n.CanvasRenderer.prototype.constructor=n.CanvasRenderer,n.CanvasRenderer.prototype.render=function(t){n.texturesToUpdate=[],n.texturesToDestroy=[],t.updateTransform(),this.view.style.backgroundColor==t.backgroundColorString||this.transparent||(this.view.style.backgroundColor=t.backgroundColorString),this.context.setTransform(1,0,0,1,0,0),this.context.clearRect(0,0,this.width,this.height),this.renderDisplayObject(t),t.interactive&&(t._interactiveEventsAdded||(t._interactiveEventsAdded=!0,t.interactionManager.setTarget(this))),n.Texture.frameUpdates.length>0&&(n.Texture.frameUpdates=[])},n.CanvasRenderer.prototype.resize=function(t,e){this.width=t,this.height=e,this.view.width=t,this.view.height=e},n.CanvasRenderer.prototype.renderDisplayObject=function(t){var e,i=this.context;i.globalCompositeOperation="source-over";var r=t.last._iNext;t=t.first;do if(e=t.worldTransform,t.visible)if(t.renderable){if(t instanceof n.Sprite){var s=t.texture.frame;s&&(i.globalAlpha=t.worldAlpha,i.setTransform(e[0],e[3],e[1],e[4],e[2],e[5]),i.drawImage(t.texture.baseTexture.source,s.x,s.y,s.width,s.height,t.anchor.x*-s.width,t.anchor.y*-s.height,s.width,s.height))}else if(t instanceof n.Strip)i.setTransform(e[0],e[3],e[1],e[4],e[2],e[5]),this.renderStrip(t);else if(t instanceof n.TilingSprite)i.setTransform(e[0],e[3],e[1],e[4],e[2],e[5]),this.renderTilingSprite(t);else if(t instanceof n.CustomRenderable)t.renderCanvas(this);else if(t instanceof n.Graphics)i.setTransform(e[0],e[3],e[1],e[4],e[2],e[5]),n.CanvasGraphics.renderGraphics(t,i);else if(t instanceof n.FilterBlock)if(t.open){i.save();var o=t.mask.alpha,a=t.mask.worldTransform;i.setTransform(a[0],a[3],a[1],a[4],a[2],a[5]),t.mask.worldAlpha=.5,i.worldAlpha=0,n.CanvasGraphics.renderGraphicsMask(t.mask,i),i.clip(),t.mask.worldAlpha=o}else i.restore();t=t._iNext}else t=t._iNext;else t=t.last._iNext;while(t!=r)},n.CanvasRenderer.prototype.renderStripFlat=function(t){var e=this.context,i=t.verticies;t.uvs;var r=i.length/2;this.count++,e.beginPath();for(var n=1;r-2>n;n++){var s=2*n,o=i[s],a=i[s+2],h=i[s+4],l=i[s+1],u=i[s+3],c=i[s+5];e.moveTo(o,l),e.lineTo(a,u),e.lineTo(h,c)}e.fillStyle="#FF0000",e.fill(),e.closePath()},n.CanvasRenderer.prototype.renderTilingSprite=function(t){var e=this.context;e.globalAlpha=t.worldAlpha,t.__tilePattern||(t.__tilePattern=e.createPattern(t.texture.baseTexture.source,"repeat")),e.beginPath();var i=t.tilePosition,r=t.tileScale;e.scale(r.x,r.y),e.translate(i.x,i.y),e.fillStyle=t.__tilePattern,e.fillRect(-i.x,-i.y,t.width/r.x,t.height/r.y),e.scale(1/r.x,1/r.y),e.translate(-i.x,-i.y),e.closePath()},n.CanvasRenderer.prototype.renderStrip=function(t){var e=this.context,i=t.verticies,r=t.uvs,n=i.length/2;this.count++;for(var s=1;n-2>s;s++){var o=2*s,a=i[o],h=i[o+2],l=i[o+4],u=i[o+1],c=i[o+3],p=i[o+5],d=r[o]*t.texture.width,f=r[o+2]*t.texture.width,v=r[o+4]*t.texture.width,m=r[o+1]*t.texture.height,g=r[o+3]*t.texture.height,x=r[o+5]*t.texture.height;e.save(),e.beginPath(),e.moveTo(a,u),e.lineTo(h,c),e.lineTo(l,p),e.closePath(),e.clip();var b=d*g+m*v+f*x-g*v-m*f-d*x,y=a*g+m*l+h*x-g*l-m*h-a*x,T=d*h+a*v+f*l-h*v-a*f-d*l,_=d*g*l+m*h*v+a*f*x-a*g*v-m*f*l-d*h*x,w=u*g+m*p+c*x-g*p-m*c-u*x,A=d*c+u*v+f*p-c*v-u*f-d*p,R=d*g*p+m*c*v+u*f*x-u*g*v-m*f*p-d*c*x;e.transform(y/b,w/b,T/b,A/b,_/b,R/b),e.drawImage(t.texture.baseTexture.source,0,0),e.restore()}},n.CanvasGraphics=function(){},n.CanvasGraphics.renderGraphics=function(t,e){for(var i=t.worldAlpha,r=0;t.graphicsData.length>r;r++){var s=t.graphicsData[r],o=s.points;if(e.strokeStyle=color="#"+("00000"+(0|s.lineColor).toString(16)).substr(-6),e.lineWidth=s.lineWidth,s.type==n.Graphics.POLY){e.beginPath(),e.moveTo(o[0],o[1]);for(var a=1;o.length/2>a;a++)e.lineTo(o[2*a],o[2*a+1]);o[0]==o[o.length-2]&&o[1]==o[o.length-1]&&e.closePath(),s.fill&&(e.globalAlpha=s.fillAlpha*i,e.fillStyle=color="#"+("00000"+(0|s.fillColor).toString(16)).substr(-6),e.fill()),s.lineWidth&&(e.globalAlpha=s.lineAlpha*i,e.stroke())}else if(s.type==n.Graphics.RECT)s.fillColor&&(e.globalAlpha=s.fillAlpha*i,e.fillStyle=color="#"+("00000"+(0|s.fillColor).toString(16)).substr(-6),e.fillRect(o[0],o[1],o[2],o[3])),s.lineWidth&&(e.globalAlpha=s.lineAlpha*i,e.strokeRect(o[0],o[1],o[2],o[3]));else if(s.type==n.Graphics.CIRC)e.beginPath(),e.arc(o[0],o[1],o[2],0,2*Math.PI),e.closePath(),s.fill&&(e.globalAlpha=s.fillAlpha*i,e.fillStyle=color="#"+("00000"+(0|s.fillColor).toString(16)).substr(-6),e.fill()),s.lineWidth&&(e.globalAlpha=s.lineAlpha*i,e.stroke());else if(s.type==n.Graphics.ELIP){var h=s.points,l=2*h[2],u=2*h[3],c=h[0]-l/2,p=h[1]-u/2;e.beginPath();var d=.5522848,f=l/2*d,v=u/2*d,m=c+l,g=p+u,x=c+l/2,b=p+u/2;e.moveTo(c,b),e.bezierCurveTo(c,b-v,x-f,p,x,p),e.bezierCurveTo(x+f,p,m,b-v,m,b),e.bezierCurveTo(m,b+v,x+f,g,x,g),e.bezierCurveTo(x-f,g,c,b+v,c,b),e.closePath(),s.fill&&(e.globalAlpha=s.fillAlpha*i,e.fillStyle=color="#"+("00000"+(0|s.fillColor).toString(16)).substr(-6),e.fill()),s.lineWidth&&(e.globalAlpha=s.lineAlpha*i,e.stroke())}}},n.CanvasGraphics.renderGraphicsMask=function(t,e){t.worldAlpha;var i=t.graphicsData.length;i>1&&(i=1,console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object"));for(var r=0;1>r;r++){var s=t.graphicsData[r],o=s.points;if(s.type==n.Graphics.POLY){e.beginPath(),e.moveTo(o[0],o[1]);for(var a=1;o.length/2>a;a++)e.lineTo(o[2*a],o[2*a+1]);o[0]==o[o.length-2]&&o[1]==o[o.length-1]&&e.closePath()}else if(s.type==n.Graphics.RECT)e.beginPath(),e.rect(o[0],o[1],o[2],o[3]),e.closePath();else if(s.type==n.Graphics.CIRC)e.beginPath(),e.arc(o[0],o[1],o[2],0,2*Math.PI),e.closePath();else if(s.type==n.Graphics.ELIP){var h=s.points,l=2*h[2],u=2*h[3],c=h[0]-l/2,p=h[1]-u/2;e.beginPath();var d=.5522848,f=l/2*d,v=u/2*d,m=c+l,g=p+u,x=c+l/2,b=p+u/2;e.moveTo(c,b),e.bezierCurveTo(c,b-v,x-f,p,x,p),e.bezierCurveTo(x+f,p,m,b-v,m,b),e.bezierCurveTo(m,b+v,x+f,g,x,g),e.bezierCurveTo(x-f,g,c,b+v,c,b),e.closePath()}}},n.Graphics=function(){n.DisplayObjectContainer.call(this),this.renderable=!0,this.fillAlpha=1,this.lineWidth=0,this.lineColor="black",this.graphicsData=[],this.currentPath={points:[]}},n.Graphics.prototype=Object.create(n.DisplayObjectContainer.prototype),n.Graphics.prototype.constructor=n.Graphics,n.Graphics.prototype.lineStyle=function(t,e,i){0==this.currentPath.points.length&&this.graphicsData.pop(),this.lineWidth=t||0,this.lineColor=e||0,this.lineAlpha=void 0==i?1:i,this.currentPath={lineWidth:this.lineWidth,lineColor:this.lineColor,lineAlpha:this.lineAlpha,fillColor:this.fillColor,fillAlpha:this.fillAlpha,fill:this.filling,points:[],type:n.Graphics.POLY},this.graphicsData.push(this.currentPath)},n.Graphics.prototype.moveTo=function(t,e){0==this.currentPath.points.length&&this.graphicsData.pop(),this.currentPath=this.currentPath={lineWidth:this.lineWidth,lineColor:this.lineColor,lineAlpha:this.lineAlpha,fillColor:this.fillColor,fillAlpha:this.fillAlpha,fill:this.filling,points:[],type:n.Graphics.POLY},this.currentPath.points.push(t,e),this.graphicsData.push(this.currentPath) -},n.Graphics.prototype.lineTo=function(t,e){this.currentPath.points.push(t,e),this.dirty=!0},n.Graphics.prototype.beginFill=function(t,e){this.filling=!0,this.fillColor=t||0,this.fillAlpha=e||1},n.Graphics.prototype.endFill=function(){this.filling=!1,this.fillColor=null,this.fillAlpha=1},n.Graphics.prototype.drawRect=function(t,e,i,r){0==this.currentPath.points.length&&this.graphicsData.pop(),this.currentPath={lineWidth:this.lineWidth,lineColor:this.lineColor,lineAlpha:this.lineAlpha,fillColor:this.fillColor,fillAlpha:this.fillAlpha,fill:this.filling,points:[t,e,i,r],type:n.Graphics.RECT},this.graphicsData.push(this.currentPath),this.dirty=!0},n.Graphics.prototype.drawCircle=function(t,e,i){0==this.currentPath.points.length&&this.graphicsData.pop(),this.currentPath={lineWidth:this.lineWidth,lineColor:this.lineColor,lineAlpha:this.lineAlpha,fillColor:this.fillColor,fillAlpha:this.fillAlpha,fill:this.filling,points:[t,e,i,i],type:n.Graphics.CIRC},this.graphicsData.push(this.currentPath),this.dirty=!0},n.Graphics.prototype.drawElipse=function(t,e,i,r){0==this.currentPath.points.length&&this.graphicsData.pop(),this.currentPath={lineWidth:this.lineWidth,lineColor:this.lineColor,lineAlpha:this.lineAlpha,fillColor:this.fillColor,fillAlpha:this.fillAlpha,fill:this.filling,points:[t,e,i,r],type:n.Graphics.ELIP},this.graphicsData.push(this.currentPath),this.dirty=!0},n.Graphics.prototype.clear=function(){this.lineWidth=0,this.filling=!1,this.dirty=!0,this.clearDirty=!0,this.graphicsData=[]},n.Graphics.POLY=0,n.Graphics.RECT=1,n.Graphics.CIRC=2,n.Graphics.ELIP=3,n.Strip=function(t,e,i){n.DisplayObjectContainer.call(this),this.texture=t,this.blendMode=n.blendModes.NORMAL;try{this.uvs=new Float32Array([0,1,1,1,1,0,0,1]),this.verticies=new Float32Array([0,0,0,0,0,0,0,0,0]),this.colors=new Float32Array([1,1,1,1]),this.indices=new Uint16Array([0,1,2,3])}catch(r){this.uvs=[0,1,1,1,1,0,0,1],this.verticies=[0,0,0,0,0,0,0,0,0],this.colors=[1,1,1,1],this.indices=[0,1,2,3]}this.width=e,this.height=i,t.baseTexture.hasLoaded?(this.width=this.texture.frame.width,this.height=this.texture.frame.height,this.updateFrame=!0):(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},n.Strip.prototype=Object.create(n.DisplayObjectContainer.prototype),n.Strip.prototype.constructor=n.Strip,n.Strip.prototype.setTexture=function(t){this.texture=t,this.width=t.frame.width,this.height=t.frame.height,this.updateFrame=!0},n.Strip.prototype.onTextureUpdate=function(){this.updateFrame=!0},n.Rope=function(t,e){n.Strip.call(this,t),this.points=e;try{this.verticies=new Float32Array(4*e.length),this.uvs=new Float32Array(4*e.length),this.colors=new Float32Array(2*e.length),this.indices=new Uint16Array(2*e.length)}catch(i){this.verticies=verticies,this.uvs=uvs,this.colors=colors,this.indices=indices}this.refresh()},n.Rope.prototype=Object.create(n.Strip.prototype),n.Rope.prototype.constructor=n.Rope,n.Rope.prototype.refresh=function(){var t=this.points;if(!(1>t.length)){var e=this.uvs,i=this.indices,r=this.colors,n=t[0],s=t[0];this.count-=.2,e[0]=0,e[1]=1,e[2]=0,e[3]=1,r[0]=1,r[1]=1,i[0]=0,i[1]=1;for(var o=t.length,a=1;o>a;a++){var s=t[a],h=4*a,l=a/(o-1);a%2?(e[h]=l,e[h+1]=0,e[h+2]=l,e[h+3]=1):(e[h]=l,e[h+1]=0,e[h+2]=l,e[h+3]=1),h=2*a,r[h]=1,r[h+1]=1,h=2*a,i[h]=h,i[h+1]=h+1,n=s}}},n.Rope.prototype.updateTransform=function(){var t=this.points;if(!(1>t.length)){var e,i=this.verticies,r=t[0],s={x:0,y:0},o=t[0];this.count-=.2,i[0]=o.x+s.x,i[1]=o.y+s.y,i[2]=o.x-s.x,i[3]=o.y-s.y;for(var a=t.length,h=1;a>h;h++){var o=t[h],l=4*h;e=t.length-1>h?t[h+1]:o,s.y=-(e.x-r.x),s.x=e.y-r.y;var u=10*(1-h/(a-1));u>1&&(u=1);var c=Math.sqrt(s.x*s.x+s.y*s.y),p=this.texture.height/2;s.x/=c,s.y/=c,s.x*=p,s.y*=p,i[l]=o.x+s.x,i[l+1]=o.y+s.y,i[l+2]=o.x-s.x,i[l+3]=o.y-s.y,r=o}n.DisplayObjectContainer.prototype.updateTransform.call(this)}},n.Rope.prototype.setTexture=function(t){this.texture=t,this.updateFrame=!0},n.TilingSprite=function(t,e,i){n.DisplayObjectContainer.call(this),this.texture=t,this.width=e,this.height=i,this.tileScale=new n.Point(1,1),this.tilePosition=new n.Point(0,0),this.renderable=!0,this.blendMode=n.blendModes.NORMAL},n.TilingSprite.prototype=Object.create(n.DisplayObjectContainer.prototype),n.TilingSprite.prototype.constructor=n.TilingSprite,n.TilingSprite.prototype.setTexture=function(t){this.texture=t,this.updateFrame=!0},n.TilingSprite.prototype.onTextureUpdate=function(){this.updateFrame=!0},n.Spine=function(t){if(n.DisplayObjectContainer.call(this),this.spineData=n.AnimCache[t],!this.spineData)throw Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: "+t);this.count=0,this.sprites=[],this.skeleton=new u.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new u.AnimationStateData(this.spineData),this.state=new u.AnimationState(this.stateData);for(var e=0;this.skeleton.drawOrder.length>e;e++){var i=this.skeleton.drawOrder[e].data.attachmentName;n.TextureCache[i]||(i+=".png");var r=new n.Sprite(n.Texture.fromFrame(i));r.anchor.x=r.anchor.y=.5,this.addChild(r),this.sprites.push(r)}},n.Spine.prototype=Object.create(n.DisplayObjectContainer.prototype),n.Spine.prototype.constructor=n.Spine,n.Spine.prototype.updateTransform=function(){this.state.update(1/60),this.state.apply(this.skeleton),this.skeleton.updateWorldTransform();for(var t=0;this.skeleton.drawOrder.length>t;t++){var e=this.skeleton.drawOrder[t],i=e.bone.worldX+e.attachment.x*e.bone.m00+e.attachment.y*e.bone.m01+.5*e.attachment.width,r=e.bone.worldY+e.attachment.x*e.bone.m10+e.attachment.y*e.bone.m11+.5*e.attachment.height;if(e.cacheName!=e.attachment.name){var s=e.attachment.name;n.TextureCache[s]||(s+=".png"),this.sprites[t].setTexture(n.TextureCache[s]),e.cacheName=e.attachment.name}i+=-(e.attachment.width*(e.bone.worldScaleX+e.attachment.scaleX-1)>>1),r+=-(e.attachment.height*(e.bone.worldScaleY+e.attachment.scaleY-1)>>1),this.sprites[t].position.x=i,this.sprites[t].position.y=r,this.sprites[t].rotation=-(e.bone.worldRotation+e.attachment.rotation)*(Math.PI/180)}n.DisplayObjectContainer.prototype.updateTransform.call(this)};var u={};u.BoneData=function(t,e){this.name=t,this.parent=e},u.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1},u.SlotData=function(t,e){this.name=t,this.boneData=e},u.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null},u.Bone=function(t,e){this.data=t,this.parent=e,this.setToSetupPose()},u.Bone.yDown=!1,u.Bone.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,m00:0,m01:0,worldX:0,m10:0,m11:0,worldY:0,worldRotation:0,worldScaleX:1,worldScaleY:1,updateWorldTransform:function(t,e){var i=this.parent;null!=i?(this.worldX=this.x*i.m00+this.y*i.m01+i.worldX,this.worldY=this.x*i.m10+this.y*i.m11+i.worldY,this.worldScaleX=i.worldScaleX*this.scaleX,this.worldScaleY=i.worldScaleY*this.scaleY,this.worldRotation=i.worldRotation+this.rotation):(this.worldX=this.x,this.worldY=this.y,this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY,this.worldRotation=this.rotation);var r=this.worldRotation*Math.PI/180,n=Math.cos(r),s=Math.sin(r);this.m00=n*this.worldScaleX,this.m10=s*this.worldScaleX,this.m01=-s*this.worldScaleY,this.m11=n*this.worldScaleY,t&&(this.m00=-this.m00,this.m01=-this.m01),e&&(this.m10=-this.m10,this.m11=-this.m11),u.Bone.yDown&&(this.m10=-this.m10,this.m11=-this.m11)},setToSetupPose:function(){var t=this.data;this.x=t.x,this.y=t.y,this.rotation=t.rotation,this.scaleX=t.scaleX,this.scaleY=t.scaleY}},u.Slot=function(t,e,i){this.data=t,this.skeleton=e,this.bone=i,this.setToSetupPose()},u.Slot.prototype={r:1,g:1,b:1,a:1,_attachmentTime:0,attachment:null,setAttachment:function(t){this.attachment=t,this._attachmentTime=this.skeleton.time},setAttachmentTime:function(t){this._attachmentTime=this.skeleton.time-t},getAttachmentTime:function(){return this.skeleton.time-this._attachmentTime},setToSetupPose:function(){var t=this.data;this.r=t.r,this.g=t.g,this.b=t.b,this.a=t.a;for(var e=this.skeleton.data.slots,i=0,r=e.length;r>i;i++)if(e[i]==t){this.setAttachment(t.attachmentName?this.skeleton.getAttachmentBySlotIndex(i,t.attachmentName):null);break}}},u.Skin=function(t){this.name=t,this.attachments={}},u.Skin.prototype={addAttachment:function(t,e,i){this.attachments[t+":"+e]=i},getAttachment:function(t,e){return this.attachments[t+":"+e]},_attachAll:function(t,e){for(var i in e.attachments){var r=i.indexOf(":"),n=parseInt(i.substring(0,r)),s=i.substring(r+1),o=t.slots[n];if(o.attachment&&o.attachment.name==s){var a=this.getAttachment(n,s);a&&o.setAttachment(a)}}}},u.Animation=function(t,e,i){this.name=t,this.timelines=e,this.duration=i},u.Animation.prototype={apply:function(t,e,i){i&&0!=this.duration&&(e%=this.duration);for(var r=this.timelines,n=0,s=r.length;s>n;n++)r[n].apply(t,e,1)},mix:function(t,e,i,r){i&&0!=this.duration&&(e%=this.duration);for(var n=this.timelines,s=0,o=n.length;o>s;s++)n[s].apply(t,e,r)}},u.binarySearch=function(t,e,i){var r=0,n=Math.floor(t.length/i)-2;if(0==n)return i;for(var s=n>>>1;;){if(e>=t[(s+1)*i]?r=s+1:n=s,r==n)return(r+1)*i;s=r+n>>>1}},u.linearSearch=function(t,e,i){for(var r=0,n=t.length-i;n>=r;r+=i)if(t[r]>e)return r;return-1},u.Curves=function(t){this.curves=[],this.curves.length=6*(t-1)},u.Curves.prototype={setLinear:function(t){this.curves[6*t]=0},setStepped:function(t){this.curves[6*t]=-1},setCurve:function(t,e,i,r,n){var s=.1,o=s*s,a=o*s,h=3*s,l=3*o,u=6*o,c=6*a,p=2*-e+r,d=2*-i+n,f=3*(e-r)+1,v=3*(i-n)+1,m=6*t,g=this.curves;g[m]=e*h+p*l+f*a,g[m+1]=i*h+d*l+v*a,g[m+2]=p*u+f*c,g[m+3]=d*u+v*c,g[m+4]=f*c,g[m+5]=v*c},getCurvePercent:function(t,e){e=0>e?0:e>1?1:e;var i=6*t,r=this.curves,n=r[i];if(!n)return e;if(-1==n)return 0;for(var s=r[i+1],o=r[i+2],a=r[i+3],h=r[i+4],l=r[i+5],u=n,c=s,p=8;;){if(u>=e){var d=u-n,f=c-s;return f+(c-f)*(e-d)/(u-d)}if(0==p)break;p--,n+=o,s+=a,o+=h,a+=l,u+=n,c+=s}return c+(1-c)*(e-u)/(1-u)}},u.RotateTimeline=function(t){this.curves=new u.Curves(t),this.frames=[],this.frames.length=2*t},u.RotateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(t,e,i){t*=2,this.frames[t]=e,this.frames[t+1]=i},apply:function(t,e,i){var r=this.frames;if(!(r[0]>e)){var n=t.bones[this.boneIndex];if(e>=r[r.length-2]){for(var s=n.data.rotation+r[r.length-1]-n.rotation;s>180;)s-=360;for(;-180>s;)s+=360;return n.rotation+=s*i,void 0}var o=u.binarySearch(r,e,2),a=r[o-1],h=r[o],l=1-(e-h)/(r[o-2]-h);l=this.curves.getCurvePercent(o/2-1,l);for(var s=r[o+1]-a;s>180;)s-=360;for(;-180>s;)s+=360;for(s=n.data.rotation+(a+s*l)-n.rotation;s>180;)s-=360;for(;-180>s;)s+=360;n.rotation+=s*i}}},u.TranslateTimeline=function(t){this.curves=new u.Curves(t),this.frames=[],this.frames.length=3*t},u.TranslateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(t,e,i,r){t*=3,this.frames[t]=e,this.frames[t+1]=i,this.frames[t+2]=r},apply:function(t,e,i){var r=this.frames;if(!(r[0]>e)){var n=t.bones[this.boneIndex];if(e>=r[r.length-3])return n.x+=(n.data.x+r[r.length-2]-n.x)*i,n.y+=(n.data.y+r[r.length-1]-n.y)*i,void 0;var s=u.binarySearch(r,e,3),o=r[s-2],a=r[s-1],h=r[s],l=1-(e-h)/(r[s+-3]-h);l=this.curves.getCurvePercent(s/3-1,l),n.x+=(n.data.x+o+(r[s+1]-o)*l-n.x)*i,n.y+=(n.data.y+a+(r[s+2]-a)*l-n.y)*i}}},u.ScaleTimeline=function(t){this.curves=new u.Curves(t),this.frames=[],this.frames.length=3*t},u.ScaleTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(t,e,i,r){t*=3,this.frames[t]=e,this.frames[t+1]=i,this.frames[t+2]=r},apply:function(t,e,i){var r=this.frames;if(!(r[0]>e)){var n=t.bones[this.boneIndex];if(e>=r[r.length-3])return n.scaleX+=(n.data.scaleX-1+r[r.length-2]-n.scaleX)*i,n.scaleY+=(n.data.scaleY-1+r[r.length-1]-n.scaleY)*i,void 0;var s=u.binarySearch(r,e,3),o=r[s-2],a=r[s-1],h=r[s],l=1-(e-h)/(r[s+-3]-h);l=this.curves.getCurvePercent(s/3-1,l),n.scaleX+=(n.data.scaleX-1+o+(r[s+1]-o)*l-n.scaleX)*i,n.scaleY+=(n.data.scaleY-1+a+(r[s+2]-a)*l-n.scaleY)*i}}},u.ColorTimeline=function(t){this.curves=new u.Curves(t),this.frames=[],this.frames.length=5*t},u.ColorTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(t,e){t*=5,this.frames[t]=e,this.frames[t+1]=r,this.frames[t+2]=g,this.frames[t+3]=b,this.frames[t+4]=a},apply:function(t,e,i){var r=this.frames;if(!(r[0]>e)){var n=t.slots[this.slotIndex];if(e>=r[r.length-5]){var s=r.length-1;return n.r=r[s-3],n.g=r[s-2],n.b=r[s-1],n.a=r[s],void 0}var o=u.binarySearch(r,e,5),a=r[o-4],h=r[o-3],l=r[o-2],c=r[o-1],p=r[o],d=1-(e-p)/(r[o-5]-p);d=this.curves.getCurvePercent(o/5-1,d);var f=a+(r[o+1]-a)*d,v=h+(r[o+2]-h)*d,m=l+(r[o+3]-l)*d,g=c+(r[o+4]-c)*d;1>i?(n.r+=(f-n.r)*i,n.g+=(v-n.g)*i,n.b+=(m-n.b)*i,n.a+=(g-n.a)*i):(n.r=f,n.g=v,n.b=m,n.a=g)}}},u.AttachmentTimeline=function(t){this.curves=new u.Curves(t),this.frames=[],this.frames.length=t,this.attachmentNames=[],this.attachmentNames.length=t},u.AttachmentTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(t,e,i){this.frames[t]=e,this.attachmentNames[t]=i},apply:function(t,e){var i=this.frames;if(!(i[0]>e)){var r;r=e>=i[i.length-1]?i.length-1:u.binarySearch(i,e,1)-1;var n=this.attachmentNames[r];t.slots[this.slotIndex].setAttachment(n?t.getAttachmentBySlotIndex(this.slotIndex,n):null)}}},u.SkeletonData=function(){this.bones=[],this.slots=[],this.skins=[],this.animations=[]},u.SkeletonData.prototype={defaultSkin:null,findBone:function(t){for(var e=this.bones,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null},findBoneIndex:function(t){for(var e=this.bones,i=0,r=e.length;r>i;i++)if(e[i].name==t)return i;return-1},findSlot:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].name==t)return slot[i];return null},findSlotIndex:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].name==t)return i;return-1},findSkin:function(t){for(var e=this.skins,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null},findAnimation:function(t){for(var e=this.animations,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null}},u.Skeleton=function(t){this.data=t,this.bones=[];for(var e=0,i=t.bones.length;i>e;e++){var r=t.bones[e],n=r.parent?this.bones[t.bones.indexOf(r.parent)]:null;this.bones.push(new u.Bone(r,n))}this.slots=[],this.drawOrder=[];for(var e=0,i=t.slots.length;i>e;e++){var s=t.slots[e],o=this.bones[t.bones.indexOf(s.boneData)],a=new u.Slot(s,this,o);this.slots.push(a),this.drawOrder.push(a)}},u.Skeleton.prototype={x:0,y:0,skin:null,r:1,g:1,b:1,a:1,time:0,flipX:!1,flipY:!1,updateWorldTransform:function(){for(var t=this.flipX,e=this.flipY,i=this.bones,r=0,n=i.length;n>r;r++)i[r].updateWorldTransform(t,e)},setToSetupPose:function(){this.setBonesToSetupPose(),this.setSlotsToSetupPose()},setBonesToSetupPose:function(){for(var t=this.bones,e=0,i=t.length;i>e;e++)t[e].setToSetupPose()},setSlotsToSetupPose:function(){for(var t=this.slots,e=0,i=t.length;i>e;e++)t[e].setToSetupPose(e)},getRootBone:function(){return 0==this.bones.length?null:this.bones[0]},findBone:function(t){for(var e=this.bones,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return e[i];return null},findBoneIndex:function(t){for(var e=this.bones,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return i;return-1},findSlot:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return e[i];return null},findSlotIndex:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return i;return-1},setSkinByName:function(t){var e=this.data.findSkin(t);if(!e)throw"Skin not found: "+t;this.setSkin(e)},setSkin:function(t){this.skin&&t&&t._attachAll(this,this.skin),this.skin=t},getAttachmentBySlotName:function(t,e){return this.getAttachmentBySlotIndex(this.data.findSlotIndex(t),e)},getAttachmentBySlotIndex:function(t,e){if(this.skin){var i=this.skin.getAttachment(t,e);if(i)return i}return this.data.defaultSkin?this.data.defaultSkin.getAttachment(t,e):null},setAttachment:function(t,e){for(var i=this.slots,r=0,n=i.size;n>r;r++){var s=i[r];if(s.data.name==t){var o=null;if(e&&(o=this.getAttachment(r,e),null==o))throw"Attachment not found: "+e+", for slot: "+t;return s.setAttachment(o),void 0}}throw"Slot not found: "+t},update:function(t){time+=t}},u.AttachmentType={region:0},u.RegionAttachment=function(){this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},u.RegionAttachment.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,width:0,height:0,rendererObject:null,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,setUVs:function(t,e,i,r,n){var s=this.uvs;n?(s[2]=t,s[3]=r,s[4]=t,s[5]=e,s[6]=i,s[7]=e,s[0]=i,s[1]=r):(s[0]=t,s[1]=r,s[2]=t,s[3]=e,s[4]=i,s[5]=e,s[6]=i,s[7]=r)},updateOffset:function(){var t=this.width/this.regionOriginalWidth*this.scaleX,e=this.height/this.regionOriginalHeight*this.scaleY,i=-this.width/2*this.scaleX+this.regionOffsetX*t,r=-this.height/2*this.scaleY+this.regionOffsetY*e,n=i+this.regionWidth*t,s=r+this.regionHeight*e,o=this.rotation*Math.PI/180,a=Math.cos(o),h=Math.sin(o),l=i*a+this.x,u=i*h,c=r*a+this.y,p=r*h,d=n*a+this.x,f=n*h,v=s*a+this.y,m=s*h,g=this.offset;g[0]=l-p,g[1]=c+u,g[2]=l-m,g[3]=v+u,g[4]=d-m,g[5]=v+f,g[6]=d-p,g[7]=c+f},computeVertices:function(t,e,i,r){t+=i.worldX,e+=i.worldY;var n=i.m00,s=i.m01,o=i.m10,a=i.m11,h=this.offset;r[0]=h[0]*n+h[1]*s+t,r[1]=h[0]*o+h[1]*a+e,r[2]=h[2]*n+h[3]*s+t,r[3]=h[2]*o+h[3]*a+e,r[4]=h[4]*n+h[5]*s+t,r[5]=h[4]*o+h[5]*a+e,r[6]=h[6]*n+h[7]*s+t,r[7]=h[6]*o+h[7]*a+e}},u.AnimationStateData=function(t){this.skeletonData=t,this.animationToMixTime={}},u.AnimationStateData.prototype={setMixByName:function(t,e,i){var r=this.skeletonData.findAnimation(t);if(!r)throw"Animation not found: "+t;var n=this.skeletonData.findAnimation(e);if(!n)throw"Animation not found: "+e;this.setMix(r,n,i)},setMix:function(t,e,i){this.animationToMixTime[t.name+":"+e.name]=i},getMix:function(t,e){var i=this.animationToMixTime[t.name+":"+e.name];return i?i:0}},u.AnimationState=function(t){this.data=t,this.queue=[]},u.AnimationState.prototype={current:null,previous:null,currentTime:0,previousTime:0,currentLoop:!1,previousLoop:!1,mixTime:0,mixDuration:0,update:function(t){if(this.currentTime+=t,this.previousTime+=t,this.mixTime+=t,this.queue.length>0){var e=this.queue[0];this.currentTime>=e.delay&&(this._setAnimation(e.animation,e.loop),this.queue.shift())}},apply:function(t){if(this.current)if(this.previous){this.previous.apply(t,this.previousTime,this.previousLoop);var e=this.mixTime/this.mixDuration;e>=1&&(e=1,this.previous=null),this.current.mix(t,this.currentTime,this.currentLoop,e)}else this.current.apply(t,this.currentTime,this.currentLoop)},clearAnimation:function(){this.previous=null,this.current=null,this.queue.length=0},_setAnimation:function(t,e){this.previous=null,t&&this.current&&(this.mixDuration=this.data.getMix(this.current,t),this.mixDuration>0&&(this.mixTime=0,this.previous=this.current,this.previousTime=this.currentTime,this.previousLoop=this.currentLoop)),this.current=t,this.currentLoop=e,this.currentTime=0},setAnimationByName:function(t,e){var i=this.data.skeletonData.findAnimation(t);if(!i)throw"Animation not found: "+t;this.setAnimation(i,e)},setAnimation:function(t,e){this.queue.length=0,this._setAnimation(t,e)},addAnimationByName:function(t,e,i){var r=this.data.skeletonData.findAnimation(t);if(!r)throw"Animation not found: "+t;this.addAnimation(r,e,i)},addAnimation:function(t,e,i){var r={};if(r.animation=t,r.loop=e,!i||0>=i){var n=0==this.queue.length?this.current:this.queue[this.queue.length-1].animation;i=null!=n?n.duration-this.data.getMix(n,t)+(i||0):0}r.delay=i,this.queue.push(r)},isComplete:function(){return!this.current||this.currentTime>=this.current.duration}},u.SkeletonJson=function(t){this.attachmentLoader=t},u.SkeletonJson.prototype={scale:1,readSkeletonData:function(t){for(var e=new u.SkeletonData,i=t.bones,r=0,n=i.length;n>r;r++){var s=i[r],o=null;if(s.parent&&(o=e.findBone(s.parent),!o))throw"Parent bone not found: "+s.parent;var a=new u.BoneData(s.name,o);a.length=(s.length||0)*this.scale,a.x=(s.x||0)*this.scale,a.y=(s.y||0)*this.scale,a.rotation=s.rotation||0,a.scaleX=s.scaleX||1,a.scaleY=s.scaleY||1,e.bones.push(a)}for(var h=t.slots,r=0,n=h.length;n>r;r++){var l=h[r],a=e.findBone(l.bone);if(!a)throw"Slot bone not found: "+l.bone;var c=new u.SlotData(l.name,a),p=l.color;p&&(c.r=u.SkeletonJson.toColor(p,0),c.g=u.SkeletonJson.toColor(p,1),c.b=u.SkeletonJson.toColor(p,2),c.a=u.SkeletonJson.toColor(p,3)),c.attachmentName=l.attachment,e.slots.push(c)}var d=t.skins;for(var f in d)if(d.hasOwnProperty(f)){var v=d[f],m=new u.Skin(f);for(var g in v)if(v.hasOwnProperty(g)){var x=e.findSlotIndex(g),b=v[g];for(var y in b)if(b.hasOwnProperty(y)){var T=this.readAttachment(m,y,b[y]);null!=T&&m.addAttachment(x,y,T)}}e.skins.push(m),"default"==m.name&&(e.defaultSkin=m)}var _=t.animations;for(var w in _)_.hasOwnProperty(w)&&this.readAnimation(w,_[w],e);return e},readAttachment:function(t,e,i){e=i.name||e;var r=u.AttachmentType[i.type||"region"],n=new u.RegionAttachment;return n.name=e,r==u.AttachmentType.region&&(n.x=(i.x||0)*this.scale,n.y=(i.y||0)*this.scale,n.scaleX=i.scaleX||1,n.scaleY=i.scaleY||1,n.rotation=i.rotation||0,n.width=(i.width||32)*this.scale,n.height=(i.height||32)*this.scale,n.updateOffset()),n},readAnimation:function(t,e,i){var r=[],n=0,s=e.bones;for(var o in s)if(s.hasOwnProperty(o)){var a=i.findBoneIndex(o);if(-1==a)throw"Bone not found: "+o;var h=s[o];for(var l in h)if(h.hasOwnProperty(l)){var c=h[l];if("rotate"==l){var p=new u.RotateTimeline(c.length);p.boneIndex=a;for(var d=0,f=0,v=c.length;v>f;f++){var m=c[f];p.setFrame(d,m.time,m.angle),u.SkeletonJson.readCurve(p,d,m),d++}r.push(p),n=Math.max(n,p.frames[2*p.getFrameCount()-2])}else{if("translate"!=l&&"scale"!=l)throw"Invalid timeline type for a bone: "+l+" ("+o+")";var p,g=1;"scale"==l?p=new u.ScaleTimeline(c.length):(p=new u.TranslateTimeline(c.length),g=this.scale),p.boneIndex=a;for(var d=0,f=0,v=c.length;v>f;f++){var m=c[f],x=(m.x||0)*g,b=(m.y||0)*g;p.setFrame(d,m.time,x,b),u.SkeletonJson.readCurve(p,d,m),d++}r.push(p),n=Math.max(n,p.frames[3*p.getFrameCount()-3])}}}var y=e.slots;for(var T in y)if(y.hasOwnProperty(T)){var _=y[T],w=i.findSlotIndex(T);for(var l in _)if(_.hasOwnProperty(l)){var c=_[l];if("color"==l){var p=new u.ColorTimeline(c.length);p.slotIndex=w;for(var d=0,f=0,v=c.length;v>f;f++){var m=c[f],A=m.color,R=u.SkeletonJson.toColor(A,0),S=u.SkeletonJson.toColor(A,1),C=u.SkeletonJson.toColor(A,2),L=u.SkeletonJson.toColor(A,3);p.setFrame(d,m.time,R,S,C,L),u.SkeletonJson.readCurve(p,d,m),d++}r.push(p),n=Math.max(n,p.frames[5*p.getFrameCount()-5])}else{if("attachment"!=l)throw"Invalid timeline type for a slot: "+l+" ("+T+")";var p=new u.AttachmentTimeline(c.length);p.slotIndex=w;for(var d=0,f=0,v=c.length;v>f;f++){var m=c[f];p.setFrame(d++,m.time,m.name)}r.push(p),n=Math.max(n,p.frames[Math.floor(p.getFrameCount())-1])}}}i.animations.push(new u.Animation(t,r,n))}},u.SkeletonJson.readCurve=function(t,e,i){var r=i.curve;r&&("stepped"==r?t.curves.setStepped(e):r instanceof Array&&t.curves.setCurve(e,r[0],r[1],r[2],r[3]))},u.SkeletonJson.toColor=function(t,e){if(8!=t.length)throw"Color hexidecimal length must be 8, recieved: "+t;return parseInt(t.substring(2*e,2),16)/255},u.Atlas=function(t,e){this.textureLoader=e,this.pages=[],this.regions=[];var i=new u.AtlasReader(t),r=[];r.length=4;for(var n=null;;){var s=i.readLine();if(null==s)break;if(s=i.trim(s),0==s.length)n=null;else if(n){var o=new u.AtlasRegion;o.name=s,o.page=n,o.rotate="true"==i.readValue(),i.readTuple(r);var a=parseInt(r[0]),h=parseInt(r[1]);i.readTuple(r);var l=parseInt(r[0]),c=parseInt(r[1]);o.u=a/n.width,o.v=h/n.height,o.rotate?(o.u2=(a+c)/n.width,o.v2=(h+l)/n.height):(o.u2=(a+l)/n.width,o.v2=(h+c)/n.height),o.x=a,o.y=h,o.width=Math.abs(l),o.height=Math.abs(c),4==i.readTuple(r)&&(o.splits=[parseInt(r[0]),parseInt(r[1]),parseInt(r[2]),parseInt(r[3])],4==i.readTuple(r)&&(o.pads=[parseInt(r[0]),parseInt(r[1]),parseInt(r[2]),parseInt(r[3])],i.readTuple(r))),o.originalWidth=parseInt(r[0]),o.originalHeight=parseInt(r[1]),i.readTuple(r),o.offsetX=parseInt(r[0]),o.offsetY=parseInt(r[1]),o.index=parseInt(i.readValue()),this.regions.push(o)}else{n=new u.AtlasPage,n.name=s,n.format=u.Atlas.Format[i.readValue()],i.readTuple(r),n.minFilter=u.Atlas.TextureFilter[r[0]],n.magFilter=u.Atlas.TextureFilter[r[1]];var p=i.readValue();n.uWrap=u.Atlas.TextureWrap.clampToEdge,n.vWrap=u.Atlas.TextureWrap.clampToEdge,"x"==p?n.uWrap=u.Atlas.TextureWrap.repeat:"y"==p?n.vWrap=u.Atlas.TextureWrap.repeat:"xy"==p&&(n.uWrap=n.vWrap=u.Atlas.TextureWrap.repeat),e.load(n,s),this.pages.push(n)}}},u.Atlas.prototype={findRegion:function(t){for(var e=this.regions,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null},dispose:function(){for(var t=this.pages,e=0,i=t.length;i>e;e++)this.textureLoader.unload(t[e].rendererObject)},updateUVs:function(t){for(var e=this.regions,i=0,r=e.length;r>i;i++){var n=e[i];n.page==t&&(n.u=n.x/t.width,n.v=n.y/t.height,n.rotate?(n.u2=(n.x+n.height)/t.width,n.v2=(n.y+n.width)/t.height):(n.u2=(n.x+n.width)/t.width,n.v2=(n.y+n.height)/t.height))}}},u.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},u.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},u.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},u.AtlasPage=function(){},u.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},u.AtlasRegion=function(){},u.AtlasRegion.prototype={page:null,name:null,x:0,y:0,width:0,height:0,u:0,v:0,u2:0,v2:0,offsetX:0,offsetY:0,originalWidth:0,originalHeight:0,index:0,rotate:!1,splits:null,pads:null},u.AtlasReader=function(t){this.lines=t.split(/\r\n|\r|\n/)},u.AtlasReader.prototype={index:0,trim:function(t){return t.replace(/^\s+|\s+$/g,"")},readLine:function(){return this.index>=this.lines.length?null:this.lines[this.index++]},readValue:function(){var t=this.readLine(),e=t.indexOf(":");if(-1==e)throw"Invalid line: "+t;return this.trim(t.substring(e+1))},readTuple:function(t){var e=this.readLine(),i=e.indexOf(":");if(-1==i)throw"Invalid line: "+e;for(var r=0,n=i+1;3>r;r++){var s=e.indexOf(",",n);if(-1==s){if(0==r)throw"Invalid line: "+e;break}t[r]=this.trim(e.substr(n,s-n)),n=s+1}return t[r]=this.trim(e.substring(n)),r+1}},u.AtlasAttachmentLoader=function(t){this.atlas=t},u.AtlasAttachmentLoader.prototype={newAttachment:function(t,e,i){switch(e){case u.AttachmentType.region:var r=this.atlas.findRegion(i);if(!r)throw"Region not found in atlas: "+i+" ("+e+")";var n=new u.RegionAttachment(i);return n.rendererObject=r,n.setUVs(r.u,r.v,r.u2,r.v2,r.rotate),n.regionOffsetX=r.offsetX,n.regionOffsetY=r.offsetY,n.regionWidth=r.width,n.regionHeight=r.height,n.regionOriginalWidth=r.originalWidth,n.regionOriginalHeight=r.originalHeight,n}throw"Unknown attachment type: "+e}},n.AnimCache={},u.Bone.yDown=!0,n.CustomRenderable=function(){n.DisplayObject.call(this)},n.CustomRenderable.prototype=Object.create(n.DisplayObject.prototype),n.CustomRenderable.prototype.constructor=n.CustomRenderable,n.CustomRenderable.prototype.renderCanvas=function(){},n.CustomRenderable.prototype.initWebGL=function(){},n.CustomRenderable.prototype.renderWebGL=function(){},n.BaseTextureCache={},n.texturesToUpdate=[],n.texturesToDestroy=[],n.BaseTexture=function(t){if(n.EventTarget.call(this),this.width=100,this.height=100,this.hasLoaded=!1,this.source=t,t){if(this.source instanceof Image||this.source instanceof HTMLImageElement)if(this.source.complete)this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,n.texturesToUpdate.push(this);else{var e=this;this.source.onload=function(){e.hasLoaded=!0,e.width=e.source.width,e.height=e.source.height,n.texturesToUpdate.push(e),e.dispatchEvent({type:"loaded",content:e})}}else this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,n.texturesToUpdate.push(this);this._powerOf2=!1}},n.BaseTexture.prototype.constructor=n.BaseTexture,n.BaseTexture.prototype.destroy=function(){this.source instanceof Image&&(this.source.src=null),this.source=null,n.texturesToDestroy.push(this)},n.BaseTexture.fromImage=function(t,e){var i=n.BaseTextureCache[t];if(!i){var r=new Image;e&&(r.crossOrigin=""),r.src=t,i=new n.BaseTexture(r),n.BaseTextureCache[t]=i}return i},n.TextureCache={},n.FrameCache={},n.Texture=function(t,e){if(n.EventTarget.call(this),e||(this.noFrame=!0,e=new n.Rectangle(0,0,1,1)),t instanceof n.Texture&&(t=t.baseTexture),this.baseTexture=t,this.frame=e,this.trim=new n.Point,this.scope=this,t.hasLoaded)this.noFrame&&(e=new n.Rectangle(0,0,t.width,t.height)),this.setFrame(e);else{var i=this;t.addEventListener("loaded",function(){i.onBaseTextureLoaded()})}},n.Texture.prototype.constructor=n.Texture,n.Texture.prototype.onBaseTextureLoaded=function(){var t=this.baseTexture;t.removeEventListener("loaded",this.onLoaded),this.noFrame&&(this.frame=new n.Rectangle(0,0,t.width,t.height)),this.noFrame=!1,this.width=this.frame.width,this.height=this.frame.height,this.scope.dispatchEvent({type:"update",content:this})},n.Texture.prototype.destroy=function(t){t&&this.baseTexture.destroy()},n.Texture.prototype.setFrame=function(t){if(this.frame=t,this.width=t.width,this.height=t.height,t.x+t.width>this.baseTexture.width||t.y+t.height>this.baseTexture.height)throw Error("Texture Error: frame does not fit inside the base Texture dimensions "+this);this.updateFrame=!0,n.Texture.frameUpdates.push(this)},n.Texture.fromImage=function(t,e){var i=n.TextureCache[t];return i||(i=new n.Texture(n.BaseTexture.fromImage(t,e)),n.TextureCache[t]=i),i},n.Texture.fromFrame=function(t){var e=n.TextureCache[t];if(!e)throw Error("The frameId '"+t+"' does not exist in the texture cache "+this);return e},n.Texture.fromCanvas=function(t){var e=new n.BaseTexture(t);return new n.Texture(e)},n.Texture.addTextureToCache=function(t,e){n.TextureCache[e]=t},n.Texture.removeTextureFromCache=function(t){var e=n.TextureCache[t];return n.TextureCache[t]=null,e},n.Texture.frameUpdates=[],n.RenderTexture=function(t,e){n.EventTarget.call(this),this.width=t||100,this.height=e||100,this.indetityMatrix=n.mat3.create(),this.frame=new n.Rectangle(0,0,this.width,this.height),n.gl?this.initWebGL():this.initCanvas()},n.RenderTexture.prototype=Object.create(n.Texture.prototype),n.RenderTexture.prototype.constructor=n.RenderTexture,n.RenderTexture.prototype.initWebGL=function(){var t=n.gl;this.glFramebuffer=t.createFramebuffer(),t.bindFramebuffer(t.FRAMEBUFFER,this.glFramebuffer),this.glFramebuffer.width=this.width,this.glFramebuffer.height=this.height,this.baseTexture=new n.BaseTexture,this.baseTexture.width=this.width,this.baseTexture.height=this.height,this.baseTexture._glTexture=t.createTexture(),t.bindTexture(t.TEXTURE_2D,this.baseTexture._glTexture),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.width,this.height,0,t.RGBA,t.UNSIGNED_BYTE,null),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),this.baseTexture.isRender=!0,t.bindFramebuffer(t.FRAMEBUFFER,this.glFramebuffer),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,this.baseTexture._glTexture,0),this.projection=new n.Point(this.width/2,this.height/2),this.render=this.renderWebGL},n.RenderTexture.prototype.resize=function(t,e){if(this.width=t,this.height=e,n.gl){this.projection.x=this.width/2,this.projection.y=this.height/2;var i=n.gl;i.bindTexture(i.TEXTURE_2D,this.baseTexture._glTexture),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,this.width,this.height,0,i.RGBA,i.UNSIGNED_BYTE,null)}else this.frame.width=this.width,this.frame.height=this.height,this.renderer.resize(this.width,this.height) -},n.RenderTexture.prototype.initCanvas=function(){this.renderer=new n.CanvasRenderer(this.width,this.height,null,0),this.baseTexture=new n.BaseTexture(this.renderer.view),this.frame=new n.Rectangle(0,0,this.width,this.height),this.render=this.renderCanvas},n.RenderTexture.prototype.renderWebGL=function(t,e,i){var r=n.gl;r.colorMask(!0,!0,!0,!0),r.viewport(0,0,this.width,this.height),r.bindFramebuffer(r.FRAMEBUFFER,this.glFramebuffer),i&&(r.clearColor(0,0,0,0),r.clear(r.COLOR_BUFFER_BIT));var s=t.children;t.worldTransform=n.mat3.create(),t.worldTransform[4]=-1,t.worldTransform[5]=2*this.projection.y,e&&(t.worldTransform[2]=e.x,t.worldTransform[5]-=e.y);for(var o=0,a=s.length;a>o;o++)s[o].updateTransform();var h=t.__renderGroup;h?t==h.root?h.render(this.projection):h.renderSpecific(t,this.projection):(this.renderGroup||(this.renderGroup=new n.WebGLRenderGroup(r)),this.renderGroup.setRenderable(t),this.renderGroup.render(this.projection))},n.RenderTexture.prototype.renderCanvas=function(t,e,i){var r=t.children;t.worldTransform=n.mat3.create(),e&&(t.worldTransform[2]=e.x,t.worldTransform[5]=e.y);for(var s=0,o=r.length;o>s;s++)r[s].updateTransform();i&&this.renderer.context.clearRect(0,0,this.width,this.height),this.renderer.renderDisplayObject(t),this.renderer.context.setTransform(1,0,0,1,0,0)},n.AssetLoader=function(t,e){n.EventTarget.call(this),this.assetURLs=t,this.crossorigin=e,this.loadersByType={jpg:n.ImageLoader,jpeg:n.ImageLoader,png:n.ImageLoader,gif:n.ImageLoader,json:n.JsonLoader,anim:n.SpineLoader,xml:n.BitmapFontLoader,fnt:n.BitmapFontLoader}},n.AssetLoader.prototype.constructor=n.AssetLoader,n.AssetLoader.prototype.load=function(){var t=this;this.loadCount=this.assetURLs.length;for(var e=0;this.assetURLs.length>e;e++){var i=this.assetURLs[e],r=i.split(".").pop().toLowerCase(),n=this.loadersByType[r];if(!n)throw Error(r+" is an unsupported file type");var s=new n(i,this.crossorigin);s.addEventListener("loaded",function(){t.onAssetLoaded()}),s.load()}},n.AssetLoader.prototype.onAssetLoaded=function(){this.loadCount--,this.dispatchEvent({type:"onProgress",content:this}),this.onProgress&&this.onProgress(),0==this.loadCount&&(this.dispatchEvent({type:"onComplete",content:this}),this.onComplete&&this.onComplete())},n.JsonLoader=function(t,e){n.EventTarget.call(this),this.url=t,this.crossorigin=e,this.baseUrl=t.replace(/[^\/]*$/,""),this.loaded=!1},n.JsonLoader.prototype.constructor=n.JsonLoader,n.JsonLoader.prototype.load=function(){this.ajaxRequest=new l;var t=this;this.ajaxRequest.onreadystatechange=function(){t.onJSONLoaded()},this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/json"),this.ajaxRequest.send(null)},n.JsonLoader.prototype.onJSONLoaded=function(){if(4==this.ajaxRequest.readyState)if(200==this.ajaxRequest.status||-1==window.location.href.indexOf("http"))if(this.json=JSON.parse(this.ajaxRequest.responseText),this.json.frames){var t=this,e=this.baseUrl+this.json.meta.image,i=new n.ImageLoader(e,this.crossorigin),r=this.json.frames;this.texture=i.texture.baseTexture,i.addEventListener("loaded",function(){t.onLoaded()});for(var s in r){var o=r[s].frame;o&&(n.TextureCache[s]=new n.Texture(this.texture,{x:o.x,y:o.y,width:o.w,height:o.h}),r[s].trimmed&&(n.TextureCache[s].realSize=r[s].spriteSourceSize,n.TextureCache[s].trim.x=0))}i.load()}else if(this.json.bones){var a=new u.SkeletonJson,h=a.readSkeletonData(this.json);n.AnimCache[this.url]=h,this.onLoaded()}else this.onLoaded();else this.onError()},n.JsonLoader.prototype.onLoaded=function(){this.loaded=!0,this.dispatchEvent({type:"loaded",content:this})},n.JsonLoader.prototype.onError=function(){this.dispatchEvent({type:"error",content:this})},n.SpriteSheetLoader=function(t,e){n.EventTarget.call(this),this.url=t,this.crossorigin=e,this.baseUrl=t.replace(/[^\/]*$/,""),this.texture=null,this.frames={}},n.SpriteSheetLoader.prototype.constructor=n.SpriteSheetLoader,n.SpriteSheetLoader.prototype.load=function(){var t=this,e=new n.JsonLoader(this.url,this.crossorigin);e.addEventListener("loaded",function(e){t.json=e.content.json,t.onJSONLoaded()}),e.load()},n.SpriteSheetLoader.prototype.onJSONLoaded=function(){var t=this,e=this.baseUrl+this.json.meta.image,i=new n.ImageLoader(e,this.crossorigin),r=this.json.frames;this.texture=i.texture.baseTexture,i.addEventListener("loaded",function(){t.onLoaded()});for(var s in r){var o=r[s].frame;o&&(n.TextureCache[s]=new n.Texture(this.texture,{x:o.x,y:o.y,width:o.w,height:o.h}),r[s].trimmed&&(n.TextureCache[s].realSize=r[s].spriteSourceSize,n.TextureCache[s].trim.x=0))}i.load()},n.SpriteSheetLoader.prototype.onLoaded=function(){this.dispatchEvent({type:"loaded",content:this})},n.ImageLoader=function(t,e){n.EventTarget.call(this),this.texture=n.Texture.fromImage(t,e)},n.ImageLoader.prototype.constructor=n.ImageLoader,n.ImageLoader.prototype.load=function(){if(this.texture.baseTexture.hasLoaded)this.onLoaded();else{var t=this;this.texture.baseTexture.addEventListener("loaded",function(){t.onLoaded()})}},n.ImageLoader.prototype.onLoaded=function(){this.dispatchEvent({type:"loaded",content:this})},n.BitmapFontLoader=function(t,e){n.EventTarget.call(this),this.url=t,this.crossorigin=e,this.baseUrl=t.replace(/[^\/]*$/,""),this.texture=null},n.BitmapFontLoader.prototype.constructor=n.BitmapFontLoader,n.BitmapFontLoader.prototype.load=function(){this.ajaxRequest=new XMLHttpRequest;var t=this;this.ajaxRequest.onreadystatechange=function(){t.onXMLLoaded()},this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/xml"),this.ajaxRequest.send(null)},n.BitmapFontLoader.prototype.onXMLLoaded=function(){if(4==this.ajaxRequest.readyState&&(200==this.ajaxRequest.status||-1==window.location.href.indexOf("http"))){var t=this.baseUrl+this.ajaxRequest.responseXML.getElementsByTagName("page")[0].attributes.getNamedItem("file").nodeValue,e=new n.ImageLoader(t,this.crossorigin);this.texture=e.texture.baseTexture;var i={},r=this.ajaxRequest.responseXML.getElementsByTagName("info")[0],s=this.ajaxRequest.responseXML.getElementsByTagName("common")[0];i.font=r.attributes.getNamedItem("face").nodeValue,i.size=parseInt(r.attributes.getNamedItem("size").nodeValue,10),i.lineHeight=parseInt(s.attributes.getNamedItem("lineHeight").nodeValue,10),i.chars={};for(var o=this.ajaxRequest.responseXML.getElementsByTagName("char"),a=0;o.length>a;a++){var h=parseInt(o[a].attributes.getNamedItem("id").nodeValue,10),l={x:parseInt(o[a].attributes.getNamedItem("x").nodeValue,10),y:parseInt(o[a].attributes.getNamedItem("y").nodeValue,10),width:parseInt(o[a].attributes.getNamedItem("width").nodeValue,10),height:parseInt(o[a].attributes.getNamedItem("height").nodeValue,10)};n.TextureCache[h]=new n.Texture(this.texture,l),i.chars[h]={xOffset:parseInt(o[a].attributes.getNamedItem("xoffset").nodeValue,10),yOffset:parseInt(o[a].attributes.getNamedItem("yoffset").nodeValue,10),xAdvance:parseInt(o[a].attributes.getNamedItem("xadvance").nodeValue,10),kerning:{},texture:new n.Texture(this.texture,l)}}var u=this.ajaxRequest.responseXML.getElementsByTagName("kerning");for(a=0;u.length>a;a++){var c=parseInt(u[a].attributes.getNamedItem("first").nodeValue,10),p=parseInt(u[a].attributes.getNamedItem("second").nodeValue,10),d=parseInt(u[a].attributes.getNamedItem("amount").nodeValue,10);i.chars[p].kerning[c]=d}n.BitmapText.fonts[i.font]=i;var f=this;e.addEventListener("loaded",function(){f.onLoaded()}),e.load()}},n.BitmapFontLoader.prototype.onLoaded=function(){this.dispatchEvent({type:"loaded",content:this})},n.SpineLoader=function(t,e){n.EventTarget.call(this),this.url=t,this.crossorigin=e,this.loaded=!1},n.SpineLoader.prototype.constructor=n.SpineLoader,n.SpineLoader.prototype.load=function(){var t=this,e=new n.JsonLoader(this.url,this.crossorigin);e.addEventListener("loaded",function(e){t.json=e.content.json,t.onJSONLoaded()}),e.load()},n.SpineLoader.prototype.onJSONLoaded=function(){var t=new u.SkeletonJson,e=t.readSkeletonData(this.json);n.AnimCache[this.url]=e,this.onLoaded()},n.SpineLoader.prototype.onLoaded=function(){this.loaded=!0,this.dispatchEvent({type:"loaded",content:this})},"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=n),exports.PIXI=n):i.PIXI=n}).call(this); \ No newline at end of file +!function(){function c(){return f.Matrix="undefined"!=typeof Float32Array?Float32Array:Array,f.Matrix}function d(a){return[(255&a>>16)/255,(255&a>>8)/255,(255&a)/255]}function d(a){return[(255&a>>16)/255,(255&a>>8)/255,(255&a)/255]}var e=this,f=f||{};f.Point=function(a,b){this.x=a||0,this.y=b||0},f.Point.prototype.clone=function(){return new f.Point(this.x,this.y)},f.Point.prototype.constructor=f.Point,f.Rectangle=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Rectangle.prototype.clone=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Rectangle.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=this.x;if(a>=c&&a<=c+this.width){var d=this.y;if(b>=d&&b<=d+this.height)return!0}return!1},f.Rectangle.prototype.constructor=f.Rectangle,f.Polygon=function(a){if(a instanceof Array||(a=Array.prototype.slice.call(arguments)),"number"==typeof a[0]){for(var b=[],c=0,d=a.length;d>c;c+=2)b.push(new f.Point(a[c],a[c+1]));a=b}this.points=a},f.Polygon.prototype.clone=function(){for(var a=[],b=0;bb!=i>b&&(h-f)*(b-g)/(i-g)+f>a;j&&(c=!c)}return c},f.Polygon.prototype.constructor=f.Polygon,f.Circle=function(a,b,c){this.x=a||0,this.y=b||0,this.radius=c||0},f.Circle.prototype.clone=function(){return new f.Circle(this.x,this.y,this.radius)},f.Circle.prototype.contains=function(a,b){if(this.radius<=0)return!1;var c=this.x-a,d=this.y-b,e=this.radius*this.radius;return c*=c,d*=d,e>=c+d},f.Circle.prototype.constructor=f.Circle,f.Ellipse=function(a,b,c,d){this.x=a||0,this.y=b||0,this.width=c||0,this.height=d||0},f.Ellipse.prototype.clone=function(){return new f.Ellipse(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.contains=function(a,b){if(this.width<=0||this.height<=0)return!1;var c=(a-this.x)/this.width-.5,d=(b-this.y)/this.height-.5;return c*=c,d*=d,.25>c+d},f.Ellipse.getBounds=function(){return new f.Rectangle(this.x,this.y,this.width,this.height)},f.Ellipse.prototype.constructor=f.Ellipse,c(),f.mat3={},f.mat3.create=function(){var a=new f.Matrix(9);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat3.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.mat4={},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat3.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5],s=b[6],t=b[7],u=b[8];return c[0]=m*d+n*g+o*j,c[1]=m*e+n*h+o*k,c[2]=m*f+n*i+o*l,c[3]=p*d+q*g+r*j,c[4]=p*e+q*h+r*k,c[5]=p*f+q*i+r*l,c[6]=s*d+t*g+u*j,c[7]=s*e+t*h+u*k,c[8]=s*f+t*i+u*l,c},f.mat3.clone=function(a){var b=new f.Matrix(9);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},f.mat3.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[5];return a[1]=a[3],a[2]=a[6],a[3]=c,a[5]=a[7],a[6]=d,a[7]=e,a}return b[0]=a[0],b[1]=a[3],b[2]=a[6],b[3]=a[1],b[4]=a[4],b[5]=a[7],b[6]=a[2],b[7]=a[5],b[8]=a[8],b},f.mat3.toMat4=function(a,b){return b||(b=f.mat4.create()),b[15]=1,b[14]=0,b[13]=0,b[12]=0,b[11]=0,b[10]=a[8],b[9]=a[7],b[8]=a[6],b[7]=0,b[6]=a[5],b[5]=a[4],b[4]=a[3],b[3]=0,b[2]=a[2],b[1]=a[1],b[0]=a[0],b},f.mat4.create=function(){var a=new f.Matrix(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},f.mat4.transpose=function(a,b){if(!b||a===b){var c=a[1],d=a[2],e=a[3],f=a[6],g=a[7],h=a[11];return a[1]=a[4],a[2]=a[8],a[3]=a[12],a[4]=c,a[6]=a[9],a[7]=a[13],a[8]=d,a[9]=f,a[11]=a[14],a[12]=e,a[13]=g,a[14]=h,a}return b[0]=a[0],b[1]=a[4],b[2]=a[8],b[3]=a[12],b[4]=a[1],b[5]=a[5],b[6]=a[9],b[7]=a[13],b[8]=a[2],b[9]=a[6],b[10]=a[10],b[11]=a[14],b[12]=a[3],b[13]=a[7],b[14]=a[11],b[15]=a[15],b},f.mat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=a[9],n=a[10],o=a[11],p=a[12],q=a[13],r=a[14],s=a[15],t=b[0],u=b[1],v=b[2],w=b[3];return c[0]=t*d+u*h+v*l+w*p,c[1]=t*e+u*i+v*m+w*q,c[2]=t*f+u*j+v*n+w*r,c[3]=t*g+u*k+v*o+w*s,t=b[4],u=b[5],v=b[6],w=b[7],c[4]=t*d+u*h+v*l+w*p,c[5]=t*e+u*i+v*m+w*q,c[6]=t*f+u*j+v*n+w*r,c[7]=t*g+u*k+v*o+w*s,t=b[8],u=b[9],v=b[10],w=b[11],c[8]=t*d+u*h+v*l+w*p,c[9]=t*e+u*i+v*m+w*q,c[10]=t*f+u*j+v*n+w*r,c[11]=t*g+u*k+v*o+w*s,t=b[12],u=b[13],v=b[14],w=b[15],c[12]=t*d+u*h+v*l+w*p,c[13]=t*e+u*i+v*m+w*q,c[14]=t*f+u*j+v*n+w*r,c[15]=t*g+u*k+v*o+w*s,c},f.DisplayObject=function(){this.last=this,this.first=this,this.position=new f.Point,this.scale=new f.Point(1,1),this.pivot=new f.Point(0,0),this.rotation=0,this.alpha=1,this.visible=!0,this.hitArea=null,this.buttonMode=!1,this.renderable=!1,this.parent=null,this.stage=null,this.worldAlpha=1,this._interactive=!1,this.worldTransform=f.mat3.create(),this.localTransform=f.mat3.create(),this.color=[],this.dynamic=!0,this._sr=0,this._cr=1},f.DisplayObject.prototype.constructor=f.DisplayObject,f.DisplayObject.prototype.setInteractive=function(a){this.interactive=a},Object.defineProperty(f.DisplayObject.prototype,"interactive",{get:function(){return this._interactive},set:function(a){this._interactive=a,this.stage&&(this.stage.dirty=!0)}}),Object.defineProperty(f.DisplayObject.prototype,"mask",{get:function(){return this._mask},set:function(a){a?this._mask?(a.start=this._mask.start,a.end=this._mask.end):(this.addFilter(a),a.renderable=!1):(this.removeFilter(this._mask),this._mask.renderable=!0),this._mask=a}}),Object.defineProperty(f.DisplayObject.prototype,"filters",{get:function(){return this._filters},set:function(a){a?(this._filters&&this.removeFilter(this._filters),this.addFilter(a)):this._filters&&this.removeFilter(this._filters),this._filters=a}}),f.DisplayObject.prototype.addFilter=function(a){var b=new f.FilterBlock,c=new f.FilterBlock;a.start=b,a.end=c,b.data=a,c.data=a,b.first=b.last=this,c.first=c.last=this,b.open=!0;var d,e,g=b,h=b;e=this.first._iPrev,e?(d=e._iNext,g._iPrev=e,e._iNext=g):d=this,d&&(d._iPrev=h,h._iNext=d);var g=c,h=c,d=null,e=null;e=this.last,d=e._iNext,d&&(d._iPrev=h,h._iNext=d),g._iPrev=e,e._iNext=g;for(var i=this,j=this.last;i;)i.last==j&&(i.last=c),i=i.parent;this.first=b,this.__renderGroup&&this.__renderGroup.addFilterBlocks(b,c)},f.DisplayObject.prototype.removeFilter=function(a){console.log("YUOIO");var b=a.start,c=b._iNext,d=b._iPrev;c&&(c._iPrev=d),d&&(d._iNext=c),this.first=b._iNext;var e=a.end,c=e._iNext,d=e._iPrev;c&&(c._iPrev=d),d._iNext=c;for(var f=e._iPrev,g=this;g.last==e&&(g.last=f,g=g.parent););this.__renderGroup&&this.__renderGroup.removeFilterBlocks(b,e)},f.DisplayObject.prototype.updateTransform=function(){this.rotation!==this.rotationCache&&(this.rotationCache=this.rotation,this._sr=Math.sin(this.rotation),this._cr=Math.cos(this.rotation));var a=this.localTransform,b=this.parent.worldTransform,c=this.worldTransform;a[0]=this._cr*this.scale.x,a[1]=-this._sr*this.scale.y,a[3]=this._sr*this.scale.x,a[4]=this._cr*this.scale.y;var d=this.pivot.x,e=this.pivot.y,g=a[0],h=a[1],i=this.position.x-a[0]*d-e*a[1],j=a[3],k=a[4],l=this.position.y-a[4]*e-d*a[3],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5];a[2]=i,a[5]=l,c[0]=m*g+n*j,c[1]=m*h+n*k,c[2]=m*i+n*l+o,c[3]=p*g+q*j,c[4]=p*h+q*k,c[5]=p*i+q*l+r,this.worldAlpha=this.alpha*this.parent.worldAlpha,this.vcount=f.visibleCount},f.visibleCount=0,f.DisplayObjectContainer=function(){f.DisplayObject.call(this),this.children=[]},f.DisplayObjectContainer.prototype=Object.create(f.DisplayObject.prototype),f.DisplayObjectContainer.prototype.constructor=f.DisplayObjectContainer,f.DisplayObjectContainer.prototype.addChild=function(a){if(void 0!=a.parent&&a.parent.removeChild(a),a.parent=this,this.children.push(a),this.stage){var b=a;do b.interactive&&(this.stage.dirty=!0),b.stage=this.stage,b=b._iNext;while(b)}var c,d,e=a.first,f=a.last;d=this._filters?this.last._iPrev:this.last,c=d._iNext;for(var g=this,h=d;g;)g.last==h&&(g.last=a.last),g=g.parent;c&&(c._iPrev=f,f._iNext=c),e._iPrev=d,d._iNext=e,this.__renderGroup&&(a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a),this.__renderGroup.addDisplayObjectAndChildren(a))},f.DisplayObjectContainer.prototype.addChildAt=function(a,b){if(!(b>=0&&b<=this.children.length))throw new Error(a+" The index "+b+" supplied is out of bounds "+this.children.length);if(void 0!=a.parent&&a.parent.removeChild(a),a.parent=this,this.stage){var c=a;do c.interactive&&(this.stage.dirty=!0),c.stage=this.stage,c=c._iNext;while(c)}var d,e,f=a.first,g=a.last;if(b==this.children.length){e=this.last;for(var h=this,i=this.last;h;)h.last==i&&(h.last=a.last),h=h.parent}else e=0==b?this:this.children[b-1].last;d=e._iNext,d&&(d._iPrev=g,g._iNext=d),f._iPrev=e,e._iNext=f,this.children.splice(b,0,a),this.__renderGroup&&(a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a),this.__renderGroup.addDisplayObjectAndChildren(a))},f.DisplayObjectContainer.prototype.swapChildren=function(){},f.DisplayObjectContainer.prototype.getChildAt=function(a){if(a>=0&&aa;a++)this.children[a].updateTransform()}},f.blendModes={},f.blendModes.NORMAL=0,f.blendModes.SCREEN=1,f.Sprite=function(a){f.DisplayObjectContainer.call(this),this.anchor=new f.Point,this.texture=a,this.blendMode=f.blendModes.NORMAL,this._width=0,this._height=0,a.baseTexture.hasLoaded?this.updateFrame=!0:(this.onTextureUpdateBind=this.onTextureUpdate.bind(this),this.texture.addEventListener("update",this.onTextureUpdateBind)),this.renderable=!0},f.Sprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Sprite.prototype.constructor=f.Sprite,Object.defineProperty(f.Sprite.prototype,"width",{get:function(){return this.scale.x*this.texture.frame.width},set:function(a){this.scale.x=a/this.texture.frame.width,this._width=a}}),Object.defineProperty(f.Sprite.prototype,"height",{get:function(){return this.scale.y*this.texture.frame.height},set:function(a){this.scale.y=a/this.texture.frame.height,this._height=a}}),f.Sprite.prototype.setTexture=function(a){this.texture.baseTexture!=a.baseTexture?(this.textureChange=!0,this.texture=a,this.__renderGroup&&this.__renderGroup.updateTexture(this)):this.texture=a,this.updateFrame=!0},f.Sprite.prototype.onTextureUpdate=function(){this._width&&(this.scale.x=this._width/this.texture.frame.width),this._height&&(this.scale.y=this._height/this.texture.frame.height),this.updateFrame=!0},f.Sprite.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache"+this);return new f.Sprite(b)},f.Sprite.fromImage=function(a){var b=f.Texture.fromImage(a);return new f.Sprite(b)},f.MovieClip=function(a){f.Sprite.call(this,a[0]),this.textures=a,this.animationSpeed=1,this.loop=!0,this.onComplete=null,this.currentFrame=0,this.playing=!1},f.MovieClip.prototype=Object.create(f.Sprite.prototype),f.MovieClip.prototype.constructor=f.MovieClip,Object.defineProperty(f.MovieClip.prototype,"totalFrames",{get:function(){return this.textures.length}}),f.MovieClip.prototype.stop=function(){this.playing=!1},f.MovieClip.prototype.play=function(){this.playing=!0},f.MovieClip.prototype.gotoAndStop=function(a){this.playing=!1,this.currentFrame=a;var b=0|this.currentFrame+.5;this.setTexture(this.textures[b%this.textures.length])},f.MovieClip.prototype.gotoAndPlay=function(a){this.currentFrame=a,this.playing=!0},f.MovieClip.prototype.updateTransform=function(){if(f.Sprite.prototype.updateTransform.call(this),this.playing){this.currentFrame+=this.animationSpeed;var a=0|this.currentFrame+.5;this.loop||a=this.textures.length&&(this.gotoAndStop(this.textures.length-1),this.onComplete&&this.onComplete())}},f.FilterBlock=function(){this.visible=!0,this.renderable=!0},f.ColorMatrixFilter=function(){this.uniforms={matrix:{type:"mat4",value:[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform float invert;","uniform mat4 matrix;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;","gl_FragColor = gl_FragColor * vColor;","}"]},Object.defineProperty(f.ColorMatrixFilter.prototype,"matrix",{get:function(){return this.uniforms.matrix.value},set:function(a){this.uniforms.matrix.value=a}}),f.Text=function(a,b){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),f.Sprite.call(this,f.Texture.fromCanvas(this.canvas)),this.setText(a),this.setStyle(b),this.updateText(),this.dirty=!1},f.Text.prototype=Object.create(f.Sprite.prototype),f.Text.prototype.constructor=f.Text,f.Text.prototype.setStyle=function(a){a=a||{},a.font=a.font||"bold 20pt Arial",a.fill=a.fill||"black",a.align=a.align||"left",a.stroke=a.stroke||"black",a.strokeThickness=a.strokeThickness||0,a.wordWrap=a.wordWrap||!1,a.wordWrapWidth=a.wordWrapWidth||100,this.style=a,this.dirty=!0},f.Text.prototype.setText=function(a){this.text=a.toString()||" ",this.dirty=!0},f.Text.prototype.updateText=function(){this.context.font=this.style.font;var a=this.text;this.style.wordWrap&&(a=this.wordWrap(this.text));for(var b=a.split(/(?:\r\n|\r|\n)/),c=[],d=0,e=0;ee?f:arguments.callee(a,b,f,d,e):arguments.callee(a,b,c,f,e)},c=function(a,c,d){if(a.measureText(c).width<=d||c.length<1)return c;var e=b(a,c,0,c.length,d);return c.substring(0,e)+"\n"+arguments.callee(a,c.substring(e),d)},d="",e=a.split("\n"),f=0;f=2?parseInt(b[b.length-2],10):f.BitmapText.fonts[this.fontName].size,this.dirty=!0},f.BitmapText.prototype.updateText=function(){for(var a=f.BitmapText.fonts[this.fontName],b=new f.Point,c=null,d=[],e=0,g=[],h=0,i=this.fontSize/a.size,j=0;j=j;j++){var n=0;"right"==this.style.align?n=e-g[j]:"center"==this.style.align&&(n=(e-g[j])/2),m.push(n)}for(j=0;j0;)this.removeChild(this.getChildAt(0));this.updateText(),this.dirty=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.BitmapText.fonts={},f.InteractionManager=function(a){this.stage=a,this.mouse=new f.InteractionData,this.touchs={},this.tempPoint=new f.Point,this.mouseoverEnabled=!0,this.pool=[],this.interactiveItems=[],this.interactionDOMElement=null,this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseOut=this.onMouseOut.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onTouchStart=this.onTouchStart.bind(this),this.onTouchEnd=this.onTouchEnd.bind(this),this.onTouchMove=this.onTouchMove.bind(this),this.last=0},f.InteractionManager.prototype.constructor=f.InteractionManager,f.InteractionManager.prototype.collectInteractiveSprite=function(a,b){for(var c=a.children,d=c.length,e=d-1;e>=0;e--){var f=c[e];f.interactive?(b.interactiveChildren=!0,this.interactiveItems.push(f),f.children.length>0&&this.collectInteractiveSprite(f,f)):(f.__iParent=null,f.children.length>0&&this.collectInteractiveSprite(f,b))}},f.InteractionManager.prototype.setTarget=function(a){this.target=a,null===this.interactionDOMElement&&this.setTargetDomElement(a.view),document.body.addEventListener("mouseup",this.onMouseUp,!0)},f.InteractionManager.prototype.setTargetDomElement=function(a){null!==this.interactionDOMElement&&(this.interactionDOMElement.style["-ms-content-zooming"]="",this.interactionDOMElement.style["-ms-touch-action"]="",this.interactionDOMElement.removeEventListener("mousemove",this.onMouseMove,!0),this.interactionDOMElement.removeEventListener("mousedown",this.onMouseDown,!0),this.interactionDOMElement.removeEventListener("mouseout",this.onMouseOut,!0),this.interactionDOMElement.removeEventListener("touchstart",this.onTouchStart,!0),this.interactionDOMElement.removeEventListener("touchend",this.onTouchEnd,!0),this.interactionDOMElement.removeEventListener("touchmove",this.onTouchMove,!0)),window.navigator.msPointerEnabled&&(a.style["-ms-content-zooming"]="none",a.style["-ms-touch-action"]="none"),this.interactionDOMElement=a,a.addEventListener("mousemove",this.onMouseMove,!0),a.addEventListener("mousedown",this.onMouseDown,!0),a.addEventListener("mouseout",this.onMouseOut,!0),a.addEventListener("touchstart",this.onTouchStart,!0),a.addEventListener("touchend",this.onTouchEnd,!0),a.addEventListener("touchmove",this.onTouchMove,!0)},f.InteractionManager.prototype.update=function(){if(this.target){var a=Date.now(),b=a-this.last;if(b=30*b/1e3,!(1>b)){if(this.last=a,this.dirty){this.dirty=!1;for(var c=this.interactiveItems.length,d=0;c>d;d++)this.interactiveItems[d].interactiveChildren=!1;this.interactiveItems=[],this.stage.interactive&&this.interactiveItems.push(this.stage),this.collectInteractiveSprite(this.stage,this.stage)}var e=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var d=0;e>d;d++){var f=this.interactiveItems[d];(f.mouseover||f.mouseout||f.buttonMode)&&(f.__hit=this.hitTest(f,this.mouse),this.mouse.target=f,f.__hit?(f.buttonMode&&(this.interactionDOMElement.style.cursor="pointer"),f.__isOver||(f.mouseover&&f.mouseover(this.mouse),f.__isOver=!0)):f.__isOver&&(f.mouseout&&f.mouseout(this.mouse),f.__isOver=!1))}}}},f.InteractionManager.prototype.onMouseMove=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactionDOMElement.getBoundingClientRect();this.mouse.global.x=(a.clientX-b.left)*(this.target.width/b.width),this.mouse.global.y=(a.clientY-b.top)*(this.target.height/b.height);var c=this.interactiveItems.length;this.mouse.global;for(var d=0;c>d;d++){var e=this.interactiveItems[d];e.mousemove&&e.mousemove(this.mouse)}},f.InteractionManager.prototype.onMouseDown=function(a){this.mouse.originalEvent=a||window.event;var b=this.interactiveItems.length;this.mouse.global,this.stage;for(var c=0;b>c;c++){var d=this.interactiveItems[c];if((d.mousedown||d.click)&&(d.__mouseIsDown=!0,d.__hit=this.hitTest(d,this.mouse),d.__hit&&(d.mousedown&&d.mousedown(this.mouse),d.__isDown=!0,!d.interactiveChildren)))break}},f.InteractionManager.prototype.onMouseOut=function(){var a=this.interactiveItems.length;this.interactionDOMElement.style.cursor="default";for(var b=0;a>b;b++){var c=this.interactiveItems[b];c.__isOver&&(this.mouse.target=c,c.mouseout&&c.mouseout(this.mouse),c.__isOver=!1)}},f.InteractionManager.prototype.onMouseUp=function(a){this.mouse.originalEvent=a||window.event,this.mouse.global;for(var b=this.interactiveItems.length,c=!1,d=0;b>d;d++){var e=this.interactiveItems[d];(e.mouseup||e.mouseupoutside||e.click)&&(e.__hit=this.hitTest(e,this.mouse),e.__hit&&!c?(e.mouseup&&e.mouseup(this.mouse),e.__isDown&&e.click&&e.click(this.mouse),e.interactiveChildren||(c=!0)):e.__isDown&&e.mouseupoutside&&e.mouseupoutside(this.mouse),e.__isDown=!1)}},f.InteractionManager.prototype.hitTest=function(a,b){var c=b.global;if(a.vcount!==f.visibleCount)return!1;var d=a instanceof f.Sprite,e=a.worldTransform,g=e[0],h=e[1],i=e[2],j=e[3],k=e[4],l=e[5],m=1/(g*k+h*-j),n=k*m*c.x+-h*m*c.y+(l*h-i*k)*m,o=g*m*c.y+-j*m*c.x+(-l*g+i*j)*m;if(b.target=a,a.hitArea&&a.hitArea.contains)return a.hitArea.contains(n,o)?(b.target=a,!0):!1;if(d){var p,q=a.texture.frame.width,r=a.texture.frame.height,s=-q*a.anchor.x;if(n>s&&s+q>n&&(p=-r*a.anchor.y,o>p&&p+r>o))return b.target=a,!0}for(var t=a.children.length,u=0;t>u;u++){var v=a.children[u],w=this.hitTest(v,b);if(w)return b.target=a,!0}return!1},f.InteractionManager.prototype.onTouchMove=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;dd;d++){var h=this.interactiveItems[d];h.touchmove&&h.touchmove(f)}},f.InteractionManager.prototype.onTouchStart=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i];if((j.touchstart||j.tap)&&(j.__hit=this.hitTest(j,g),j.__hit&&(j.touchstart&&j.touchstart(g),j.__isDown=!0,j.__touchData=g,!j.interactiveChildren)))break}}},f.InteractionManager.prototype.onTouchEnd=function(a){for(var b=this.interactionDOMElement.getBoundingClientRect(),c=a.changedTouches,d=0;di;i++){var j=this.interactiveItems[i],k=j.__touchData;j.__hit=this.hitTest(j,f),k==f&&(f.originalEvent=a||window.event,(j.touchend||j.tap)&&(j.__hit&&!g?(j.touchend&&j.touchend(f),j.__isDown&&j.tap&&j.tap(f),j.interactiveChildren||(g=!0)):j.__isDown&&j.touchendoutside&&j.touchendoutside(f),j.__isDown=!1),j.__touchData=null)}this.pool.push(f),this.touchs[e.identifier]=null}},f.InteractionData=function(){this.global=new f.Point,this.local=new f.Point,this.target,this.originalEvent},f.InteractionData.prototype.getLocalPosition=function(a){var b=a.worldTransform,c=this.global,d=b[0],e=b[1],g=b[2],h=b[3],i=b[4],j=b[5],k=1/(d*i+e*-h);return new f.Point(i*k*c.x+-e*k*c.y+(j*e-g*i)*k,d*k*c.y+-h*k*c.x+(-j*d+g*h)*k)},f.InteractionData.prototype.constructor=f.InteractionData,f.Stage=function(a){f.DisplayObjectContainer.call(this),this.worldTransform=f.mat3.create(),this.interactive=!0,this.interactionManager=new f.InteractionManager(this),this.dirty=!0,this.__childrenAdded=[],this.__childrenRemoved=[],this.stage=this,this.stage.hitArea=new f.Rectangle(0,0,1e5,1e5),this.setBackgroundColor(a),this.worldVisible=!0},f.Stage.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Stage.prototype.constructor=f.Stage,f.Stage.prototype.setInteractionDelegate=function(a){this.interactionManager.setTargetDomElement(a)},f.Stage.prototype.updateTransform=function(){this.worldAlpha=1,this.vcount=f.visibleCount;for(var a=0,b=this.children.length;b>a;a++)this.children[a].updateTransform();this.dirty&&(this.dirty=!1,this.interactionManager.dirty=!0),this.interactive&&this.interactionManager.update()},f.Stage.prototype.setBackgroundColor=function(a){this.backgroundColor=a||0,this.backgroundColorSplit=d(this.backgroundColor);var b=this.backgroundColor.toString(16);b="000000".substr(0,6-b.length)+b,this.backgroundColorString="#"+b},f.Stage.prototype.getMousePosition=function(){return this.interactionManager.mouse.global};for(var h=0,i=["ms","moz","webkit","o"],j=0;j>>>>>>>>"),console.log("_");var b=0,c=a.first;for(console.log(c);c._iNext;)if(b++,c=c._iNext,console.log(c),b>100){console.log("BREAK");break}},f.EventTarget=function(){var a={};this.addEventListener=this.on=function(b,c){void 0===a[b]&&(a[b]=[]),-1===a[b].indexOf(c)&&a[b].push(c)},this.dispatchEvent=this.emit=function(b){if(a[b.type]&&a[b.type].length)for(var c=0,d=a[b.type].length;d>c;c++)a[b.type][c](b)},this.removeEventListener=this.off=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)}},f.autoDetectRenderer=function(a,b,c,d,e){a||(a=800),b||(b=600);var g=function(){try{return!!window.WebGLRenderingContext&&!!document.createElement("canvas").getContext("experimental-webgl")}catch(a){return!1}}();return g?new f.WebGLRenderer(a,b,c,d,e):new f.CanvasRenderer(a,b,c,d)},f.PolyK={},f.PolyK.Triangulate=function(a){var b=!0,c=a.length>>1;if(3>c)return[];for(var d=[],e=[],g=0;c>g;g++)e.push(g);for(var g=0,h=c;h>3;){var i=e[(g+0)%h],j=e[(g+1)%h],k=e[(g+2)%h],l=a[2*i],m=a[2*i+1],n=a[2*j],o=a[2*j+1],p=a[2*k],q=a[2*k+1],r=!1;if(f.PolyK._convex(l,m,n,o,p,q,b)){r=!0;for(var s=0;h>s;s++){var t=e[s];if(t!=i&&t!=j&&t!=k&&f.PolyK._PointInTriangle(a[2*t],a[2*t+1],l,m,n,o,p,q)){r=!1;break}}}if(r)d.push(i,j,k),e.splice((g+1)%h,1),h--,g=0;else if(g++>3*h){if(!b)return console.log("PIXI Warning: shape too complex to fill"),[];var d=[];e=[];for(var g=0;c>g;g++)e.push(g);g=0,h=c,b=!1}}return d.push(e[0],e[1],e[2]),d},f.PolyK._PointInTriangle=function(a,b,c,d,e,f,g,h){var i=g-c,j=h-d,k=e-c,l=f-d,m=a-c,n=b-d,o=i*i+j*j,p=i*k+j*l,q=i*m+j*n,r=k*k+l*l,s=k*m+l*n,t=1/(o*r-p*p),u=(r*q-p*s)*t,v=(o*s-p*q)*t;return u>=0&&v>=0&&1>u+v},f.PolyK._convex=function(a,b,c,d,e,f,g){return(b-d)*(e-c)+(c-a)*(f-d)>=0==g},f.shaderFragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * vColor;","}"],f.shaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying float vColor;","void main(void) {","gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.stripShaderFragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform float alpha;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));","gl_FragColor = gl_FragColor * alpha;","}"],f.stripShaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","attribute float aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","varying vec2 vTextureCoord;","varying float vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vTextureCoord = aTextureCoord;","vColor = aColor;","}"],f.primitiveShaderFragmentSrc=["precision mediump float;","varying vec4 vColor;","void main(void) {","gl_FragColor = vColor;","}"],f.primitiveShaderVertexSrc=["attribute vec2 aVertexPosition;","attribute vec4 aColor;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform float alpha;","varying vec4 vColor;","void main(void) {","vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);","gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);","vColor = aColor * alpha;","}"],f.shaderStack=[],f.initPrimitiveShader=function(){var a=f.gl,b=f.compileProgram(f.primitiveShaderVertexSrc,f.primitiveShaderFragmentSrc); +a.useProgram(b),b.vertexPositionAttribute=a.getAttribLocation(b,"aVertexPosition"),b.colorAttribute=a.getAttribLocation(b,"aColor"),b.projectionVector=a.getUniformLocation(b,"projectionVector"),b.translationMatrix=a.getUniformLocation(b,"translationMatrix"),b.alpha=a.getUniformLocation(b,"alpha"),f.primitiveProgram=b},f.initDefaultShader=function(){f.defaultShader=new f.PixiShader,f.defaultShader.init(),f.activateShader(f.defaultShader)},f.initDefaultStripShader=function(){var a=this.gl,b=f.compileProgram(f.stripShaderVertexSrc,f.stripShaderFragmentSrc);a.useProgram(b),b.vertexPositionAttribute=a.getAttribLocation(b,"aVertexPosition"),b.projectionVector=a.getUniformLocation(b,"projectionVector"),b.textureCoordAttribute=a.getAttribLocation(b,"aTextureCoord"),b.translationMatrix=a.getUniformLocation(b,"translationMatrix"),b.alpha=a.getUniformLocation(b,"alpha"),b.colorAttribute=a.getAttribLocation(b,"aColor"),b.projectionVector=a.getUniformLocation(b,"projectionVector"),b.samplerUniform=a.getUniformLocation(b,"uSampler"),f.stripShaderProgram=b},f.CompileVertexShader=function(a,b){return f._CompileShader(a,b,a.VERTEX_SHADER)},f.CompileFragmentShader=function(a,b){return f._CompileShader(a,b,a.FRAGMENT_SHADER)},f._CompileShader=function(a,b,c){var d=b.join("\n"),e=a.createShader(c);return a.shaderSource(e,d),a.compileShader(e),a.getShaderParameter(e,a.COMPILE_STATUS)?e:(alert(a.getShaderInfoLog(e)),null)},f.compileProgram=function(a,b){var c=f.gl,d=f.CompileFragmentShader(c,b),e=f.CompileVertexShader(c,a),g=c.createProgram();return c.attachShader(g,e),c.attachShader(g,d),c.linkProgram(g),c.getProgramParameter(g,c.LINK_STATUS)||alert("Could not initialise shaders"),g},f.activateShader=function(a){f.shaderStack.push(a);var b=f.gl,c=a.program;b.useProgram(c),b.enableVertexAttribArray(c.vertexPositionAttribute),b.enableVertexAttribArray(c.colorAttribute),b.enableVertexAttribArray(c.textureCoordAttribute),a.syncUniforms(),f.currentShader=c},f.popShader=function(){var a=f.gl;f.shaderStack.pop();var b=f.shaderStack[f.shaderStack.length-1].program;a.useProgram(b),f.currentShader=b},f.activatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.primitiveProgram),a.disableVertexAttribArray(f.currentShader.textureCoordAttribute)},f.deactivatePrimitiveShader=function(){var a=f.gl;a.useProgram(f.currentShader),a.enableVertexAttribArray(f.currentShader.textureCoordAttribute)},f.PixiShader=function(){this.program,this.fragmentSrc=["precision lowp float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D uSampler;","void main(void) {","gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;","}"]},f.PixiShader.prototype.init=function(){var a=f.compileProgram(this.vertexSrc||f.shaderVertexSrc,this.fragmentSrc),b=f.gl;b.useProgram(a),a.vertexPositionAttribute=b.getAttribLocation(a,"aVertexPosition"),a.colorAttribute=b.getAttribLocation(a,"aColor"),a.textureCoordAttribute=b.getAttribLocation(a,"aTextureCoord"),a.projectionVector=b.getUniformLocation(a,"projectionVector"),a.samplerUniform=b.getUniformLocation(a,"uSampler");for(var c in this.uniforms)a[c]=b.getUniformLocation(a,c);this.program=a},f.PixiShader.prototype.syncUniforms=function(){var a=f.gl;for(var b in this.uniforms){var c=this.uniforms[b].type;"f"==c?a.uniform1f(this.program[b],this.uniforms[b].value):"mat4"==c&&a.uniformMatrix4fv(this.program[b],!1,this.uniforms[b].value)}},f.WebGLGraphics=function(){},f.WebGLGraphics.renderGraphics=function(a,b){var c=f.gl;a._webGL||(a._webGL={points:[],indices:[],lastIndex:0,buffer:c.createBuffer(),indexBuffer:c.createBuffer()}),a.dirty&&(a.dirty=!1,a.clearDirty&&(a.clearDirty=!1,a._webGL.lastIndex=0,a._webGL.points=[],a._webGL.indices=[]),f.WebGLGraphics.updateGraphics(a)),f.activatePrimitiveShader();var d=f.mat3.clone(a.worldTransform);f.mat3.transpose(d),c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA),c.uniformMatrix3fv(f.primitiveProgram.translationMatrix,!1,d),c.uniform2f(f.primitiveProgram.projectionVector,b.x,b.y),c.uniform1f(f.primitiveProgram.alpha,a.worldAlpha),c.bindBuffer(c.ARRAY_BUFFER,a._webGL.buffer),c.vertexAttribPointer(f.primitiveProgram.vertexPositionAttribute,2,c.FLOAT,!1,24,0),c.vertexAttribPointer(f.primitiveProgram.colorAttribute,4,c.FLOAT,!1,24,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),c.drawElements(c.TRIANGLE_STRIP,a._webGL.indices.length,c.UNSIGNED_SHORT,0),f.deactivatePrimitiveShader()},f.WebGLGraphics.updateGraphics=function(a){for(var b=a._webGL.lastIndex;b3&&f.WebGLGraphics.buildPoly(c,a._webGL),c.lineWidth>0&&f.WebGLGraphics.buildLine(c,a._webGL)):c.type==f.Graphics.RECT?f.WebGLGraphics.buildRectangle(c,a._webGL):(c.type==f.Graphics.CIRC||c.type==f.Graphics.ELIP)&&f.WebGLGraphics.buildCircle(c,a._webGL)}a._webGL.lastIndex=a.graphicsData.length;var d=f.gl;a._webGL.glPoints=new Float32Array(a._webGL.points),d.bindBuffer(d.ARRAY_BUFFER,a._webGL.buffer),d.bufferData(d.ARRAY_BUFFER,a._webGL.glPoints,d.STATIC_DRAW),a._webGL.glIndicies=new Uint16Array(a._webGL.indices),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,a._webGL.indexBuffer),d.bufferData(d.ELEMENT_ARRAY_BUFFER,a._webGL.glIndicies,d.STATIC_DRAW)},f.WebGLGraphics.buildRectangle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3];if(a.fill){var j=d(a.fillColor),k=a.fillAlpha,l=j[0]*k,m=j[1]*k,n=j[2]*k,o=b.points,p=b.indices,q=o.length/6;o.push(e,g),o.push(l,m,n,k),o.push(e+h,g),o.push(l,m,n,k),o.push(e,g+i),o.push(l,m,n,k),o.push(e+h,g+i),o.push(l,m,n,k),p.push(q,q,q+1,q+2,q+3,q+3)}a.lineWidth&&(a.points=[e,g,e+h,g,e+h,g+i,e,g+i,e,g],f.WebGLGraphics.buildLine(a,b))},f.WebGLGraphics.buildCircle=function(a,b){var c=a.points,e=c[0],g=c[1],h=c[2],i=c[3],j=40,k=2*Math.PI/j;if(a.fill){var l=d(a.fillColor),m=a.fillAlpha,n=l[0]*m,o=l[1]*m,p=l[2]*m,q=b.points,r=b.indices,s=q.length/6;r.push(s);for(var t=0;j+1>t;t++)q.push(e,g,n,o,p,m),q.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i,n,o,p,m),r.push(s++,s++);r.push(s-1)}if(a.lineWidth){a.points=[];for(var t=0;j+1>t;t++)a.points.push(e+Math.sin(k*t)*h,g+Math.cos(k*t)*i);f.WebGLGraphics.buildLine(a,b)}},f.WebGLGraphics.buildLine=function(a,b){var c=a.points;if(0!=c.length){var e=new f.Point(c[0],c[1]),g=new f.Point(c[c.length-2],c[c.length-1]);if(e.x==g.x&&e.y==g.y){c.pop(),c.pop(),g=new f.Point(c[c.length-2],c[c.length-1]);var h=g.x+.5*(e.x-g.x),i=g.y+.5*(e.y-g.y);c.unshift(h,i),c.push(h,i)}var j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=b.points,F=b.indices,G=c.length/2,H=c.length,I=E.length/6,J=a.lineWidth/2,K=d(a.lineColor),L=a.lineAlpha,M=K[0]*L,N=K[1]*L,O=K[2]*L;j=c[0],k=c[1],l=c[2],m=c[3],p=-(k-m),q=j-l,D=Math.sqrt(p*p+q*q),p/=D,q/=D,p*=J,q*=J,E.push(j-p,k-q,M,N,O,L),E.push(j+p,k+q,M,N,O,L);for(var P=1;G-1>P;P++)j=c[2*(P-1)],k=c[2*(P-1)+1],l=c[2*P],m=c[2*P+1],n=c[2*(P+1)],o=c[2*(P+1)+1],p=-(k-m),q=j-l,D=Math.sqrt(p*p+q*q),p/=D,q/=D,p*=J,q*=J,r=-(m-o),s=l-n,D=Math.sqrt(r*r+s*s),r/=D,s/=D,r*=J,s*=J,v=-q+k-(-q+m),w=-p+l-(-p+j),x=(-p+j)*(-q+m)-(-p+l)*(-q+k),y=-s+o-(-s+m),z=-r+l-(-r+n),A=(-r+n)*(-s+m)-(-r+l)*(-s+o),B=v*z-y*w,0==B&&(B+=1),px=(w*A-z*x)/B,py=(y*x-v*A)/B,C=(px-l)*(px-l)+(py-m)+(py-m),C>19600?(t=p-r,u=q-s,D=Math.sqrt(t*t+u*u),t/=D,u/=D,t*=J,u*=J,E.push(l-t,m-u),E.push(M,N,O,L),E.push(l+t,m+u),E.push(M,N,O,L),E.push(l-t,m-u),E.push(M,N,O,L),H++):(E.push(px,py),E.push(M,N,O,L),E.push(l-(px-l),m-(py-m)),E.push(M,N,O,L));j=c[2*(G-2)],k=c[2*(G-2)+1],l=c[2*(G-1)],m=c[2*(G-1)+1],p=-(k-m),q=j-l,D=Math.sqrt(p*p+q*q),p/=D,q/=D,p*=J,q*=J,E.push(l-p,m-q),E.push(M,N,O,L),E.push(l+p,m+q),E.push(M,N,O,L),F.push(I);for(var P=0;H>P;P++)F.push(I++);F.push(I-1)}},f.WebGLGraphics.buildPoly=function(a,b){var c=a.points;if(!(c.length<6)){for(var e=b.points,g=b.indices,h=c.length/2,i=d(a.fillColor),j=a.fillAlpha,k=i[0]*j,l=i[1]*j,m=i[2]*j,n=f.PolyK.Triangulate(c),o=e.length/6,p=0;pp;p++)e.push(c[2*p],c[2*p+1],k,l,m,j)}},f._defaultFrame=new f.Rectangle(0,0,1,1),f.gl,f.WebGLRenderer=function(a,b,c,d,e){this.transparent=!!d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.view.width=this.width,this.view.height=this.height;var g=this;this.view.addEventListener("webglcontextlost",function(a){g.handleContextLost(a)},!1),this.view.addEventListener("webglcontextrestored",function(a){g.handleContextRestored(a)},!1),this.batchs=[];try{f.gl=this.gl=this.view.getContext("experimental-webgl",{alpha:this.transparent,antialias:!!e,premultipliedAlpha:!1,stencil:!0})}catch(h){throw new Error(" This browser does not support webGL. Try using the canvas renderer"+this)}f.initDefaultShader(),f.initPrimitiveShader(),f.initDefaultStripShader();var i=this.gl;f.WebGLRenderer.gl=i,this.batch=new f.WebGLBatch(i),i.disable(i.DEPTH_TEST),i.disable(i.CULL_FACE),i.enable(i.BLEND),i.colorMask(!0,!0,!0,this.transparent),f.projection=new f.Point(400,300),this.resize(this.width,this.height),this.contextLost=!1,f.activateShader(f.defaultShader),this.stageRenderGroup=new f.WebGLRenderGroup(this.gl)},f.WebGLRenderer.prototype.constructor=f.WebGLRenderer,f.WebGLRenderer.getBatch=function(){return 0==f._batchs.length?new f.WebGLBatch(f.WebGLRenderer.gl):f._batchs.pop()},f.WebGLRenderer.returnBatch=function(a){a.clean(),f._batchs.push(a)},f.WebGLRenderer.prototype.render=function(a){if(!this.contextLost){this.__stage!==a&&(this.__stage=a,this.stageRenderGroup.setRenderable(a)),f.WebGLRenderer.updateTextures(),f.visibleCount++,a.updateTransform();var b=this.gl;if(b.colorMask(!0,!0,!0,this.transparent),b.viewport(0,0,this.width,this.height),b.bindFramebuffer(b.FRAMEBUFFER,null),b.clearColor(a.backgroundColorSplit[0],a.backgroundColorSplit[1],a.backgroundColorSplit[2],!this.transparent),b.clear(b.COLOR_BUFFER_BIT),this.stageRenderGroup.backgroundColor=a.backgroundColorSplit,this.stageRenderGroup.render(f.projection),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0){for(var c=0;cc;c++){var d=6*c,e=4*c;this.indices[d+0]=e+0,this.indices[d+1]=e+1,this.indices[d+2]=e+2,this.indices[d+3]=e+0,this.indices[d+4]=e+2,this.indices[d+5]=e+3}a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer),a.bufferData(a.ELEMENT_ARRAY_BUFFER,this.indices,a.STATIC_DRAW)},f.WebGLBatch.prototype.refresh=function(){this.gl,this.dynamicSize0;)n=n.children[n.children.length-1],n.renderable&&(m=n.last);if(m instanceof f.Sprite){l=m.batch;var k=l.head;if(k==m)g=0;else for(g=1;k.__next!=m;)g++,k=k.__next}else l=m;if(j==l)return j instanceof f.WebGLBatch?j.render(d,g+1):this.renderSpecial(j,b),void 0;e=this.batchs.indexOf(j),h=this.batchs.indexOf(l),j instanceof f.WebGLBatch?j.render(d):this.renderSpecial(j,b);for(var o=e+1;h>o;o++)renderable=this.batchs[o],renderable instanceof f.WebGLBatch?this.batchs[o].render():this.renderSpecial(renderable,b);l instanceof f.WebGLBatch?l.render(0,g+1):this.renderSpecial(l,b)},f.WebGLRenderGroup.prototype.renderSpecial=function(a,b){f.shaderStack.length;var c=a.vcount===f.visibleCount;a instanceof f.TilingSprite?c&&this.renderTilingSprite(a,b):a instanceof f.Strip?c&&this.renderStrip(a,b):a instanceof f.CustomRenderable?c&&a.renderWebGL(this,b):a instanceof f.Graphics?c&&a.renderable&&f.WebGLGraphics.renderGraphics(a,b):a instanceof f.FilterBlock&&this.handleFilterBlock(a,b)},f.WebGLRenderGroup.prototype.handleFilterBlock=function(a,b){var c=f.gl;if(a.open)if(a.data instanceof Array){var d=a.data[0];if(!d.shader){var e=new f.PixiShader;e.fragmentSrc=d.fragmentSrc,e.uniforms=d.uniforms,e.init(),d.shader=e}f.activateShader(d.shader),c.uniform2f(f.currentShader.projectionVector,b.x,b.y)}else c.enable(c.STENCIL_TEST),c.colorMask(!1,!1,!1,!1),c.stencilFunc(c.ALWAYS,1,255),c.stencilOp(c.KEEP,c.KEEP,c.REPLACE),f.WebGLGraphics.renderGraphics(a.data,b),c.colorMask(!0,!0,!0,!0),c.stencilFunc(c.NOTEQUAL,0,255),c.stencilOp(c.KEEP,c.KEEP,c.KEEP);else a.data instanceof Array?(f.popShader(),c.uniform2f(f.currentShader.projectionVector,b.x,b.y)):c.disable(c.STENCIL_TEST)},f.WebGLRenderGroup.prototype.updateTexture=function(a){this.removeObject(a);for(var b=a.first;b!=this.root&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););this.insertObject(a,b,c)},f.WebGLRenderGroup.prototype.addFilterBlocks=function(a,b){a.__renderGroup=this,b.__renderGroup=this;for(var c=a;c!=this.root.first&&(c=c._iPrev,!c.renderable||!c.__renderGroup););this.insertAfter(a,c);for(var d=b;d!=this.root.first&&(d=d._iPrev,!d.renderable||!d.__renderGroup););this.insertAfter(b,d)},f.WebGLRenderGroup.prototype.removeFilterBlocks=function(a,b){this.removeObject(a),this.removeObject(b)},f.WebGLRenderGroup.prototype.addDisplayObjectAndChildren=function(a){a.__renderGroup&&a.__renderGroup.removeDisplayObjectAndChildren(a);for(var b=a.first;b!=this.root.first&&(b=b._iPrev,!b.renderable||!b.__renderGroup););for(var c=a.last;c._iNext&&(c=c._iNext,!c.renderable||!c.__renderGroup););var d=a.first,e=a.last._iNext;do d.__renderGroup=this,d.renderable&&(this.insertObject(d,b,c),b=d),d=d._iNext;while(d!=e)},f.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren=function(a){if(a.__renderGroup==this){a.last;do a.__renderGroup=null,a.renderable&&this.removeObject(a),a=a._iNext;while(a)}},f.WebGLRenderGroup.prototype.insertObject=function(a,b,c){var d=b,e=c;if(a instanceof f.Sprite){var g,h;if(d instanceof f.Sprite){if(g=d.batch,g&&g.texture==a.texture.baseTexture&&g.blendMode==a.blendMode)return g.insertAfter(a,d),void 0}else g=d;if(e)if(e instanceof f.Sprite){if(h=e.batch){if(h.texture==a.texture.baseTexture&&h.blendMode==a.blendMode)return h.insertBefore(a,e),void 0;if(h==g){var i=g.split(e),j=f.WebGLRenderer.getBatch(),k=this.batchs.indexOf(g);return j.init(a),this.batchs.splice(k+1,0,j,i),void 0}}}else h=e;var j=f.WebGLRenderer.getBatch();if(j.init(a),g){var k=this.batchs.indexOf(g);this.batchs.splice(k+1,0,j)}else this.batchs.push(j)}else a instanceof f.TilingSprite?this.initTilingSprite(a):a instanceof f.Strip&&this.initStrip(a),this.insertAfter(a,d)},f.WebGLRenderGroup.prototype.insertAfter=function(a,b){if(b instanceof f.Sprite){var c=b.batch;if(c)if(c.tail==b){var d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a)}else{var e=c.split(b.__next),d=this.batchs.indexOf(c);this.batchs.splice(d+1,0,a,e)}else this.batchs.push(a)}else{var d=this.batchs.indexOf(b);this.batchs.splice(d+1,0,a)}},f.WebGLRenderGroup.prototype.removeObject=function(a){var b;if(a instanceof f.Sprite){var c=a.batch;if(!c)return;c.remove(a),0==c.size&&(b=c)}else b=a;if(b){var d=this.batchs.indexOf(b);if(-1==d)return;if(0==d||d==this.batchs.length-1)return this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),void 0;if(this.batchs[d-1]instanceof f.WebGLBatch&&this.batchs[d+1]instanceof f.WebGLBatch&&this.batchs[d-1].texture==this.batchs[d+1].texture&&this.batchs[d-1].blendMode==this.batchs[d+1].blendMode)return this.batchs[d-1].merge(this.batchs[d+1]),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b),f.WebGLRenderer.returnBatch(this.batchs[d+1]),this.batchs.splice(d,2),void 0;this.batchs.splice(d,1),b instanceof f.WebGLBatch&&f.WebGLRenderer.returnBatch(b)}},f.WebGLRenderGroup.prototype.initTilingSprite=function(a){var b=this.gl;a.verticies=new Float32Array([0,0,a.width,0,a.width,a.height,0,a.height]),a.uvs=new Float32Array([0,0,1,0,1,1,0,1]),a.colors=new Float32Array([1,1,1,1]),a.indices=new Uint16Array([0,1,3,2]),a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW),a.texture.baseTexture._glTexture?(b.bindTexture(b.TEXTURE_2D,a.texture.baseTexture._glTexture),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.REPEAT),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.REPEAT),a.texture.baseTexture._powerOf2=!0):a.texture.baseTexture._powerOf2=!0},f.WebGLRenderGroup.prototype.renderStrip=function(a,b){var c=this.gl,d=f.stripShaderProgram;c.useProgram(d);var e=f.mat3.clone(a.worldTransform);f.mat3.transpose(e),c.uniformMatrix3fv(d.translationMatrix,!1,e),c.uniform2f(d.projectionVector,b.x,b.y),c.uniform1f(d.alpha,a.worldAlpha),a.dirty?(a.dirty=!1,c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferData(c.ARRAY_BUFFER,a.verticies,c.STATIC_DRAW),c.vertexAttribPointer(d.vertexPositionAttribute,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferData(c.ARRAY_BUFFER,a.uvs,c.STATIC_DRAW),c.vertexAttribPointer(d.textureCoordAttribute,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.bufferData(c.ARRAY_BUFFER,a.colors,c.STATIC_DRAW),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer),c.bufferData(c.ELEMENT_ARRAY_BUFFER,a.indices,c.STATIC_DRAW)):(c.bindBuffer(c.ARRAY_BUFFER,a._vertexBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.verticies),c.vertexAttribPointer(d.vertexPositionAttribute,2,c.FLOAT,!1,0,0),c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.vertexAttribPointer(d.textureCoordAttribute,2,c.FLOAT,!1,0,0),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,a.texture.baseTexture._glTexture),c.bindBuffer(c.ARRAY_BUFFER,a._colorBuffer),c.vertexAttribPointer(d.colorAttribute,1,c.FLOAT,!1,0,0),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,a._indexBuffer)),c.drawElements(c.TRIANGLE_STRIP,a.indices.length,c.UNSIGNED_SHORT,0),c.useProgram(f.currentProgram)},f.WebGLRenderGroup.prototype.renderTilingSprite=function(a,b){var c=this.gl;f.shaderProgram;var d=a.tilePosition,e=a.tileScale,g=d.x/a.texture.baseTexture.width,h=d.y/a.texture.baseTexture.height,i=a.width/a.texture.baseTexture.width/e.x,j=a.height/a.texture.baseTexture.height/e.y;a.uvs[0]=0-g,a.uvs[1]=0-h,a.uvs[2]=1*i-g,a.uvs[3]=0-h,a.uvs[4]=1*i-g,a.uvs[5]=1*j-h,a.uvs[6]=0-g,a.uvs[7]=1*j-h,c.bindBuffer(c.ARRAY_BUFFER,a._uvBuffer),c.bufferSubData(c.ARRAY_BUFFER,0,a.uvs),this.renderStrip(a,b)},f.WebGLRenderGroup.prototype.initStrip=function(a){var b=this.gl;this.shaderProgram,a._vertexBuffer=b.createBuffer(),a._indexBuffer=b.createBuffer(),a._uvBuffer=b.createBuffer(),a._colorBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,a._vertexBuffer),b.bufferData(b.ARRAY_BUFFER,a.verticies,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._uvBuffer),b.bufferData(b.ARRAY_BUFFER,a.uvs,b.STATIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,a._colorBuffer),b.bufferData(b.ARRAY_BUFFER,a.colors,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,a._indexBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,a.indices,b.STATIC_DRAW)},f.CanvasRenderer=function(a,b,c,d){this.transparent=d,this.width=a||800,this.height=b||600,this.view=c||document.createElement("canvas"),this.context=this.view.getContext("2d"),this.refresh=!0,this.view.width=this.width,this.view.height=this.height,this.count=0},f.CanvasRenderer.prototype.constructor=f.CanvasRenderer,f.CanvasRenderer.prototype.render=function(a){f.texturesToUpdate=[],f.texturesToDestroy=[],f.visibleCount++,a.updateTransform(),this.view.style.backgroundColor==a.backgroundColorString||this.transparent||(this.view.style.backgroundColor=a.backgroundColorString),this.context.setTransform(1,0,0,1,0,0),this.context.clearRect(0,0,this.width,this.height),this.renderDisplayObject(a),a.interactive&&(a._interactiveEventsAdded||(a._interactiveEventsAdded=!0,a.interactionManager.setTarget(this))),f.Texture.frameUpdates.length>0&&(f.Texture.frameUpdates=[])},f.CanvasRenderer.prototype.resize=function(a,b){this.width=a,this.height=b,this.view.width=a,this.view.height=b},f.CanvasRenderer.prototype.renderDisplayObject=function(a){var b,c=this.context;c.globalCompositeOperation="source-over";var d=a.last._iNext;a=a.first;do if(b=a.worldTransform,a.visible)if(a.renderable){if(a instanceof f.Sprite){var e=a.texture.frame;e&&e.width&&e.height&&(c.globalAlpha=a.worldAlpha,c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),c.drawImage(a.texture.baseTexture.source,e.x,e.y,e.width,e.height,a.anchor.x*-e.width,a.anchor.y*-e.height,e.width,e.height))}else if(a instanceof f.Strip)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderStrip(a);else if(a instanceof f.TilingSprite)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),this.renderTilingSprite(a);else if(a instanceof f.CustomRenderable)a.renderCanvas(this);else if(a instanceof f.Graphics)c.setTransform(b[0],b[3],b[1],b[4],b[2],b[5]),f.CanvasGraphics.renderGraphics(a,c);else if(a instanceof f.FilterBlock&&f.FilterBlock.data instanceof f.Graphics)if(a.open){c.save();var g=a.mask.alpha,h=a.mask.worldTransform;c.setTransform(h[0],h[3],h[1],h[4],h[2],h[5]),a.mask.worldAlpha=.5,c.worldAlpha=0,f.CanvasGraphics.renderGraphicsMask(a.mask,c),c.clip(),a.mask.worldAlpha=g}else c.restore();a=a._iNext}else a=a._iNext;else a=a.last._iNext;while(a!=d)},f.CanvasRenderer.prototype.renderStripFlat=function(a){var b=this.context,c=a.verticies;a.uvs;var d=c.length/2;this.count++,b.beginPath();for(var e=1;d-2>e;e++){var f=2*e,g=c[f],h=c[f+2],i=c[f+4],j=c[f+1],k=c[f+3],l=c[f+5];b.moveTo(g,j),b.lineTo(h,k),b.lineTo(i,l)}b.fillStyle="#FF0000",b.fill(),b.closePath()},f.CanvasRenderer.prototype.renderTilingSprite=function(a){var b=this.context;b.globalAlpha=a.worldAlpha,a.__tilePattern||(a.__tilePattern=b.createPattern(a.texture.baseTexture.source,"repeat")),b.beginPath();var c=a.tilePosition,d=a.tileScale;b.scale(d.x,d.y),b.translate(c.x,c.y),b.fillStyle=a.__tilePattern,b.fillRect(-c.x,-c.y,a.width/d.x,a.height/d.y),b.scale(1/d.x,1/d.y),b.translate(-c.x,-c.y),b.closePath()},f.CanvasRenderer.prototype.renderStrip=function(a){var b=this.context,c=a.verticies,d=a.uvs,e=c.length/2;this.count++;for(var f=1;e-2>f;f++){var g=2*f,h=c[g],i=c[g+2],j=c[g+4],k=c[g+1],l=c[g+3],m=c[g+5],n=d[g]*a.texture.width,o=d[g+2]*a.texture.width,p=d[g+4]*a.texture.width,q=d[g+1]*a.texture.height,r=d[g+3]*a.texture.height,s=d[g+5]*a.texture.height;b.save(),b.beginPath(),b.moveTo(h,k),b.lineTo(i,l),b.lineTo(j,m),b.closePath(),b.clip();var t=n*r+q*p+o*s-r*p-q*o-n*s,u=h*r+q*j+i*s-r*j-q*i-h*s,v=n*i+h*p+o*j-i*p-h*o-n*j,w=n*r*j+q*i*p+h*o*s-h*r*p-q*o*j-n*i*s,x=k*r+q*m+l*s-r*m-q*l-k*s,y=n*l+k*p+o*m-l*p-k*o-n*m,z=n*r*m+q*l*p+k*o*s-k*r*p-q*o*m-n*l*s;b.transform(u/t,x/t,v/t,y/t,w/t,z/t),b.drawImage(a.texture.baseTexture.source,0,0),b.restore()}},f.CanvasGraphics=function(){},f.CanvasGraphics.renderGraphics=function(a,b){for(var c=a.worldAlpha,d=0;d1&&(c=1,console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object"));for(var d=0;1>d;d++){var e=a.graphicsData[d],g=e.points;if(e.type==f.Graphics.POLY){b.beginPath(),b.moveTo(g[0],g[1]);for(var h=1;hh;h++){var f=a[h],i=4*h,j=h/(g-1);h%2?(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1):(b[i]=j,b[i+1]=0,b[i+2]=j,b[i+3]=1),i=2*h,d[i]=1,d[i+1]=1,i=2*h,c[i]=i,c[i+1]=i+1,e=f}}},f.Rope.prototype.updateTransform=function(){var a=this.points;if(!(a.length<1)){var b,c=this.verticies,d=a[0],e={x:0,y:0},g=a[0];this.count-=.2,c[0]=g.x+e.x,c[1]=g.y+e.y,c[2]=g.x-e.x,c[3]=g.y-e.y;for(var h=a.length,i=1;h>i;i++){var g=a[i],j=4*i;b=i1&&(k=1);var l=Math.sqrt(e.x*e.x+e.y*e.y),m=this.texture.height/2;e.x/=l,e.y/=l,e.x*=m,e.y*=m,c[j]=g.x+e.x,c[j+1]=g.y+e.y,c[j+2]=g.x-e.x,c[j+3]=g.y-e.y,d=g}f.DisplayObjectContainer.prototype.updateTransform.call(this)}},f.Rope.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite=function(a,b,c){f.DisplayObjectContainer.call(this),this.texture=a,this.width=b,this.height=c,this.tileScale=new f.Point(1,1),this.tilePosition=new f.Point(0,0),this.renderable=!0,this.blendMode=f.blendModes.NORMAL},f.TilingSprite.prototype=Object.create(f.DisplayObjectContainer.prototype),f.TilingSprite.prototype.constructor=f.TilingSprite,f.TilingSprite.prototype.setTexture=function(a){this.texture=a,this.updateFrame=!0},f.TilingSprite.prototype.onTextureUpdate=function(){this.updateFrame=!0},f.Spine=function(a){if(f.DisplayObjectContainer.call(this),this.spineData=f.AnimCache[a],!this.spineData)throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: "+a);this.skeleton=new l.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new l.AnimationStateData(this.spineData),this.state=new l.AnimationState(this.stateData),this.slotContainers=[];for(var b=0,c=this.skeleton.drawOrder.length;c>b;b++){var d=this.skeleton.drawOrder[b],e=d.attachment,g=new f.DisplayObjectContainer;if(this.slotContainers.push(g),this.addChild(g),e instanceof l.RegionAttachment){var h=e.rendererObject.name,i=this.createSprite(d,e.rendererObject);d.currentSprite=i,d.currentSpriteName=h,g.addChild(i)}}},f.Spine.prototype=Object.create(f.DisplayObjectContainer.prototype),f.Spine.prototype.constructor=f.Spine,f.Spine.prototype.updateTransform=function(){this.lastTime=this.lastTime||Date.now();var a=.001*(Date.now()-this.lastTime);this.lastTime=Date.now(),this.state.update(a),this.state.apply(this.skeleton),this.skeleton.updateWorldTransform();for(var b=this.skeleton.drawOrder,c=0,d=b.length;d>c;c++){var e=b[c],g=e.attachment,h=this.slotContainers[c];if(g instanceof l.RegionAttachment){if(g.rendererObject&&(!e.currentSpriteName||e.currentSpriteName!=g.name)){var i=g.rendererObject.name;if(void 0!==e.currentSprite&&(e.currentSprite.visible=!1),e.sprites=e.sprites||{},void 0!==e.sprites[i])e.sprites[i].visible=!0;else{var j=this.createSprite(e,g.rendererObject);h.addChild(j)}e.currentSprite=e.sprites[i],e.currentSpriteName=i}h.visible=!0;var k=e.bone;h.position.x=k.worldX+g.x*k.m00+g.y*k.m01,h.position.y=k.worldY+g.x*k.m10+g.y*k.m11,h.scale.x=k.worldScaleX,h.scale.y=k.worldScaleY,h.rotation=-(e.bone.worldRotation*Math.PI/180)}else h.visible=!1}f.DisplayObjectContainer.prototype.updateTransform.call(this)},f.Spine.prototype.createSprite=function(a,b){var c=f.TextureCache[b.name]?b.name:b.name+".png",d=new f.Sprite(f.Texture.fromFrame(c));return d.scale=b.scale,d.rotation=b.rotation,d.anchor.x=d.anchor.y=.5,a.sprites=a.sprites||{},a.sprites[b.name]=d,d};var l={};l.BoneData=function(a,b){this.name=a,this.parent=b},l.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1},l.SlotData=function(a,b){this.name=a,this.boneData=b},l.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null},l.Bone=function(a,b){this.data=a,this.parent=b,this.setToSetupPose()},l.Bone.yDown=!1,l.Bone.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,m00:0,m01:0,worldX:0,m10:0,m11:0,worldY:0,worldRotation:0,worldScaleX:1,worldScaleY:1,updateWorldTransform:function(a,b){var c=this.parent;null!=c?(this.worldX=this.x*c.m00+this.y*c.m01+c.worldX,this.worldY=this.x*c.m10+this.y*c.m11+c.worldY,this.worldScaleX=c.worldScaleX*this.scaleX,this.worldScaleY=c.worldScaleY*this.scaleY,this.worldRotation=c.worldRotation+this.rotation):(this.worldX=this.x,this.worldY=this.y,this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY,this.worldRotation=this.rotation);var d=this.worldRotation*Math.PI/180,e=Math.cos(d),f=Math.sin(d);this.m00=e*this.worldScaleX,this.m10=f*this.worldScaleX,this.m01=-f*this.worldScaleY,this.m11=e*this.worldScaleY,a&&(this.m00=-this.m00,this.m01=-this.m01),b&&(this.m10=-this.m10,this.m11=-this.m11),l.Bone.yDown&&(this.m10=-this.m10,this.m11=-this.m11)},setToSetupPose:function(){var a=this.data;this.x=a.x,this.y=a.y,this.rotation=a.rotation,this.scaleX=a.scaleX,this.scaleY=a.scaleY}},l.Slot=function(a,b,c){this.data=a,this.skeleton=b,this.bone=c,this.setToSetupPose()},l.Slot.prototype={r:1,g:1,b:1,a:1,_attachmentTime:0,attachment:null,setAttachment:function(a){this.attachment=a,this._attachmentTime=this.skeleton.time},setAttachmentTime:function(a){this._attachmentTime=this.skeleton.time-a},getAttachmentTime:function(){return this.skeleton.time-this._attachmentTime},setToSetupPose:function(){var a=this.data;this.r=a.r,this.g=a.g,this.b=a.b,this.a=a.a;for(var b=this.skeleton.data.slots,c=0,d=b.length;d>c;c++)if(b[c]==a){this.setAttachment(a.attachmentName?this.skeleton.getAttachmentBySlotIndex(c,a.attachmentName):null);break}}},l.Skin=function(a){this.name=a,this.attachments={}},l.Skin.prototype={addAttachment:function(a,b,c){this.attachments[a+":"+b]=c},getAttachment:function(a,b){return this.attachments[a+":"+b]},_attachAll:function(a,b){for(var c in b.attachments){var d=c.indexOf(":"),e=parseInt(c.substring(0,d)),f=c.substring(d+1),g=a.slots[e];if(g.attachment&&g.attachment.name==f){var h=this.getAttachment(e,f);h&&g.setAttachment(h)}}}},l.Animation=function(a,b,c){this.name=a,this.timelines=b,this.duration=c},l.Animation.prototype={apply:function(a,b,c){c&&0!=this.duration&&(b%=this.duration);for(var d=this.timelines,e=0,f=d.length;f>e;e++)d[e].apply(a,b,1)},mix:function(a,b,c,d){c&&0!=this.duration&&(b%=this.duration);for(var e=this.timelines,f=0,g=e.length;g>f;f++)e[f].apply(a,b,d)}},l.binarySearch=function(a,b,c){var d=0,e=Math.floor(a.length/c)-2;if(0==e)return c;for(var f=e>>>1;;){if(a[(f+1)*c]<=b?d=f+1:e=f,d==e)return(d+1)*c;f=d+e>>>1}},l.linearSearch=function(a,b,c){for(var d=0,e=a.length-c;e>=d;d+=c)if(a[d]>b)return d;return-1},l.Curves=function(a){this.curves=[],this.curves.length=6*(a-1)},l.Curves.prototype={setLinear:function(a){this.curves[6*a]=0},setStepped:function(a){this.curves[6*a]=-1},setCurve:function(a,b,c,d,e){var f=.1,g=f*f,h=g*f,i=3*f,j=3*g,k=6*g,l=6*h,m=2*-b+d,n=2*-c+e,o=3*(b-d)+1,p=3*(c-e)+1,q=6*a,r=this.curves;r[q]=b*i+m*j+o*h,r[q+1]=c*i+n*j+p*h,r[q+2]=m*k+o*l,r[q+3]=n*k+p*l,r[q+4]=o*l,r[q+5]=p*l},getCurvePercent:function(a,b){b=0>b?0:b>1?1:b;var c=6*a,d=this.curves,e=d[c];if(!e)return b;if(-1==e)return 0;for(var f=d[c+1],g=d[c+2],h=d[c+3],i=d[c+4],j=d[c+5],k=e,l=f,m=8;;){if(k>=b){var n=k-e,o=l-f;return o+(l-o)*(b-n)/(k-n)}if(0==m)break;m--,e+=g,f+=h,g+=i,h+=j,k+=e,l+=f}return l+(1-l)*(b-k)/(1-k)}},l.RotateTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=2*a},l.RotateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(a,b,c){a*=2,this.frames[a]=b,this.frames[a+1]=c},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-2]){for(var f=e.data.rotation+d[d.length-1]-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;return e.rotation+=f*c,void 0}var g=l.binarySearch(d,b,2),h=d[g-1],i=d[g],j=1-(b-i)/(d[g-2]-i);j=this.curves.getCurvePercent(g/2-1,j);for(var f=d[g+1]-h;f>180;)f-=360;for(;-180>f;)f+=360;for(f=e.data.rotation+(h+f*j)-e.rotation;f>180;)f-=360;for(;-180>f;)f+=360;e.rotation+=f*c}}},l.TranslateTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=3*a},l.TranslateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.x+=(e.data.x+d[d.length-2]-e.x)*c,e.y+=(e.data.y+d[d.length-1]-e.y)*c,void 0;var f=l.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.x+=(e.data.x+g+(d[f+1]-g)*j-e.x)*c,e.y+=(e.data.y+h+(d[f+2]-h)*j-e.y)*c}}},l.ScaleTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=3*a},l.ScaleTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(a,b,c,d){a*=3,this.frames[a]=b,this.frames[a+1]=c,this.frames[a+2]=d},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-3])return e.scaleX+=(e.data.scaleX-1+d[d.length-2]-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+d[d.length-1]-e.scaleY)*c,void 0;var f=l.binarySearch(d,b,3),g=d[f-2],h=d[f-1],i=d[f],j=1-(b-i)/(d[f+-3]-i);j=this.curves.getCurvePercent(f/3-1,j),e.scaleX+=(e.data.scaleX-1+g+(d[f+1]-g)*j-e.scaleX)*c,e.scaleY+=(e.data.scaleY-1+h+(d[f+2]-h)*j-e.scaleY)*c}}},l.ColorTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=5*a},l.ColorTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(c,d){c*=5,this.frames[c]=d,this.frames[c+1]=r,this.frames[c+2]=g,this.frames[c+3]=b,this.frames[c+4]=a},apply:function(a,b,c){var d=this.frames;if(!(b=d[d.length-5]){var f=d.length-1;return e.r=d[f-3],e.g=d[f-2],e.b=d[f-1],e.a=d[f],void 0}var g=l.binarySearch(d,b,5),h=d[g-4],i=d[g-3],j=d[g-2],k=d[g-1],m=d[g],n=1-(b-m)/(d[g-5]-m);n=this.curves.getCurvePercent(g/5-1,n);var o=h+(d[g+1]-h)*n,p=i+(d[g+2]-i)*n,q=j+(d[g+3]-j)*n,r=k+(d[g+4]-k)*n;1>c?(e.r+=(o-e.r)*c,e.g+=(p-e.g)*c,e.b+=(q-e.b)*c,e.a+=(r-e.a)*c):(e.r=o,e.g=p,e.b=q,e.a=r)}}},l.AttachmentTimeline=function(a){this.curves=new l.Curves(a),this.frames=[],this.frames.length=a,this.attachmentNames=[],this.attachmentNames.length=a},l.AttachmentTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length},setFrame:function(a,b,c){this.frames[a]=b,this.attachmentNames[a]=c},apply:function(a,b){var c=this.frames;if(!(b=c[c.length-1]?c.length-1:l.binarySearch(c,b,1)-1;var e=this.attachmentNames[d];a.slots[this.slotIndex].setAttachment(e?a.getAttachmentBySlotIndex(this.slotIndex,e):null)}}},l.SkeletonData=function(){this.bones=[],this.slots=[],this.skins=[],this.animations=[]},l.SkeletonData.prototype={defaultSkin:null,findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return slot[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].name==a)return c;return-1},findSkin:function(a){for(var b=this.skins,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},findAnimation:function(a){for(var b=this.animations,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null}},l.Skeleton=function(a){this.data=a,this.bones=[];for(var b=0,c=a.bones.length;c>b;b++){var d=a.bones[b],e=d.parent?this.bones[a.bones.indexOf(d.parent)]:null;this.bones.push(new l.Bone(d,e))}this.slots=[],this.drawOrder=[];for(var b=0,c=a.slots.length;c>b;b++){var f=a.slots[b],g=this.bones[a.bones.indexOf(f.boneData)],h=new l.Slot(f,this,g);this.slots.push(h),this.drawOrder.push(h)}},l.Skeleton.prototype={x:0,y:0,skin:null,r:1,g:1,b:1,a:1,time:0,flipX:!1,flipY:!1,updateWorldTransform:function(){for(var a=this.flipX,b=this.flipY,c=this.bones,d=0,e=c.length;e>d;d++)c[d].updateWorldTransform(a,b)},setToSetupPose:function(){this.setBonesToSetupPose(),this.setSlotsToSetupPose()},setBonesToSetupPose:function(){for(var a=this.bones,b=0,c=a.length;c>b;b++)a[b].setToSetupPose()},setSlotsToSetupPose:function(){for(var a=this.slots,b=0,c=a.length;c>b;b++)a[b].setToSetupPose(b)},getRootBone:function(){return 0==this.bones.length?null:this.bones[0]},findBone:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findBoneIndex:function(a){for(var b=this.bones,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},findSlot:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return b[c];return null},findSlotIndex:function(a){for(var b=this.slots,c=0,d=b.length;d>c;c++)if(b[c].data.name==a)return c;return-1},setSkinByName:function(a){var b=this.data.findSkin(a);if(!b)throw"Skin not found: "+a;this.setSkin(b)},setSkin:function(a){this.skin&&a&&a._attachAll(this,this.skin),this.skin=a},getAttachmentBySlotName:function(a,b){return this.getAttachmentBySlotIndex(this.data.findSlotIndex(a),b)},getAttachmentBySlotIndex:function(a,b){if(this.skin){var c=this.skin.getAttachment(a,b);if(c)return c}return this.data.defaultSkin?this.data.defaultSkin.getAttachment(a,b):null},setAttachment:function(a,b){for(var c=this.slots,d=0,e=c.size;e>d;d++){var f=c[d];if(f.data.name==a){var g=null;if(b&&(g=this.getAttachment(d,b),null==g))throw"Attachment not found: "+b+", for slot: "+a;return f.setAttachment(g),void 0}}throw"Slot not found: "+a},update:function(a){time+=a}},l.AttachmentType={region:0},l.RegionAttachment=function(){this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},l.RegionAttachment.prototype={x:0,y:0,rotation:0,scaleX:1,scaleY:1,width:0,height:0,rendererObject:null,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,setUVs:function(a,b,c,d,e){var f=this.uvs;e?(f[2]=a,f[3]=d,f[4]=a,f[5]=b,f[6]=c,f[7]=b,f[0]=c,f[1]=d):(f[0]=a,f[1]=d,f[2]=a,f[3]=b,f[4]=c,f[5]=b,f[6]=c,f[7]=d)},updateOffset:function(){var a=this.width/this.regionOriginalWidth*this.scaleX,b=this.height/this.regionOriginalHeight*this.scaleY,c=-this.width/2*this.scaleX+this.regionOffsetX*a,d=-this.height/2*this.scaleY+this.regionOffsetY*b,e=c+this.regionWidth*a,f=d+this.regionHeight*b,g=this.rotation*Math.PI/180,h=Math.cos(g),i=Math.sin(g),j=c*h+this.x,k=c*i,l=d*h+this.y,m=d*i,n=e*h+this.x,o=e*i,p=f*h+this.y,q=f*i,r=this.offset;r[0]=j-m,r[1]=l+k,r[2]=j-q,r[3]=p+k,r[4]=n-q,r[5]=p+o,r[6]=n-m,r[7]=l+o},computeVertices:function(a,b,c,d){a+=c.worldX,b+=c.worldY;var e=c.m00,f=c.m01,g=c.m10,h=c.m11,i=this.offset;d[0]=i[0]*e+i[1]*f+a,d[1]=i[0]*g+i[1]*h+b,d[2]=i[2]*e+i[3]*f+a,d[3]=i[2]*g+i[3]*h+b,d[4]=i[4]*e+i[5]*f+a,d[5]=i[4]*g+i[5]*h+b,d[6]=i[6]*e+i[7]*f+a,d[7]=i[6]*g+i[7]*h+b}},l.AnimationStateData=function(a){this.skeletonData=a,this.animationToMixTime={}},l.AnimationStateData.prototype={defaultMix:0,setMixByName:function(a,b,c){var d=this.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;var e=this.skeletonData.findAnimation(b);if(!e)throw"Animation not found: "+b;this.setMix(d,e,c)},setMix:function(a,b,c){this.animationToMixTime[a.name+":"+b.name]=c},getMix:function(a,b){var c=this.animationToMixTime[a.name+":"+b.name];return c?c:this.defaultMix}},l.AnimationState=function(a){this.data=a,this.queue=[]},l.AnimationState.prototype={current:null,previous:null,currentTime:0,previousTime:0,currentLoop:!1,previousLoop:!1,mixTime:0,mixDuration:0,update:function(a){if(this.currentTime+=a,this.previousTime+=a,this.mixTime+=a,this.queue.length>0){var b=this.queue[0];this.currentTime>=b.delay&&(this._setAnimation(b.animation,b.loop),this.queue.shift())}},apply:function(a){if(this.current)if(this.previous){this.previous.apply(a,this.previousTime,this.previousLoop);var b=this.mixTime/this.mixDuration;b>=1&&(b=1,this.previous=null),this.current.mix(a,this.currentTime,this.currentLoop,b)}else this.current.apply(a,this.currentTime,this.currentLoop)},clearAnimation:function(){this.previous=null,this.current=null,this.queue.length=0},_setAnimation:function(a,b){this.previous=null,a&&this.current&&(this.mixDuration=this.data.getMix(this.current,a),this.mixDuration>0&&(this.mixTime=0,this.previous=this.current,this.previousTime=this.currentTime,this.previousLoop=this.currentLoop)),this.current=a,this.currentLoop=b,this.currentTime=0},setAnimationByName:function(a,b){var c=this.data.skeletonData.findAnimation(a);if(!c)throw"Animation not found: "+a;this.setAnimation(c,b)},setAnimation:function(a,b){this.queue.length=0,this._setAnimation(a,b)},addAnimationByName:function(a,b,c){var d=this.data.skeletonData.findAnimation(a);if(!d)throw"Animation not found: "+a;this.addAnimation(d,b,c)},addAnimation:function(a,b,c){var d={};if(d.animation=a,d.loop=b,!c||0>=c){var e=0==this.queue.length?this.current:this.queue[this.queue.length-1].animation;c=null!=e?e.duration-this.data.getMix(e,a)+(c||0):0}d.delay=c,this.queue.push(d)},isComplete:function(){return!this.current||this.currentTime>=this.current.duration}},l.SkeletonJson=function(a){this.attachmentLoader=a},l.SkeletonJson.prototype={scale:1,readSkeletonData:function(a){for(var b=new l.SkeletonData,c=a.bones,d=0,e=c.length;e>d;d++){var f=c[d],g=null;if(f.parent&&(g=b.findBone(f.parent),!g))throw"Parent bone not found: "+f.parent;var h=new l.BoneData(f.name,g);h.length=(f.length||0)*this.scale,h.x=(f.x||0)*this.scale,h.y=(f.y||0)*this.scale,h.rotation=f.rotation||0,h.scaleX=f.scaleX||1,h.scaleY=f.scaleY||1,b.bones.push(h)}for(var i=a.slots,d=0,e=i.length;e>d;d++){var j=i[d],h=b.findBone(j.bone);if(!h)throw"Slot bone not found: "+j.bone;var k=new l.SlotData(j.name,h),m=j.color;m&&(k.r=l.SkeletonJson.toColor(m,0),k.g=l.SkeletonJson.toColor(m,1),k.b=l.SkeletonJson.toColor(m,2),k.a=l.SkeletonJson.toColor(m,3)),k.attachmentName=j.attachment,b.slots.push(k)}var n=a.skins;for(var o in n)if(n.hasOwnProperty(o)){var p=n[o],q=new l.Skin(o);for(var r in p)if(p.hasOwnProperty(r)){var s=b.findSlotIndex(r),t=p[r];for(var u in t)if(t.hasOwnProperty(u)){var v=this.readAttachment(q,u,t[u]);null!=v&&q.addAttachment(s,u,v)}}b.skins.push(q),"default"==q.name&&(b.defaultSkin=q)}var w=a.animations;for(var x in w)w.hasOwnProperty(x)&&this.readAnimation(x,w[x],b);return b},readAttachment:function(a,b,c){b=c.name||b;var d=l.AttachmentType[c.type||"region"];if(d==l.AttachmentType.region){var e=new l.RegionAttachment;return e.x=(c.x||0)*this.scale,e.y=(c.y||0)*this.scale,e.scaleX=c.scaleX||1,e.scaleY=c.scaleY||1,e.rotation=c.rotation||0,e.width=(c.width||32)*this.scale,e.height=(c.height||32)*this.scale,e.updateOffset(),e.rendererObject={},e.rendererObject.name=b,e.rendererObject.scale={},e.rendererObject.scale.x=e.scaleX,e.rendererObject.scale.y=e.scaleY,e.rendererObject.rotation=-e.rotation*Math.PI/180,e}throw"Unknown attachment type: "+d},readAnimation:function(a,b,c){var d=[],e=0,f=b.bones;for(var g in f)if(f.hasOwnProperty(g)){var h=c.findBoneIndex(g);if(-1==h)throw"Bone not found: "+g;var i=f[g];for(var j in i)if(i.hasOwnProperty(j)){var k=i[j];if("rotate"==j){var m=new l.RotateTimeline(k.length);m.boneIndex=h;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o];m.setFrame(n,q.time,q.angle),l.SkeletonJson.readCurve(m,n,q),n++}d.push(m),e=Math.max(e,m.frames[2*m.getFrameCount()-2])}else{if("translate"!=j&&"scale"!=j)throw"Invalid timeline type for a bone: "+j+" ("+g+")";var m,r=1;"scale"==j?m=new l.ScaleTimeline(k.length):(m=new l.TranslateTimeline(k.length),r=this.scale),m.boneIndex=h;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o],s=(q.x||0)*r,t=(q.y||0)*r;m.setFrame(n,q.time,s,t),l.SkeletonJson.readCurve(m,n,q),n++}d.push(m),e=Math.max(e,m.frames[3*m.getFrameCount()-3])}}}var u=b.slots;for(var v in u)if(u.hasOwnProperty(v)){var w=u[v],x=c.findSlotIndex(v);for(var j in w)if(w.hasOwnProperty(j)){var k=w[j];if("color"==j){var m=new l.ColorTimeline(k.length);m.slotIndex=x;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o],y=q.color,z=l.SkeletonJson.toColor(y,0),A=l.SkeletonJson.toColor(y,1),B=l.SkeletonJson.toColor(y,2),C=l.SkeletonJson.toColor(y,3);m.setFrame(n,q.time,z,A,B,C),l.SkeletonJson.readCurve(m,n,q),n++}d.push(m),e=Math.max(e,m.frames[5*m.getFrameCount()-5])}else{if("attachment"!=j)throw"Invalid timeline type for a slot: "+j+" ("+v+")";var m=new l.AttachmentTimeline(k.length);m.slotIndex=x;for(var n=0,o=0,p=k.length;p>o;o++){var q=k[o];m.setFrame(n++,q.time,q.name)}d.push(m),e=Math.max(e,m.frames[m.getFrameCount()-1])}}}c.animations.push(new l.Animation(a,d,e))}},l.SkeletonJson.readCurve=function(a,b,c){var d=c.curve;d&&("stepped"==d?a.curves.setStepped(b):d instanceof Array&&a.curves.setCurve(b,d[0],d[1],d[2],d[3]))},l.SkeletonJson.toColor=function(a,b){if(8!=a.length)throw"Color hexidecimal length must be 8, recieved: "+a;return parseInt(a.substring(2*b,2),16)/255},l.Atlas=function(a,b){this.textureLoader=b,this.pages=[],this.regions=[];var c=new l.AtlasReader(a),d=[];d.length=4;for(var e=null;;){var f=c.readLine();if(null==f)break;if(f=c.trim(f),0==f.length)e=null;else if(e){var g=new l.AtlasRegion;g.name=f,g.page=e,g.rotate="true"==c.readValue(),c.readTuple(d);var h=parseInt(d[0]),i=parseInt(d[1]);c.readTuple(d);var j=parseInt(d[0]),k=parseInt(d[1]);g.u=h/e.width,g.v=i/e.height,g.rotate?(g.u2=(h+k)/e.width,g.v2=(i+j)/e.height):(g.u2=(h+j)/e.width,g.v2=(i+k)/e.height),g.x=h,g.y=i,g.width=Math.abs(j),g.height=Math.abs(k),4==c.readTuple(d)&&(g.splits=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],4==c.readTuple(d)&&(g.pads=[parseInt(d[0]),parseInt(d[1]),parseInt(d[2]),parseInt(d[3])],c.readTuple(d))),g.originalWidth=parseInt(d[0]),g.originalHeight=parseInt(d[1]),c.readTuple(d),g.offsetX=parseInt(d[0]),g.offsetY=parseInt(d[1]),g.index=parseInt(c.readValue()),this.regions.push(g)}else{e=new l.AtlasPage,e.name=f,e.format=l.Atlas.Format[c.readValue()],c.readTuple(d),e.minFilter=l.Atlas.TextureFilter[d[0]],e.magFilter=l.Atlas.TextureFilter[d[1]];var m=c.readValue();e.uWrap=l.Atlas.TextureWrap.clampToEdge,e.vWrap=l.Atlas.TextureWrap.clampToEdge,"x"==m?e.uWrap=l.Atlas.TextureWrap.repeat:"y"==m?e.vWrap=l.Atlas.TextureWrap.repeat:"xy"==m&&(e.uWrap=e.vWrap=l.Atlas.TextureWrap.repeat),b.load(e,f),this.pages.push(e)}}},l.Atlas.prototype={findRegion:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++)if(b[c].name==a)return b[c];return null},dispose:function(){for(var a=this.pages,b=0,c=a.length;c>b;b++)this.textureLoader.unload(a[b].rendererObject)},updateUVs:function(a){for(var b=this.regions,c=0,d=b.length;d>c;c++){var e=b[c];e.page==a&&(e.u=e.x/a.width,e.v=e.y/a.height,e.rotate?(e.u2=(e.x+e.height)/a.width,e.v2=(e.y+e.width)/a.height):(e.u2=(e.x+e.width)/a.width,e.v2=(e.y+e.height)/a.height))}}},l.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},l.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},l.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},l.AtlasPage=function(){},l.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},l.AtlasRegion=function(){},l.AtlasRegion.prototype={page:null,name:null,x:0,y:0,width:0,height:0,u:0,v:0,u2:0,v2:0,offsetX:0,offsetY:0,originalWidth:0,originalHeight:0,index:0,rotate:!1,splits:null,pads:null},l.AtlasReader=function(a){this.lines=a.split(/\r\n|\r|\n/)},l.AtlasReader.prototype={index:0,trim:function(a){return a.replace(/^\s+|\s+$/g,"")},readLine:function(){return this.index>=this.lines.length?null:this.lines[this.index++]},readValue:function(){var a=this.readLine(),b=a.indexOf(":");if(-1==b)throw"Invalid line: "+a;return this.trim(a.substring(b+1))},readTuple:function(a){var b=this.readLine(),c=b.indexOf(":");if(-1==c)throw"Invalid line: "+b;for(var d=0,e=c+1;3>d;d++){var f=b.indexOf(",",e);if(-1==f){if(0==d)throw"Invalid line: "+b;break}a[d]=this.trim(b.substr(e,f-e)),e=f+1}return a[d]=this.trim(b.substring(e)),d+1}},l.AtlasAttachmentLoader=function(a){this.atlas=a},l.AtlasAttachmentLoader.prototype={newAttachment:function(a,b,c){switch(b){case l.AttachmentType.region:var d=this.atlas.findRegion(c);if(!d)throw"Region not found in atlas: "+c+" ("+b+")";var e=new l.RegionAttachment(c);return e.rendererObject=d,e.setUVs(d.u,d.v,d.u2,d.v2,d.rotate),e.regionOffsetX=d.offsetX,e.regionOffsetY=d.offsetY,e.regionWidth=d.width,e.regionHeight=d.height,e.regionOriginalWidth=d.originalWidth,e.regionOriginalHeight=d.originalHeight,e}throw"Unknown attachment type: "+b}},f.AnimCache={},l.Bone.yDown=!0,f.CustomRenderable=function(){f.DisplayObject.call(this)},f.CustomRenderable.prototype=Object.create(f.DisplayObject.prototype),f.CustomRenderable.prototype.constructor=f.CustomRenderable,f.CustomRenderable.prototype.renderCanvas=function(){},f.CustomRenderable.prototype.initWebGL=function(){},f.CustomRenderable.prototype.renderWebGL=function(){},f.BaseTextureCache={},f.texturesToUpdate=[],f.texturesToDestroy=[],f.BaseTexture=function(a){if(f.EventTarget.call(this),this.width=100,this.height=100,this.hasLoaded=!1,this.source=a,a){if(this.source instanceof Image||this.source instanceof HTMLImageElement)if(this.source.complete)this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);else{var b=this;this.source.onload=function(){b.hasLoaded=!0,b.width=b.source.width,b.height=b.source.height,f.texturesToUpdate.push(b),b.dispatchEvent({type:"loaded",content:b}) +}}else this.hasLoaded=!0,this.width=this.source.width,this.height=this.source.height,f.texturesToUpdate.push(this);this._powerOf2=!1}},f.BaseTexture.prototype.constructor=f.BaseTexture,f.BaseTexture.prototype.destroy=function(){this.source instanceof Image&&(this.source.src=null),this.source=null,f.texturesToDestroy.push(this)},f.BaseTexture.fromImage=function(a,b){var c=f.BaseTextureCache[a];if(!c){var d=new Image;b&&(d.crossOrigin=""),d.src=a,c=new f.BaseTexture(d),f.BaseTextureCache[a]=c}return c},f.TextureCache={},f.FrameCache={},f.Texture=function(a,b){if(f.EventTarget.call(this),b||(this.noFrame=!0,b=new f.Rectangle(0,0,1,1)),a instanceof f.Texture&&(a=a.baseTexture),this.baseTexture=a,this.frame=b,this.trim=new f.Point,this.scope=this,a.hasLoaded)this.noFrame&&(b=new f.Rectangle(0,0,a.width,a.height)),this.setFrame(b);else{var c=this;a.addEventListener("loaded",function(){c.onBaseTextureLoaded()})}},f.Texture.prototype.constructor=f.Texture,f.Texture.prototype.onBaseTextureLoaded=function(){var a=this.baseTexture;a.removeEventListener("loaded",this.onLoaded),this.noFrame&&(this.frame=new f.Rectangle(0,0,a.width,a.height)),this.noFrame=!1,this.width=this.frame.width,this.height=this.frame.height,this.scope.dispatchEvent({type:"update",content:this})},f.Texture.prototype.destroy=function(a){a&&this.baseTexture.destroy()},f.Texture.prototype.setFrame=function(a){if(this.frame=a,this.width=a.width,this.height=a.height,a.x+a.width>this.baseTexture.width||a.y+a.height>this.baseTexture.height)throw new Error("Texture Error: frame does not fit inside the base Texture dimensions "+this);this.updateFrame=!0,f.Texture.frameUpdates.push(this)},f.Texture.fromImage=function(a,b){var c=f.TextureCache[a];return c||(c=new f.Texture(f.BaseTexture.fromImage(a,b)),f.TextureCache[a]=c),c},f.Texture.fromFrame=function(a){var b=f.TextureCache[a];if(!b)throw new Error("The frameId '"+a+"' does not exist in the texture cache "+this);return b},f.Texture.fromCanvas=function(a){var b=new f.BaseTexture(a);return new f.Texture(b)},f.Texture.addTextureToCache=function(a,b){f.TextureCache[b]=a},f.Texture.removeTextureFromCache=function(a){var b=f.TextureCache[a];return f.TextureCache[a]=null,b},f.Texture.frameUpdates=[],f.RenderTexture=function(a,b){f.EventTarget.call(this),this.width=a||100,this.height=b||100,this.indetityMatrix=f.mat3.create(),this.frame=new f.Rectangle(0,0,this.width,this.height),f.gl?this.initWebGL():this.initCanvas()},f.RenderTexture.prototype=Object.create(f.Texture.prototype),f.RenderTexture.prototype.constructor=f.RenderTexture,f.RenderTexture.prototype.initWebGL=function(){var a=f.gl;this.glFramebuffer=a.createFramebuffer(),a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),this.glFramebuffer.width=this.width,this.glFramebuffer.height=this.height,this.baseTexture=new f.BaseTexture,this.baseTexture.width=this.width,this.baseTexture.height=this.height,this.baseTexture._glTexture=a.createTexture(),a.bindTexture(a.TEXTURE_2D,this.baseTexture._glTexture),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,this.width,this.height,0,a.RGBA,a.UNSIGNED_BYTE,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),this.baseTexture.isRender=!0,a.bindFramebuffer(a.FRAMEBUFFER,this.glFramebuffer),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.baseTexture._glTexture,0),this.projection=new f.Point(this.width/2,this.height/2),this.render=this.renderWebGL},f.RenderTexture.prototype.resize=function(a,b){if(this.width=a,this.height=b,f.gl){this.projection.x=this.width/2,this.projection.y=this.height/2;var c=f.gl;c.bindTexture(c.TEXTURE_2D,this.baseTexture._glTexture),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,this.width,this.height,0,c.RGBA,c.UNSIGNED_BYTE,null)}else this.frame.width=this.width,this.frame.height=this.height,this.renderer.resize(this.width,this.height)},f.RenderTexture.prototype.initCanvas=function(){this.renderer=new f.CanvasRenderer(this.width,this.height,null,0),this.baseTexture=new f.BaseTexture(this.renderer.view),this.frame=new f.Rectangle(0,0,this.width,this.height),this.render=this.renderCanvas},f.RenderTexture.prototype.renderWebGL=function(a,b,c){var d=f.gl;d.colorMask(!0,!0,!0,!0),d.viewport(0,0,this.width,this.height),d.bindFramebuffer(d.FRAMEBUFFER,this.glFramebuffer),c&&(d.clearColor(0,0,0,0),d.clear(d.COLOR_BUFFER_BIT));var e=a.children,g=a.worldTransform;a.worldTransform=f.mat3.create(),a.worldTransform[4]=-1,a.worldTransform[5]=2*this.projection.y,b&&(a.worldTransform[2]=b.x,a.worldTransform[5]-=b.y),f.visibleCount++,a.vcount=f.visibleCount;for(var h=0,i=e.length;i>h;h++)e[h].updateTransform();var j=a.__renderGroup;j?a==j.root?j.render(this.projection):j.renderSpecific(a,this.projection):(this.renderGroup||(this.renderGroup=new f.WebGLRenderGroup(d)),this.renderGroup.setRenderable(a),this.renderGroup.render(this.projection)),a.worldTransform=g},f.RenderTexture.prototype.renderCanvas=function(a,b,c){var d=a.children;a.worldTransform=f.mat3.create(),b&&(a.worldTransform[2]=b.x,a.worldTransform[5]=b.y);for(var e=0,g=d.length;g>e;e++)d[e].updateTransform();c&&this.renderer.context.clearRect(0,0,this.width,this.height),this.renderer.renderDisplayObject(a),this.renderer.context.setTransform(1,0,0,1,0,0)},f.AssetLoader=function(a,b){f.EventTarget.call(this),this.assetURLs=a,this.crossorigin=b,this.loadersByType={jpg:f.ImageLoader,jpeg:f.ImageLoader,png:f.ImageLoader,gif:f.ImageLoader,json:f.JsonLoader,anim:f.SpineLoader,xml:f.BitmapFontLoader,fnt:f.BitmapFontLoader}},f.AssetLoader.prototype.constructor=f.AssetLoader,f.AssetLoader.prototype.load=function(){var a=this;this.loadCount=this.assetURLs.length;for(var b=0;bh;h++)for(var i=0;d>i;i++,g++){var j=new f.Texture(this.texture,{x:i*a,y:h*b,width:a,height:b});this.frames.push(j),c&&(f.TextureCache[c+"-"+g]=j)}if(this.texture.baseTexture.hasLoaded)this.onLoaded();else{var k=this;this.texture.baseTexture.addEventListener("loaded",function(){k.onLoaded()})}},f.BitmapFontLoader=function(a,b){f.EventTarget.call(this),this.url=a,this.crossorigin=b,this.baseUrl=a.replace(/[^\/]*$/,""),this.texture=null},f.BitmapFontLoader.prototype.constructor=f.BitmapFontLoader,f.BitmapFontLoader.prototype.load=function(){this.ajaxRequest=new XMLHttpRequest;var a=this;this.ajaxRequest.onreadystatechange=function(){a.onXMLLoaded()},this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/xml"),this.ajaxRequest.send(null)},f.BitmapFontLoader.prototype.onXMLLoaded=function(){if(4==this.ajaxRequest.readyState&&(200==this.ajaxRequest.status||-1==window.location.href.indexOf("http"))){var a=this.baseUrl+this.ajaxRequest.responseXML.getElementsByTagName("page")[0].attributes.getNamedItem("file").nodeValue,b=new f.ImageLoader(a,this.crossorigin);this.texture=b.texture.baseTexture;var c={},d=this.ajaxRequest.responseXML.getElementsByTagName("info")[0],e=this.ajaxRequest.responseXML.getElementsByTagName("common")[0];c.font=d.attributes.getNamedItem("face").nodeValue,c.size=parseInt(d.attributes.getNamedItem("size").nodeValue,10),c.lineHeight=parseInt(e.attributes.getNamedItem("lineHeight").nodeValue,10),c.chars={};for(var g=this.ajaxRequest.responseXML.getElementsByTagName("char"),h=0;h x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y + + + pixi.js example 15 - Filters + + + + + + + + + diff --git a/examples/example 15 - Filters/panda.png b/examples/example 15 - Filters/panda.png new file mode 100644 index 0000000..215a4a9 Binary files /dev/null and b/examples/example 15 - Filters/panda.png differ diff --git a/examples/example 15 - Filters/pixi.js b/examples/example 15 - Filters/pixi.js new file mode 100644 index 0000000..6d567a2 --- /dev/null +++ b/examples/example 15 - Filters/pixi.js @@ -0,0 +1,10649 @@ +/** + * @license + * Pixi.JS - v1.3.0 + * Copyright (c) 2012, Mat Groves + * http://goodboydigital.com/ + * + * Compiled: 2013-09-30 + * + * Pixi.JS is licensed under the MIT License. + * http://www.opensource.org/licenses/mit-license.php + */ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +(function(){ + + var root = this; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * @module PIXI + */ +var PIXI = PIXI || {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The Point object represents a location in a two-dimensional coordinate system, where x represents the horizontal axis and y represents the vertical axis. + * + * @class Point + * @constructor + * @param x {Number} position of the point + * @param y {Number} position of the point + */ +PIXI.Point = function(x, y) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; +} + +/** + * Creates a clone of this point + * + * @method clone + * @return {Point} a copy of the point + */ +PIXI.Point.prototype.clone = function() +{ + return new PIXI.Point(this.x, this.y); +} + +// constructor +PIXI.Point.prototype.constructor = PIXI.Point; + + +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. + * + * @class Rectangle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the rectangle + * @param y {Number} The Y coord of the upper-left corner of the rectangle + * @param width {Number} The overall width of this rectangle + * @param height {Number} The overall height of this rectangle + */ +PIXI.Rectangle = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +} + +/** + * Creates a clone of this Rectangle + * + * @method clone + * @return {Rectangle} a copy of the rectangle + */ +PIXI.Rectangle.prototype.clone = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this Rectangle + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this Rectangle + */ +PIXI.Rectangle.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + var x1 = this.x; + if(x >= x1 && x <= x1 + this.width) + { + var y1 = this.y; + + if(y >= y1 && y <= y1 + this.height) + { + return true; + } + } + + return false; +} + +// constructor +PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; + + +/** + * @author Adrien Brault + */ + +/** + * @class Polygon + * @constructor + * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be + * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the + * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are + * Numbers. + */ +PIXI.Polygon = function(points) +{ + //if points isn't an array, use arguments as the array + if(!(points instanceof Array)) + points = Array.prototype.slice.call(arguments); + + //if this is a flat array of numbers, convert it to points + if(typeof points[0] === 'number') { + var p = []; + for(var i = 0, il = points.length; i < il; i+=2) { + p.push( + new PIXI.Point(points[i], points[i + 1]) + ); + } + + points = p; + } + + this.points = points; +} + +/** + * Creates a clone of this polygon + * + * @method clone + * @return {Polygon} a copy of the polygon + */ +PIXI.Polygon.prototype.clone = function() +{ + var points = []; + for (var i=0; i y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + + if(intersect) inside = !inside; + } + + return inside; +} + +// constructor +PIXI.Polygon.prototype.constructor = PIXI.Polygon; + +/** + * @author Chad Engler + */ + +/** + * The Circle object can be used to specify a hit area for displayobjects + * + * @class Circle + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this circle + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this circle + * @param radius {Number} The radius of the circle + */ +PIXI.Circle = function(x, y, radius) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property radius + * @type Number + * @default 0 + */ + this.radius = radius || 0; +} + +/** + * Creates a clone of this Circle instance + * + * @method clone + * @return {Circle} a copy of the polygon + */ +PIXI.Circle.prototype.clone = function() +{ + return new PIXI.Circle(this.x, this.y, this.radius); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this circle + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this polygon + */ +PIXI.Circle.prototype.contains = function(x, y) +{ + if(this.radius <= 0) + return false; + + var dx = (this.x - x), + dy = (this.y - y), + r2 = this.radius * this.radius; + + dx *= dx; + dy *= dy; + + return (dx + dy <= r2); +} + +// constructor +PIXI.Circle.prototype.constructor = PIXI.Circle; + + +/** + * @author Chad Engler + */ + +/** + * The Ellipse object can be used to specify a hit area for displayobjects + * + * @class Ellipse + * @constructor + * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse + * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse + */ +PIXI.Ellipse = function(x, y, width, height) +{ + /** + * @property x + * @type Number + * @default 0 + */ + this.x = x || 0; + + /** + * @property y + * @type Number + * @default 0 + */ + this.y = y || 0; + + /** + * @property width + * @type Number + * @default 0 + */ + this.width = width || 0; + + /** + * @property height + * @type Number + * @default 0 + */ + this.height = height || 0; +} + +/** + * Creates a clone of this Ellipse instance + * + * @method clone + * @return {Ellipse} a copy of the ellipse + */ +PIXI.Ellipse.prototype.clone = function() +{ + return new PIXI.Ellipse(this.x, this.y, this.width, this.height); +} + +/** + * Checks if the x, and y coords passed to this function are contained within this ellipse + * + * @method contains + * @param x {Number} The X coord of the point to test + * @param y {Number} The Y coord of the point to test + * @return {Boolean} if the x/y coords are within this ellipse + */ +PIXI.Ellipse.prototype.contains = function(x, y) +{ + if(this.width <= 0 || this.height <= 0) + return false; + + //normalize the coords to an ellipse with center 0,0 + //and a radius of 0.5 + var normx = ((x - this.x) / this.width) - 0.5, + normy = ((y - this.y) / this.height) - 0.5; + + normx *= normx; + normy *= normy; + + return (normx + normy < 0.25); +} + +PIXI.Ellipse.getBounds = function() +{ + return new PIXI.Rectangle(this.x, this.y, this.width, this.height); +} + +// constructor +PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; + + + +/* + * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV + * you both rock! + */ + +function determineMatrixArrayType() { + PIXI.Matrix = (typeof Float32Array !== 'undefined') ? Float32Array : Array; + return PIXI.Matrix; +} + +determineMatrixArrayType(); + +PIXI.mat3 = {}; + +PIXI.mat3.create = function() +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat3.identity = function(matrix) +{ + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + + return matrix; +} + + +PIXI.mat4 = {}; + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat3.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], + a10 = mat[3], a11 = mat[4], a12 = mat[5], + a20 = mat[6], a21 = mat[7], a22 = mat[8], + + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], + b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], + b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22; + + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; + dest[4] = b10 * a01 + b11 * a11 + b12 * a21; + dest[5] = b10 * a02 + b11 * a12 + b12 * a22; + + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; + dest[7] = b20 * a01 + b21 * a11 + b22 * a21; + dest[8] = b20 * a02 + b21 * a12 + b22 * a22; + + return dest; +} + +PIXI.mat3.clone = function(mat) +{ + var matrix = new PIXI.Matrix(9); + + matrix[0] = mat[0]; + matrix[1] = mat[1]; + matrix[2] = mat[2]; + matrix[3] = mat[3]; + matrix[4] = mat[4]; + matrix[5] = mat[5]; + matrix[6] = mat[6]; + matrix[7] = mat[7]; + matrix[8] = mat[8]; + + return matrix; +} + +PIXI.mat3.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], + a12 = mat[5]; + + mat[1] = mat[3]; + mat[2] = mat[6]; + mat[3] = a01; + mat[5] = mat[7]; + mat[6] = a02; + mat[7] = a12; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[3]; + dest[2] = mat[6]; + dest[3] = mat[1]; + dest[4] = mat[4]; + dest[5] = mat[7]; + dest[6] = mat[2]; + dest[7] = mat[5]; + dest[8] = mat[8]; + return dest; +} + +PIXI.mat3.toMat4 = function (mat, dest) +{ + if (!dest) { dest = PIXI.mat4.create(); } + + dest[15] = 1; + dest[14] = 0; + dest[13] = 0; + dest[12] = 0; + + dest[11] = 0; + dest[10] = mat[8]; + dest[9] = mat[7]; + dest[8] = mat[6]; + + dest[7] = 0; + dest[6] = mat[5]; + dest[5] = mat[4]; + dest[4] = mat[3]; + + dest[3] = 0; + dest[2] = mat[2]; + dest[1] = mat[1]; + dest[0] = mat[0]; + + return dest; +} + + +///// + + +PIXI.mat4.create = function() +{ + var matrix = new PIXI.Matrix(16); + + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 0; + matrix[5] = 1; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = 1; + matrix[11] = 0; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + + return matrix; +} + +PIXI.mat4.transpose = function (mat, dest) +{ + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) + { + var a01 = mat[1], a02 = mat[2], a03 = mat[3], + a12 = mat[6], a13 = mat[7], + a23 = mat[11]; + + mat[1] = mat[4]; + mat[2] = mat[8]; + mat[3] = mat[12]; + mat[4] = a01; + mat[6] = mat[9]; + mat[7] = mat[13]; + mat[8] = a02; + mat[9] = a12; + mat[11] = mat[14]; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[4]; + dest[2] = mat[8]; + dest[3] = mat[12]; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = mat[9]; + dest[7] = mat[13]; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = mat[14]; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +} + +PIXI.mat4.multiply = function (mat, mat2, dest) +{ + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; + var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; + var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; + var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + // Cache only the current line of the second matrix + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[4]; + b1 = mat2[5]; + b2 = mat2[6]; + b3 = mat2[7]; + dest[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[8]; + b1 = mat2[9]; + b2 = mat2[10]; + b3 = mat2[11]; + dest[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = mat2[12]; + b1 = mat2[13]; + b2 = mat2[14]; + b3 = mat2[15]; + dest[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + dest[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + dest[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + dest[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + return dest; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The base class for all objects that are rendered on the screen. + * + * @class DisplayObject + * @constructor + */ +PIXI.DisplayObject = function() +{ + this.last = this; + this.first = this; + /** + * The coordinate of the object relative to the local coordinates of the parent. + * + * @property position + * @type Point + */ + this.position = new PIXI.Point(); + + /** + * The scale factor of the object. + * + * @property scale + * @type Point + */ + this.scale = new PIXI.Point(1,1);//{x:1, y:1}; + + /** + * The pivot point of the displayObject that it rotates around + * + * @property pivot + * @type Point + */ + this.pivot = new PIXI.Point(0,0); + + /** + * The rotation of the object in radians. + * + * @property rotation + * @type Number + */ + this.rotation = 0; + + /** + * The opacity of the object. + * + * @property alpha + * @type Number + */ + this.alpha = 1; + + /** + * The visibility of the object. + * + * @property visible + * @type Boolean + */ + this.visible = true; + + /** + * This is the defined area that will pick up mouse / touch events. It is null by default. + * Setting it is a neat way of optimising the hitTest function that the interactionManager will use (as it will not need to hit test all the children) + * + * @property hitArea + * @type Rectangle|Circle|Ellipse|Polygon + */ + this.hitArea = null; + + /** + * This is used to indicate if the displayObject should display a mouse hand cursor on rollover + * + * @property buttonMode + * @type Boolean + */ + this.buttonMode = false; + + /** + * Can this object be rendered + * + * @property renderable + * @type Boolean + */ + this.renderable = false; + + /** + * [read-only] The display object container that contains this display object. + * + * @property parent + * @type DisplayObjectContainer + * @readOnly + */ + this.parent = null; + + /** + * [read-only] The stage the display object is connected to, or undefined if it is not connected to the stage. + * + * @property stage + * @type Stage + * @readOnly + */ + this.stage = null; + + /** + * [read-only] The multiplied alpha of the displayobject + * + * @property worldAlpha + * @type Number + * @readOnly + */ + this.worldAlpha = 1; + + /** + * [read-only] Whether or not the object is interactive, do not toggle directly! use the `interactive` property + * + * @property _interactive + * @type Boolean + * @readOnly + * @private + */ + this._interactive = false; + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [read-only] Current transform of the object locally + * + * @property localTransform + * @type Mat3 + * @readOnly + * @private + */ + this.localTransform = PIXI.mat3.create()//mat3.identity(); + + /** + * [NYI] Unkown + * + * @property color + * @type Array<> + * @private + */ + this.color = []; + + /** + * [NYI] Holds whether or not this object is dynamic, for rendering optimization + * + * @property dynamic + * @type Boolean + * @private + */ + this.dynamic = true; + + // chach that puppy! + this._sr = 0; + this._cr = 1; + + /* + * MOUSE Callbacks + */ + + /** + * A callback that is used when the users clicks on the displayObject with their mouse + * @method click + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user clicks the mouse down over the sprite + * @method mousedown + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject + * for this callback to be fired the mouse must have been pressed down over the displayObject + * @method mouseup + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject + * for this callback to be fired, The touch must have started over the displayObject + * @method mouseupoutside + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse rolls over the displayObject + * @method mouseover + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the users mouse leaves the displayObject + * @method mouseout + * @param interactionData {InteractionData} + */ + + + /* + * TOUCH Callbacks + */ + + /** + * A callback that is used when the users taps on the sprite with their finger + * basically a touch version of click + * @method tap + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user touch's over the displayObject + * @method touchstart + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases a touch over the displayObject + * @method touchend + * @param interactionData {InteractionData} + */ + + /** + * A callback that is used when the user releases the touch that was over the displayObject + * for this callback to be fired, The touch must have started over the sprite + * @method touchendoutside + * @param interactionData {InteractionData} + */ +} + +// constructor +PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; + +/** + * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default + * Instead of using this function you can now simply set the interactive property to true or false + * + * @method setInteractive + * @param interactive {Boolean} + * @deprecated Simply set the `interactive` property directly + */ +PIXI.DisplayObject.prototype.setInteractive = function(interactive) +{ + this.interactive = interactive; +} + +/** + * Indicates if the sprite will have touch and mouse interactivity. It is false by default + * + * @property interactive + * @type Boolean + * @default false + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { + get: function() { + return this._interactive; + }, + set: function(value) { + this._interactive = value; + + // TODO more to be done here.. + // need to sort out a re-crawl! + if(this.stage)this.stage.dirty = true; + } +}); + +/** + * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. + * In PIXI a regular mask must be a PIXI.Ggraphics object. This allows for much faster masking in canvas as it utilises shape clipping. + * To remove a mask, set this property to null. + * + * @property mask + * @type Graphics + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { + get: function() { + return this._mask; + }, + set: function(value) { + + + if(value) + { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); + this.addFilter(value) + } + else + { + if(this._filters)this.removeFilter(this._filters); + } + + this._filters = value; + } +}); + +/* + * Adds a filter to this displayObject + * + * @method addFilter + * @param mask {Graphics} the graphics object to use as a filter + * @private + */ +PIXI.DisplayObject.prototype.addFilter = function(data) +{ + //if(this.filter)return; + //this.filter = true; + + // insert a filter block.. + // TODO Onject pool thease bad boys.. + var start = new PIXI.FilterBlock(); + var end = new PIXI.FilterBlock(); + + data.start = start; + data.end = end; + + start.data = data; + end.data = data; + + start.first = start.last = this; + end.first = end.last = this; + + start.open = true; + + /* + * insert start + */ + + var childFirst = start + var childLast = start + var nextObject; + var previousObject; + + previousObject = this.first._iPrev; + + if(previousObject) + { + nextObject = previousObject._iNext; + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + } + else + { + nextObject = this; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + + // now insert the end filter block.. + + /* + * insert end filter + */ + var childFirst = end + var childLast = end + var nextObject = null; + var previousObject = null; + + previousObject = this.last; + nextObject = previousObject._iNext; + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + var updateLast = this; + + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = end; + } + updateLast = updateLast.parent; + } + + this.first = start; + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.addFilterBlocks(start, end); + } + +} + +/* + * Removes the filter to this displayObject + * + * @method removeFilter + * @private + */ +PIXI.DisplayObject.prototype.removeFilter = function(data) +{ + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") + // modify the list.. + var startBlock = data.start; + + + var nextObject = startBlock._iNext; + var previousObject = startBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + if(previousObject)previousObject._iNext = nextObject; + + this.first = startBlock._iNext; + + // remove the end filter + var lastBlock = data.end; + + var nextObject = lastBlock._iNext; + var previousObject = lastBlock._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + // this is always true too! + var tempLast = lastBlock._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == lastBlock) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + + // if webGL... + if(this.__renderGroup) + { + this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); + } +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObject.prototype.updateTransform = function() +{ + // TODO OPTIMIZE THIS!! with dirty + if(this.rotation !== this.rotationCache) + { + this.rotationCache = this.rotation; + this._sr = Math.sin(this.rotation); + this._cr = Math.cos(this.rotation); + } + + var localTransform = this.localTransform; + var parentTransform = this.parent.worldTransform; + var worldTransform = this.worldTransform; + //console.log(localTransform) + localTransform[0] = this._cr * this.scale.x; + localTransform[1] = -this._sr * this.scale.y + localTransform[3] = this._sr * this.scale.x; + localTransform[4] = this._cr * this.scale.y; + + // TODO --> do we even need a local matrix??? + + var px = this.pivot.x; + var py = this.pivot.y; + + // Cache the matrix values (makes for huge speed increases!) + var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], + a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], + + b00 = parentTransform[0], b01 = parentTransform[1], b02 = parentTransform[2], + b10 = parentTransform[3], b11 = parentTransform[4], b12 = parentTransform[5]; + + localTransform[2] = a02 + localTransform[5] = a12 + + worldTransform[0] = b00 * a00 + b01 * a10; + worldTransform[1] = b00 * a01 + b01 * a11; + worldTransform[2] = b00 * a02 + b01 * a12 + b02; + + worldTransform[3] = b10 * a00 + b11 * a10; + worldTransform[4] = b10 * a01 + b11 * a11; + worldTransform[5] = b10 * a02 + b11 * a12 + b12; + + // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! + // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); + this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; + +} + +PIXI.visibleCount = 0; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A DisplayObjectContainer represents a collection of display objects. + * It is the base class of all display objects that act as a container for other objects. + * + * @class DisplayObjectContainer + * @extends DisplayObject + * @constructor + */ +PIXI.DisplayObjectContainer = function() +{ + PIXI.DisplayObject.call( this ); + + /** + * [read-only] The of children of this container. + * + * @property children + * @type Array + * @readOnly + */ + this.children = []; +} + +// constructor +PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; + +/** + * Adds a child to the container. + * + * @method addChild + * @param child {DisplayObject} The DisplayObject to add to the container + */ +PIXI.DisplayObjectContainer.prototype.addChild = function(child) +{ + if(child.parent != undefined) + { + + //// COULD BE THIS??? + child.parent.removeChild(child); + // return; + } + + child.parent = this; + + this.children.push(child); + + // update the stage refference.. + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // LINKED LIST // + + // modify the list.. + var childFirst = child.first + var childLast = child.last; + var nextObject; + var previousObject; + + // this could be wrong if there is a filter?? + if(this._filters) + { + previousObject = this.last._iPrev; + } + else + { + previousObject = this.last; + } + + nextObject = previousObject._iNext; + + // always true in this case + // need to make sure the parents last is updated too + var updateLast = this; + var prevLast = previousObject; + + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + +} + +/** + * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown + * + * @method addChildAt + * @param child {DisplayObject} The child to add + * @param index {Number} The index to place the child in + */ +PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) +{ + if(index >= 0 && index <= this.children.length) + { + if(child.parent != undefined) + { + child.parent.removeChild(child); + } + child.parent = this; + + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = this.stage; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + var nextObject; + var previousObject; + + if(index == this.children.length) + { + previousObject = this.last; + var updateLast = this; + var prevLast = this.last; + while(updateLast) + { + if(updateLast.last == prevLast) + { + updateLast.last = child.last; + } + updateLast = updateLast.parent; + } + } + else if(index == 0) + { + previousObject = this; + } + else + { + previousObject = this.children[index-1].last; + } + + nextObject = previousObject._iNext; + + // always true in this case + if(nextObject) + { + nextObject._iPrev = childLast; + childLast._iNext = nextObject; + } + + childFirst._iPrev = previousObject; + previousObject._iNext = childFirst; + + this.children.splice(index, 0, child); + // need to remove any render groups.. + if(this.__renderGroup) + { + // being used by a renderTexture.. if it exists then it must be from a render texture; + if(child.__renderGroup)child.__renderGroup.removeDisplayObjectAndChildren(child); + // add them to the new render group.. + this.__renderGroup.addDisplayObjectAndChildren(child); + } + + } + else + { + throw new Error(child + " The index "+ index +" supplied is out of bounds " + this.children.length); + } +} + +/** + * [NYI] Swaps the depth of 2 displayObjects + * + * @method swapChildren + * @param child {DisplayObject} + * @param child2 {DisplayObject} + * @private + */ +PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) +{ + /* + * this funtion needs to be recoded.. + * can be done a lot faster.. + */ + return; + + // need to fix this function :/ + /* + // TODO I already know this?? + var index = this.children.indexOf( child ); + var index2 = this.children.indexOf( child2 ); + + if ( index !== -1 && index2 !== -1 ) + { + // cool + + /* + if(this.stage) + { + // this is to satisfy the webGL batching.. + // TODO sure there is a nicer way to achieve this! + this.stage.__removeChild(child); + this.stage.__removeChild(child2); + + this.stage.__addChild(child); + this.stage.__addChild(child2); + } + + // swap the positions.. + this.children[index] = child2; + this.children[index2] = child; + + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + }*/ +} + +/** + * Returns the Child at the specified index + * + * @method getChildAt + * @param index {Number} The index to get the child from + */ +PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) +{ + if(index >= 0 && index < this.children.length) + { + return this.children[index]; + } + else + { + throw new Error(child + " Both the supplied DisplayObjects must be a child of the caller " + this); + } +} + +/** + * Removes a child from the container. + * + * @method removeChild + * @param child {DisplayObject} The DisplayObject to remove + */ +PIXI.DisplayObjectContainer.prototype.removeChild = function(child) +{ + var index = this.children.indexOf( child ); + if ( index !== -1 ) + { + // unlink // + // modify the list.. + var childFirst = child.first; + var childLast = child.last; + + var nextObject = childLast._iNext; + var previousObject = childFirst._iPrev; + + if(nextObject)nextObject._iPrev = previousObject; + previousObject._iNext = nextObject; + + if(this.last == childLast) + { + var tempLast = childFirst._iPrev; + // need to make sure the parents last is updated too + var updateLast = this; + while(updateLast.last == childLast.last) + { + updateLast.last = tempLast; + updateLast = updateLast.parent; + if(!updateLast)break; + } + } + + childLast._iNext = null; + childFirst._iPrev = null; + + // update the stage reference.. + if(this.stage) + { + var tmpChild = child; + do + { + if(tmpChild.interactive)this.stage.dirty = true; + tmpChild.stage = null; + tmpChild = tmpChild._iNext; + } + while(tmpChild) + } + + // webGL trim + if(child.__renderGroup) + { + child.__renderGroup.removeDisplayObjectAndChildren(child); + } + + child.parent = undefined; + this.children.splice( index, 1 ); + } + else + { + throw new Error(child + " The supplied DisplayObject must be a child of the caller " + this); + } +} + +/* + * Updates the container's children's transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.DisplayObjectContainer.prototype.updateTransform = function() +{ + if(!this.visible)return; + + PIXI.DisplayObject.prototype.updateTransform.call( this ); + + for(var i=0,j=this.children.length; i} an array of {Texture} objects that make up the animation + */ +PIXI.MovieClip = function(textures) +{ + PIXI.Sprite.call(this, textures[0]); + + /** + * The array of textures that make up the animation + * + * @property textures + * @type Array + */ + this.textures = textures; + + /** + * The speed that the MovieClip will play at. Higher is faster, lower is slower + * + * @property animationSpeed + * @type Number + * @default 1 + */ + this.animationSpeed = 1; + + /** + * Whether or not the movie clip repeats after playing. + * + * @property loop + * @type Boolean + * @default true + */ + this.loop = true; + + /** + * Function to call when a MovieClip finishes playing + * + * @property onComplete + * @type Function + */ + this.onComplete = null; + + /** + * [read-only] The index MovieClips current frame (this may not have to be a whole number) + * + * @property currentFrame + * @type Number + * @default 0 + * @readOnly + */ + this.currentFrame = 0; + + /** + * [read-only] Indicates if the MovieClip is currently playing + * + * @property playing + * @type Boolean + * @readOnly + */ + this.playing = false; +} + +// constructor +PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); +PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; + +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + +/** + * Stops the MovieClip + * + * @method stop + */ +PIXI.MovieClip.prototype.stop = function() +{ + this.playing = false; +} + +/** + * Plays the MovieClip + * + * @method play + */ +PIXI.MovieClip.prototype.play = function() +{ + this.playing = true; +} + +/** + * Stops the MovieClip and goes to a specific frame + * + * @method gotoAndStop + * @param frameNumber {Number} frame index to stop at + */ +PIXI.MovieClip.prototype.gotoAndStop = function(frameNumber) +{ + this.playing = false; + this.currentFrame = frameNumber; + var round = (this.currentFrame + 0.5) | 0; + this.setTexture(this.textures[round % this.textures.length]); +} + +/** + * Goes to a specific frame and begins playing the MovieClip + * + * @method gotoAndPlay + * @param frameNumber {Number} frame index to start at + */ +PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) +{ + this.currentFrame = frameNumber; + this.playing = true; +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.MovieClip.prototype.updateTransform = function() +{ + PIXI.Sprite.prototype.updateTransform.call(this); + + if(!this.playing)return; + + this.currentFrame += this.animationSpeed; + + var round = (this.currentFrame + 0.5) | 0; + + if(this.loop || round < this.textures.length) + { + this.setTexture(this.textures[round % this.textures.length]); + } + else if(round >= this.textures.length) + { + this.gotoAndStop(this.textures.length - 1); + if(this.onComplete) + { + this.onComplete(); + } + } +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + + +PIXI.FilterBlock = function() +{ + this.visible = true; + this.renderable = true; +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} + + +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text to split a line you can use "\n" + * + * @class Text + * @extends Sprite + * @constructor + * @param text {String} The copy that you would like the text to display + * @param [style] {Object} The style parameters + * @param [style.font] {String} default "bold 20pt Arial" The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text = function(text, style) +{ + this.canvas = document.createElement("canvas"); + this.context = this.canvas.getContext("2d"); + PIXI.Sprite.call(this, PIXI.Texture.fromCanvas(this.canvas)); + + this.setText(text); + this.setStyle(style); + + this.updateText(); + this.dirty = false; +}; + +// constructor +PIXI.Text.prototype = Object.create(PIXI.Sprite.prototype); +PIXI.Text.prototype.constructor = PIXI.Text; + +/** + * Set the style of the text + * + * @method setStyle + * @param [style] {Object} The style parameters + * @param [style.font="bold 20pt Arial"] {String} The style and size of the font + * @param [style.fill="black"] {Object} A canvas fillstyle that will be used on the text eg "red", "#00FF00" + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + * @param [style.stroke="black"] {String} A canvas fillstyle that will be used on the text stroke eg "blue", "#FCFF00" + * @param [style.strokeThickness=0] {Number} A number that represents the thickness of the stroke. Default is 0 (no stroke) + * @param [style.wordWrap=false] {Boolean} Indicates if word wrap should be used + * @param [style.wordWrapWidth=100] {Number} The width at which text will wrap + */ +PIXI.Text.prototype.setStyle = function(style) +{ + style = style || {}; + style.font = style.font || "bold 20pt Arial"; + style.fill = style.fill || "black"; + style.align = style.align || "left"; + style.stroke = style.stroke || "black"; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 + style.strokeThickness = style.strokeThickness || 0; + style.wordWrap = style.wordWrap || false; + style.wordWrapWidth = style.wordWrapWidth || 100; + this.style = style; + this.dirty = true; +}; + +/** + * Set the copy for the text object. To split a line you can use "\n" + * + * @methos setText + * @param {String} text The copy that you would like the text to display + */ +PIXI.Text.prototype.setText = function(text) +{ + this.text = text.toString() || " "; + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.Text.prototype.updateText = function() +{ + this.context.font = this.style.font; + + var outputText = this.text; + + // word wrap + // preserve original text + if(this.style.wordWrap)outputText = this.wordWrap(this.text); + + //split text into lines + var lines = outputText.split(/(?:\r\n|\r|\n)/); + + //calculate text width + var lineWidths = []; + var maxLineWidth = 0; + for (var i = 0; i < lines.length; i++) + { + var lineWidth = this.context.measureText(lines[i]).width; + lineWidths[i] = lineWidth; + maxLineWidth = Math.max(maxLineWidth, lineWidth); + } + this.canvas.width = maxLineWidth + this.style.strokeThickness; + + //calculate text height + var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; + this.canvas.height = lineHeight * lines.length; + + //set canvas text styles + this.context.fillStyle = this.style.fill; + this.context.font = this.style.font; + + this.context.strokeStyle = this.style.stroke; + this.context.lineWidth = this.style.strokeThickness; + + this.context.textBaseline = "top"; + + //draw lines line by line + for (i = 0; i < lines.length; i++) + { + var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); + + if(this.style.align == "right") + { + linePosition.x += maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + linePosition.x += (maxLineWidth - lineWidths[i]) / 2; + } + + if(this.style.stroke && this.style.strokeThickness) + { + this.context.strokeText(lines[i], linePosition.x, linePosition.y); + } + + if(this.style.fill) + { + this.context.fillText(lines[i], linePosition.x, linePosition.y); + } + } + + this.updateTexture(); +}; + +/** + * Updates texture size based on canvas size + * + * @method updateTexture + * @private + */ +PIXI.Text.prototype.updateTexture = function() +{ + this.texture.baseTexture.width = this.canvas.width; + this.texture.baseTexture.height = this.canvas.height; + this.texture.frame.width = this.canvas.width; + this.texture.frame.height = this.canvas.height; + + this._width = this.canvas.width; + this._height = this.canvas.height; + + PIXI.texturesToUpdate.push(this.texture.baseTexture); +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.Text.prototype.updateTransform = function() +{ + if(this.dirty) + { + this.updateText(); + this.dirty = false; + } + + PIXI.Sprite.prototype.updateTransform.call(this); +}; + +/* + * http://stackoverflow.com/users/34441/ellisbben + * great solution to the problem! + * + * @method determineFontHeight + * @param fontStyle {Object} + * @private + */ +PIXI.Text.prototype.determineFontHeight = function(fontStyle) +{ + // build a little reference dictionary so if the font style has been used return a + // cached version... + var result = PIXI.Text.heightCache[fontStyle]; + + if(!result) + { + var body = document.getElementsByTagName("body")[0]; + var dummy = document.createElement("div"); + var dummyText = document.createTextNode("M"); + dummy.appendChild(dummyText); + dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); + body.appendChild(dummy); + + result = dummy.offsetHeight; + PIXI.Text.heightCache[fontStyle] = result; + + body.removeChild(dummy); + } + + return result; +}; + +/** + * A Text Object will apply wordwrap + * + * @method wordWrap + * @param text {String} + * @private + */ +PIXI.Text.prototype.wordWrap = function(text) +{ + // search good wrap position + var searchWrapPos = function(ctx, text, start, end, wrapWidth) + { + var p = Math.floor((end-start) / 2) + start; + if(p == start) { + return 1; + } + + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) + { + if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) + { + return p; + } + else + { + return arguments.callee(ctx, text, p, end, wrapWidth); + } + } + else + { + return arguments.callee(ctx, text, start, p, wrapWidth); + } + }; + + var lineWrap = function(ctx, text, wrapWidth) + { + if(ctx.measureText(text).width <= wrapWidth || text.length < 1) + { + return text; + } + var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); + return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); + }; + + var result = ""; + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) + { + result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; + } + + return result; +}; + +/** + * Destroys this text object + * + * @method destroy + * @param destroyTexture {Boolean} + */ +PIXI.Text.prototype.destroy = function(destroyTexture) +{ + if(destroyTexture) + { + this.texture.destroy(); + } + +}; + +PIXI.Text.heightCache = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" + * You can generate the fnt files using + * http://www.angelcode.com/products/bmfont/ for windows or + * http://www.bmglyph.com/ for mac. + * + * @class BitmapText + * @extends DisplayObjectContainer + * @constructor + * @param text {String} The copy that you would like the text to display + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText = function(text, style) +{ + PIXI.DisplayObjectContainer.call(this); + + this.setText(text); + this.setStyle(style); + this.updateText(); + this.dirty = false + +}; + +// constructor +PIXI.BitmapText.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.BitmapText.prototype.constructor = PIXI.BitmapText; + +/** + * Set the copy for the text object + * + * @method setText + * @param text {String} The copy that you would like the text to display + */ +PIXI.BitmapText.prototype.setText = function(text) +{ + this.text = text || " "; + this.dirty = true; +}; + +/** + * Set the style of the text + * + * @method setStyle + * @param style {Object} The style parameters + * @param style.font {String} The size (optional) and bitmap font id (required) eq "Arial" or "20px Arial" (must have loaded previously) + * @param [style.align="left"] {String} An alignment of the multiline text ("left", "center" or "right") + */ +PIXI.BitmapText.prototype.setStyle = function(style) +{ + style = style || {}; + style.align = style.align || "left"; + this.style = style; + + var font = style.font.split(" "); + this.fontName = font[font.length - 1]; + this.fontSize = font.length >= 2 ? parseInt(font[font.length - 2], 10) : PIXI.BitmapText.fonts[this.fontName].size; + + this.dirty = true; +}; + +/** + * Renders text + * + * @method updateText + * @private + */ +PIXI.BitmapText.prototype.updateText = function() +{ + var data = PIXI.BitmapText.fonts[this.fontName]; + var pos = new PIXI.Point(); + var prevCharCode = null; + var chars = []; + var maxLineWidth = 0; + var lineWidths = []; + var line = 0; + var scale = this.fontSize / data.size; + for(var i = 0; i < this.text.length; i++) + { + var charCode = this.text.charCodeAt(i); + if(/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) + { + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + line++; + + pos.x = 0; + pos.y += data.lineHeight; + prevCharCode = null; + continue; + } + + var charData = data.chars[charCode]; + if(!charData) continue; + + if(prevCharCode && charData[prevCharCode]) + { + pos.x += charData.kerning[prevCharCode]; + } + chars.push({texture:charData.texture, line: line, charCode: charCode, position: new PIXI.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); + pos.x += charData.xAdvance; + + prevCharCode = charCode; + } + + lineWidths.push(pos.x); + maxLineWidth = Math.max(maxLineWidth, pos.x); + + var lineAlignOffsets = []; + for(i = 0; i <= line; i++) + { + var alignOffset = 0; + if(this.style.align == "right") + { + alignOffset = maxLineWidth - lineWidths[i]; + } + else if(this.style.align == "center") + { + alignOffset = (maxLineWidth - lineWidths[i]) / 2; + } + lineAlignOffsets.push(alignOffset); + } + + for(i = 0; i < chars.length; i++) + { + var c = new PIXI.Sprite(chars[i].texture)//PIXI.Sprite.fromFrame(chars[i].charCode); + c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; + c.position.y = chars[i].position.y * scale; + c.scale.x = c.scale.y = scale; + this.addChild(c); + } + + this.width = pos.x * scale; + this.height = (pos.y + data.lineHeight) * scale; +}; + +/** + * Updates the transfor of this object + * + * @method updateTransform + * @private + */ +PIXI.BitmapText.prototype.updateTransform = function() +{ + if(this.dirty) + { + while(this.children.length > 0) + { + this.removeChild(this.getChildAt(0)); + } + this.updateText(); + + this.dirty = false; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + +PIXI.BitmapText.fonts = {}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + /** + * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive + * This manager also supports multitouch. + * + * @class InteractionManager + * @constructor + * @param stage {Stage} The stage to handle interactions + */ +PIXI.InteractionManager = function(stage) +{ + /** + * a refference to the stage + * + * @property stage + * @type Stage + */ + this.stage = stage; + + /** + * the mouse data + * + * @property mouse + * @type InteractionData + */ + this.mouse = new PIXI.InteractionData(); + + /** + * an object that stores current touches (InteractionData) by id reference + * + * @property touchs + * @type Object + */ + this.touchs = {}; + + + + // helpers + this.tempPoint = new PIXI.Point(); + //this.tempMatrix = mat3.create(); + + this.mouseoverEnabled = true; + + //tiny little interactiveData pool! + this.pool = []; + + this.interactiveItems = []; + this.interactionDOMElement = null; + + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + + this.last = 0; +} + +// constructor +PIXI.InteractionManager.prototype.constructor = PIXI.InteractionManager; + +/** + * Collects an interactive sprite recursively to have their interactions managed + * + * @method collectInteractiveSprite + * @param displayObject {DisplayObject} the displayObject to collect + * @param iParent {DisplayObject} + * @private + */ +PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObject, iParent) +{ + var children = displayObject.children; + var length = children.length; + + /// make an interaction tree... {item.__interactiveParent} + for (var i = length-1; i >= 0; i--) + { + var child = children[i]; + +// if(child.visible) { + // push all interactive bits + if(child.interactive) + { + iParent.interactiveChildren = true; + //child.__iParent = iParent; + this.interactiveItems.push(child); + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, child); + } + } + else + { + child.__iParent = null; + + if(child.children.length > 0) + { + this.collectInteractiveSprite(child, iParent); + } + } +// } + } +} + +/** + * Sets the target for event delegation + * + * @method setTarget + * @param target {WebGLRenderer|CanvasRenderer} the renderer to bind events to + * @private + */ +PIXI.InteractionManager.prototype.setTarget = function(target) +{ + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + + if (window.navigator.msPointerEnabled) + { + // time to remove some of that zoom in ja.. + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; + + // DO some window specific touch! + } + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); +} + + +/** + * updates the state of interactive objects + * + * @method update + * @private + */ +PIXI.InteractionManager.prototype.update = function() +{ + if(!this.target)return; + + // frequency of 30fps?? + var now = Date.now(); + var diff = now - this.last; + diff = (diff * 30) / 1000; + if(diff < 1)return; + this.last = now; + // + + // ok.. so mouse events?? + // yes for now :) + // OPTIMSE - how often to check?? + if(this.dirty) + { + this.dirty = false; + + var len = this.interactiveItems.length; + + for (var i=0; i < len; i++) { + this.interactiveItems[i].interactiveChildren = false; + } + + this.interactiveItems = []; + + if(this.stage.interactive)this.interactiveItems.push(this.stage); + // go through and collect all the objects that are interactive.. + this.collectInteractiveSprite(this.stage, this.stage); + } + + // loop through interactive objects! + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + + //if(!item.visible)continue; + + // OPTIMISATION - only calculate every time if the mousemove function exists.. + // OK so.. does the object have any other interactive functions? + // hit-test the clip! + + + if(item.mouseover || item.mouseout || item.buttonMode) + { + // ok so there are some functions so lets hit test it.. + item.__hit = this.hitTest(item, this.mouse); + this.mouse.target = item; + // ok so deal with interactions.. + // loks like there was a hit! + if(item.__hit) + { + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; + + if(!item.__isOver) + { + + if(item.mouseover)item.mouseover(this.mouse); + item.__isOver = true; + } + } + else + { + if(item.__isOver) + { + // roll out! + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } + } + + // ---> + } +} + +/** + * Is called when the mouse moves accross the renderer element + * + * @method onMouseMove + * @param event {Event} The DOM event of the mouse moving + * @private + */ +PIXI.InteractionManager.prototype.onMouseMove = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + // TODO optimize by not check EVERY TIME! maybe half as often? // + var rect = this.interactionDOMElement.getBoundingClientRect(); + + this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); + this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); + + var length = this.interactiveItems.length; + var global = this.mouse.global; + + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousemove) + { + //call the function! + item.mousemove(this.mouse); + } + } +} + +/** + * Is called when the mouse button is pressed down on the renderer element + * + * @method onMouseDown + * @param event {Event} The DOM event of a mouse button being pressed down + * @private + */ +PIXI.InteractionManager.prototype.onMouseDown = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + // loop through inteaction tree... + // hit test each item! -> + // get interactive items under point?? + //stage.__i + var length = this.interactiveItems.length; + var global = this.mouse.global; + + var index = 0; + var parent = this.stage; + + // while + // hit test + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mousedown || item.click) + { + item.__mouseIsDown = true; + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit) + { + //call the function! + if(item.mousedown)item.mousedown(this.mouse); + item.__isDown = true; + + // just the one! + if(!item.interactiveChildren)break; + } + } + } +} + + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + +/** + * Is called when the mouse button is released on the renderer element + * + * @method onMouseUp + * @param event {Event} The DOM event of a mouse button being released + * @private + */ +PIXI.InteractionManager.prototype.onMouseUp = function(event) +{ + this.mouse.originalEvent = event || window.event; //IE uses window.event + + var global = this.mouse.global; + + + var length = this.interactiveItems.length; + var up = false; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.mouseup || item.mouseupoutside || item.click) + { + item.__hit = this.hitTest(item, this.mouse); + + if(item.__hit && !up) + { + //call the function! + if(item.mouseup) + { + item.mouseup(this.mouse); + } + if(item.__isDown) + { + if(item.click)item.click(this.mouse); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.mouseupoutside)item.mouseupoutside(this.mouse); + } + } + + item.__isDown = false; + } + } +} + +/** + * Tests if the current mouse coords hit a sprite + * + * @method hitTest + * @param item {DisplayObject} The displayObject to test for a hit + * @param interactionData {InteractionData} The interactiondata object to update in the case of a hit + * @private + */ +PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) +{ + var global = interactionData.global; + + if(item.vcount !== PIXI.visibleCount)return false; + + var isSprite = (item instanceof PIXI.Sprite), + worldTransform = item.worldTransform, + a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10), + x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; + + interactionData.target = item; + + //a sprite or display object with a hit area defined + if(item.hitArea && item.hitArea.contains) { + if(item.hitArea.contains(x, y)) { + //if(isSprite) + interactionData.target = item; + + return true; + } + + return false; + } + // a sprite with no hitarea defined + else if(isSprite) + { + var width = item.texture.frame.width, + height = item.texture.frame.height, + x1 = -width * item.anchor.x, + y1; + + if(x > x1 && x < x1 + width) + { + y1 = -height * item.anchor.y; + + if(y > y1 && y < y1 + height) + { + // set the target property if a hit is true! + interactionData.target = item + return true; + } + } + } + + var length = item.children.length; + + for (var i = 0; i < length; i++) + { + var tempItem = item.children[i]; + var hit = this.hitTest(tempItem, interactionData); + if(hit) + { + // hmm.. TODO SET CORRECT TARGET? + interactionData.target = item + return true; + } + } + + return false; +} + +/** + * Is called when a touch is moved accross the renderer element + * + * @method onTouchMove + * @param event {Event} The DOM event of a touch moving accross the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchMove = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; + + // update the touch position + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + } + + var length = this.interactiveItems.length; + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + if(item.touchmove)item.touchmove(touchData); + } +} + +/** + * Is called when a touch is started on the renderer element + * + * @method onTouchStart + * @param event {Event} The DOM event of a touch starting on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchStart = function(event) +{ + var rect = this.interactionDOMElement.getBoundingClientRect(); + + var changedTouches = event.changedTouches; + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + + var touchData = this.pool.pop(); + if(!touchData)touchData = new PIXI.InteractionData(); + + touchData.originalEvent = event || window.event; + + this.touchs[touchEvent.identifier] = touchData; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + + if(item.touchstart || item.tap) + { + item.__hit = this.hitTest(item, touchData); + + if(item.__hit) + { + //call the function! + if(item.touchstart)item.touchstart(touchData); + item.__isDown = true; + item.__touchData = touchData; + + if(!item.interactiveChildren)break; + } + } + } + } +} + +/** + * Is called when a touch is ended on the renderer element + * + * @method onTouchEnd + * @param event {Event} The DOM event of a touch ending on the renderer view + * @private + */ +PIXI.InteractionManager.prototype.onTouchEnd = function(event) +{ + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); + var changedTouches = event.changedTouches; + + for (var i=0; i < changedTouches.length; i++) + { + var touchEvent = changedTouches[i]; + var touchData = this.touchs[touchEvent.identifier]; + var up = false; + touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); + touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); + + var length = this.interactiveItems.length; + for (var j = 0; j < length; j++) + { + var item = this.interactiveItems[j]; + var itemTouchData = item.__touchData; // <-- Here! + item.__hit = this.hitTest(item, touchData); + + if(itemTouchData == touchData) + { + // so this one WAS down... + touchData.originalEvent = event || window.event; + // hitTest?? + + if(item.touchend || item.tap) + { + if(item.__hit && !up) + { + if(item.touchend)item.touchend(touchData); + if(item.__isDown) + { + if(item.tap)item.tap(touchData); + } + + if(!item.interactiveChildren)up = true; + } + else + { + if(item.__isDown) + { + if(item.touchendoutside)item.touchendoutside(touchData); + } + } + + item.__isDown = false; + } + + item.__touchData = null; + + } + else + { + + } + } + // remove the touch.. + this.pool.push(touchData); + this.touchs[touchEvent.identifier] = null; + } +} + +/** + * Holds all information related to an Interaction event + * + * @class InteractionData + * @constructor + */ +PIXI.InteractionData = function() +{ + /** + * This point stores the global coords of where the touch/mouse event happened + * + * @property global + * @type Point + */ + this.global = new PIXI.Point(); + + // this is here for legacy... but will remove + this.local = new PIXI.Point(); + + /** + * The target Sprite that was interacted with + * + * @property target + * @type Sprite + */ + this.target; + + /** + * When passed to an event handler, this will be the original DOM Event that was captured + * + * @property originalEvent + * @type Event + */ + this.originalEvent; +} + +/** + * This will return the local coords of the specified displayObject for this InteractionData + * + * @method getLocalPosition + * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off + * @return {Point} A point containing the coords of the InteractionData position relative to the DisplayObject + */ +PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) +{ + var worldTransform = displayObject.worldTransform; + var global = this.global; + + // do a cheeky transform to get the mouse coords; + var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], + a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], + id = 1 / (a00 * a11 + a01 * -a10); + // set the mouse coords... + return new PIXI.Point(a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id, + a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id) +} + +// constructor +PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A Stage represents the root of the display tree. Everything connected to the stage is rendered + * + * @class Stage + * @extends DisplayObjectContainer + * @constructor + * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format + * like: 0xFFFFFF for white + */ +PIXI.Stage = function(backgroundColor) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * [read-only] Current transform of the object based on world (parent) factors + * + * @property worldTransform + * @type Mat3 + * @readOnly + * @private + */ + this.worldTransform = PIXI.mat3.create(); + + /** + * Whether or not the stage is interactive + * + * @property interactive + * @type Boolean + */ + this.interactive = true; + + /** + * The interaction manage for this stage, manages all interactive activity on the stage + * + * @property interactive + * @type InteractionManager + */ + this.interactionManager = new PIXI.InteractionManager(this); + + /** + * Whether the stage is dirty and needs to have interactions updated + * + * @property dirty + * @type Boolean + * @private + */ + this.dirty = true; + + this.__childrenAdded = []; + this.__childrenRemoved = []; + + //the stage is it's own stage + this.stage = this; + + //optimize hit detection a bit + this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); + + this.setBackgroundColor(backgroundColor); + this.worldVisible = true; +} + +// constructor +PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Stage.prototype.constructor = PIXI.Stage; + +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Stage.prototype.updateTransform = function() +{ + this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; + + for(var i=0,j=this.children.length; i> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + +/** + * A polyfill for Function.prototype.bind + * + * @method bind + */ +if (typeof Function.prototype.bind != 'function') { + Function.prototype.bind = (function () { + var slice = Array.prototype.slice; + return function (thisArg) { + var target = this, boundArgs = slice.call(arguments, 1); + + if (typeof target != 'function') throw new TypeError(); + + function bound() { + var args = boundArgs.concat(slice.call(arguments)); + target.apply(this instanceof bound ? this : thisArg, args); + } + + bound.prototype = (function F(proto) { + proto && (F.prototype = proto); + if (!(this instanceof F)) return new F; + })(target.prototype); + + return bound; + }; + })(); +} + +/** + * A wrapper for ajax requests to be handled cross browser + * + * @class AjaxRequest + * @constructor + */ +var AjaxRequest = PIXI.AjaxRequest = function() +{ + var activexmodes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Microsoft.XMLHTTP"] //activeX versions to check for in IE + + if (window.ActiveXObject) + { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) + for (var i=0; i>>>>>>>>") + console.log("_") + var safe = 0; + var tmp = item.first; + console.log(tmp); + + while(tmp._iNext) + { + safe++; + tmp = tmp._iNext; + console.log(tmp); + // console.log(tmp); + + if(safe > 100) + { + console.log("BREAK") + break + } + } +} + + + + + + +/** + * https://github.com/mrdoob/eventtarget.js/ + * THankS mr DOob! + */ + +/** + * Adds event emitter functionality to a class + * + * @class EventTarget + * @example + * function MyEmitter() { + * PIXI.EventTarget.call(this); //mixes in event target stuff + * } + * + * var em = new MyEmitter(); + * em.emit({ type: 'eventName', data: 'some data' }); + */ +PIXI.EventTarget = function () { + + var listeners = {}; + + this.addEventListener = this.on = function ( type, listener ) { + + + if ( listeners[ type ] === undefined ) { + + listeners[ type ] = []; + + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); + } + + }; + + this.dispatchEvent = this.emit = function ( event ) { + + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + + } + + }; + + this.removeEventListener = this.off = function ( type, listener ) { + + var index = listeners[ type ].indexOf( listener ); + + if ( index !== - 1 ) { + + listeners[ type ].splice( index, 1 ); + + } + + }; + +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * This helper function will automatically detect which renderer you should be using. + * WebGL is the preferred renderer as it is a lot fastest. If webGL is not supported by + * the browser then this function will return a canvas renderer + * + * @method autoDetectRenderer + * @static + * @param width {Number} the width of the renderers view + * @param height {Number} the height of the renderers view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias + */ +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) +{ + if(!width)width = 800; + if(!height)height = 600; + + // BORROWED from Mr Doob (mrdoob.com) + var webgl = ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(); + + //console.log(webgl); + if( webgl ) + { + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); + } + + return new PIXI.CanvasRenderer(width, height, view, transparent); +}; + + + +/* + PolyK library + url: http://polyk.ivank.net + Released under MIT licence. + + Copyright (c) 2012 Ivan Kuckir + + 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. + + This is an amazing lib! + + slightly modified by mat groves (matgroves.com); +*/ + +PIXI.PolyK = {}; + +/** + * Triangulates shapes for webGL graphic fills + * + * @method Triangulate + * @namespace PolyK + * @constructor + */ +PIXI.PolyK.Triangulate = function(p) +{ + var sign = true; + + var n = p.length>>1; + if(n<3) return []; + var tgs = []; + var avl = []; + for(var i=0; i 3) + { + var i0 = avl[(i+0)%al]; + var i1 = avl[(i+1)%al]; + var i2 = avl[(i+2)%al]; + + var ax = p[2*i0], ay = p[2*i0+1]; + var bx = p[2*i1], by = p[2*i1+1]; + var cx = p[2*i2], cy = p[2*i2+1]; + + var earFound = false; + if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) + { + earFound = true; + for(var j=0; j 3*al) + { + // need to flip flip reverse it! + // reset! + if(sign) + { + var tgs = []; + avl = []; + for(var i=0; i= 0) && (v >= 0) && (u + v < 1); +} + +/** + * Checks if a shape is convex + * + * @class _convex + * @namespace PolyK + * @private + */ +PIXI.PolyK._convex = function(ax, ay, bx, by, cx, cy, sign) +{ + return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) == sign; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/* + * the default suoer fast shader! + */ + +PIXI.shaderFragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", + "gl_FragColor = gl_FragColor * vColor;", + "}" +]; + +PIXI.shaderVertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + + "uniform vec2 projectionVector;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "void main(void) {", + "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" +]; + +/* + * the triangle strip shader.. + */ + +PIXI.stripShaderFragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float alpha;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));", + "gl_FragColor = gl_FragColor * alpha;", + "}" +]; + + +PIXI.stripShaderVertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec2 aTextureCoord;", + "attribute float aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", + "vTextureCoord = aTextureCoord;", + "vColor = aColor;", + "}" +]; + +/* + * primitive shader.. + */ + +PIXI.primitiveShaderFragmentSrc = [ + "precision mediump float;", + "varying vec4 vColor;", + "void main(void) {", + "gl_FragColor = vColor;", + "}" +]; + +PIXI.primitiveShaderVertexSrc = [ + "attribute vec2 aVertexPosition;", + "attribute vec4 aColor;", + "uniform mat3 translationMatrix;", + "uniform vec2 projectionVector;", + "uniform float alpha;", + "varying vec4 vColor;", + "void main(void) {", + "vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);", + "gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);", + "vColor = aColor * alpha;", + "}" +]; + +PIXI.shaderStack = []; + +PIXI.initPrimitiveShader = function() +{ + var gl = PIXI.gl; + + var shaderProgram = PIXI.compileProgram(PIXI.primitiveShaderVertexSrc, PIXI.primitiveShaderFragmentSrc) + + gl.useProgram(shaderProgram); + + shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); + shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); + + shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); + shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); + + PIXI.primitiveProgram = shaderProgram; + + +} + +PIXI.initDefaultShader = function() +{ + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ +} + +PIXI.initDefaultStripShader = function() +{ + var gl = this.gl; + var shaderProgram = PIXI.compileProgram(PIXI.stripShaderVertexSrc, PIXI.stripShaderFragmentSrc) + + gl.useProgram(shaderProgram); + + shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); + shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); + shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); + shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); + + shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); + shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); + shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); + + PIXI.stripShaderProgram = shaderProgram; +} + +PIXI.CompileVertexShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.VERTEX_SHADER); +} + +PIXI.CompileFragmentShader = function(gl, shaderSrc) +{ + return PIXI._CompileShader(gl, shaderSrc, gl.FRAGMENT_SHADER); +} + +PIXI._CompileShader = function(gl, shaderSrc, shaderType) +{ + var src = shaderSrc.join("\n"); + var shader = gl.createShader(shaderType); + gl.shaderSource(shader, src); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + alert(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +} + + +PIXI.compileProgram = function(vertexSrc, fragmentSrc) +{ + var gl = PIXI.gl; + var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); + var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); + + var shaderProgram = gl.createProgram(); + + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + alert("Could not initialise shaders"); + } + + return shaderProgram; +} + +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); + + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() +{ + var gl = PIXI.gl; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; + + gl.useProgram(shaderProgram); + + PIXI.currentShader = shaderProgram; +} + +PIXI.activatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.primitiveProgram); + + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); +} + +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A set of functions used by the webGL renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.WebGLGraphics = function() +{ + +} + +/** + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param projection {Object} + */ +PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) +{ + var gl = PIXI.gl; + + if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, + buffer:gl.createBuffer(), + indexBuffer:gl.createBuffer()}; + + if(graphics.dirty) + { + graphics.dirty = false; + + if(graphics.clearDirty) + { + graphics.clearDirty = false; + + graphics._webGL.lastIndex = 0; + graphics._webGL.points = []; + graphics._webGL.indices = []; + + } + + PIXI.WebGLGraphics.updateGraphics(graphics); + } + + + PIXI.activatePrimitiveShader(); + + // This could be speeded up fo sure! + var m = PIXI.mat3.clone(graphics.worldTransform); + + PIXI.mat3.transpose(m); + + // set the matrix transform for the + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + + gl.uniformMatrix3fv(PIXI.primitiveProgram.translationMatrix, false, m); + + gl.uniform2f(PIXI.primitiveProgram.projectionVector, projection.x, projection.y); + + gl.uniform1f(PIXI.primitiveProgram.alpha, graphics.worldAlpha); + + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + + // WHY DOES THIS LINE NEED TO BE THERE??? + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + // its not even used.. but need to be set or it breaks? + // only on pc though.. + + gl.vertexAttribPointer(PIXI.primitiveProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 4 * 6, 0); + gl.vertexAttribPointer(PIXI.primitiveProgram.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); + + // set the index buffer! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + + gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + + PIXI.deactivatePrimitiveShader(); + + // return to default shader... +// PIXI.activateShader(PIXI.defaultShader); +} + +/** + * Updates the graphics object + * + * @static + * @private + * @method updateGraphics + * @param graphics {Graphics} + */ +PIXI.WebGLGraphics.updateGraphics = function(graphics) +{ + for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + + if(data.type == PIXI.Graphics.POLY) + { + if(data.fill) + { + if(data.points.length>3) + PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); + } + + if(data.lineWidth > 0) + { + PIXI.WebGLGraphics.buildLine(data, graphics._webGL); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL); + } + else if(data.type == PIXI.Graphics.CIRC || data.type == PIXI.Graphics.ELIP) + { + PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); + } + }; + + graphics._webGL.lastIndex = graphics.graphicsData.length; + + var gl = PIXI.gl; + + graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); + + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); + gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); + + graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); +} + +/** + * Builds a rectangle to draw + * + * @static + * @private + * @method buildRectangle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vertPos = verts.length/6; + + // start + verts.push(x, y); + verts.push(r, g, b, alpha); + + verts.push(x + width, y); + verts.push(r, g, b, alpha); + + verts.push(x , y + height); + verts.push(r, g, b, alpha); + + verts.push(x + width, y + height); + verts.push(r, g, b, alpha); + + // insert 2 dead triangles.. + indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) + } + + if(graphicsData.lineWidth) + { + graphicsData.points = [x, y, + x + width, y, + x + width, y + height, + x, y + height, + x, y]; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a circle to draw + * + * @static + * @private + * @method buildCircle + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) +{ + // --- // + // need to convert points to a nice regular data + // + var rectData = graphicsData.points; + var x = rectData[0]; + var y = rectData[1]; + var width = rectData[2]; + var height = rectData[3]; + + var totalSegs = 40; + var seg = (Math.PI * 2) / totalSegs ; + + if(graphicsData.fill) + { + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var verts = webGLData.points; + var indices = webGLData.indices; + + var vecPos = verts.length/6; + + indices.push(vecPos); + + for (var i=0; i < totalSegs + 1 ; i++) + { + verts.push(x,y, r, g, b, alpha); + + verts.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height, + r, g, b, alpha); + + indices.push(vecPos++, vecPos++); + }; + + indices.push(vecPos-1); + } + + if(graphicsData.lineWidth) + { + graphicsData.points = []; + + for (var i=0; i < totalSegs + 1; i++) + { + graphicsData.points.push(x + Math.sin(seg * i) * width, + y + Math.cos(seg * i) * height) + }; + + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + } + +} + +/** + * Builds a line to draw + * + * @static + * @private + * @method buildLine + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) +{ + // TODO OPTIMISE! + + var wrap = true; + var points = graphicsData.points; + if(points.length == 0)return; + + // get first and last point.. figure out the middle! + var firstPoint = new PIXI.Point( points[0], points[1] ); + var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + // if the first point is the last point - goona have issues :) + if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) + { + points.pop(); + points.pop(); + + lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); + + var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; + var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; + + points.unshift(midPointX, midPointY); + points.push(midPointX, midPointY) + } + + var verts = webGLData.points; + var indices = webGLData.indices; + var length = points.length / 2; + var indexCount = points.length; + var indexStart = verts.length/6; + + // DRAW the Line + var width = graphicsData.lineWidth / 2; + + // sort color + var color = HEXtoRGB(graphicsData.lineColor); + var alpha = graphicsData.lineAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var p1x, p1y, p2x, p2y, p3x, p3y; + var perpx, perpy, perp2x, perp2y, perp3x, perp3y; + var ipx, ipy; + var a1, b1, c1, a2, b2, c2; + var denom, pdist, dist; + + p1x = points[0]; + p1y = points[1]; + + p2x = points[2]; + p2y = points[3]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + // start + verts.push(p1x - perpx , p1y - perpy, + r, g, b, alpha); + + verts.push(p1x + perpx , p1y + perpy, + r, g, b, alpha); + + for (var i = 1; i < length-1; i++) + { + p1x = points[(i-1)*2]; + p1y = points[(i-1)*2 + 1]; + + p2x = points[(i)*2] + p2y = points[(i)*2 + 1] + + p3x = points[(i+1)*2]; + p3y = points[(i+1)*2 + 1]; + + perpx = -(p1y - p2y); + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + perp2x = -(p2y - p3y); + perp2y = p2x - p3x; + + dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); + perp2x /= dist; + perp2y /= dist; + perp2x *= width; + perp2y *= width; + + a1 = (-perpy + p1y) - (-perpy + p2y); + b1 = (-perpx + p2x) - (-perpx + p1x); + c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); + a2 = (-perp2y + p3y) - (-perp2y + p2y); + b2 = (-perp2x + p2x) - (-perp2x + p3x); + c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); + + denom = a1*b2 - a2*b1; + + if (denom == 0) { + denom+=1; + } + + px = (b1*c2 - b2*c1)/denom; + py = (a2*c1 - a1*c2)/denom; + + pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); + + if(pdist > 140 * 140) + { + perp3x = perpx - perp2x; + perp3y = perpy - perp2y; + + dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); + perp3x /= dist; + perp3y /= dist; + perp3x *= width; + perp3y *= width; + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x + perp3x, p2y +perp3y); + verts.push(r, g, b, alpha); + + verts.push(p2x - perp3x, p2y -perp3y); + verts.push(r, g, b, alpha); + + indexCount++; + } + else + { + verts.push(px , py); + verts.push(r, g, b, alpha); + + verts.push(p2x - (px-p2x), p2y - (py - p2y)); + verts.push(r, g, b, alpha); + } + } + + p1x = points[(length-2)*2] + p1y = points[(length-2)*2 + 1] + + p2x = points[(length-1)*2] + p2y = points[(length-1)*2 + 1] + + perpx = -(p1y - p2y) + perpy = p1x - p2x; + + dist = Math.sqrt(perpx*perpx + perpy*perpy); + perpx /= dist; + perpy /= dist; + perpx *= width; + perpy *= width; + + verts.push(p2x - perpx , p2y - perpy) + verts.push(r, g, b, alpha); + + verts.push(p2x + perpx , p2y + perpy) + verts.push(r, g, b, alpha); + + indices.push(indexStart); + + for (var i=0; i < indexCount; i++) + { + indices.push(indexStart++); + }; + + indices.push(indexStart-1); +} + +/** + * Builds a polygon to draw + * + * @static + * @private + * @method buildPoly + * @param graphics {Graphics} + * @param webGLData {Object} + */ +PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) +{ + var points = graphicsData.points; + if(points.length < 6)return; + + // get first and last point.. figure out the middle! + var verts = webGLData.points; + var indices = webGLData.indices; + + var length = points.length / 2; + + // sort color + var color = HEXtoRGB(graphicsData.fillColor); + var alpha = graphicsData.fillAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + var triangles = PIXI.PolyK.Triangulate(points); + + var vertPos = verts.length / 6; + + for (var i=0; i < triangles.length; i+=3) + { + indices.push(triangles[i] + vertPos); + indices.push(triangles[i] + vertPos); + indices.push(triangles[i+1] + vertPos); + indices.push(triangles[i+2] +vertPos); + indices.push(triangles[i+2] + vertPos); + }; + + for (var i = 0; i < length; i++) + { + verts.push(points[i * 2], points[i * 2 + 1], + r, g, b, alpha); + }; +} + +function HEXtoRGB(hex) { + return [(hex >> 16 & 0xFF) / 255, ( hex >> 8 & 0xFF) / 255, (hex & 0xFF)/ 255]; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1); + +// an instance of the gl context.. +// only one at the moment :/ +PIXI.gl; + +/** + * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer + * should be used for browsers support webGL. This Render works by automatically managing webGLBatchs. + * So no need for Sprite Batch's or Sprite Cloud's + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class WebGLRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) + * + */ +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) +{ + // do a catch.. only 1 webGL renderer.. + + this.transparent = !!transparent; + + this.width = width || 800; + this.height = height || 600; + + this.view = view || document.createElement( 'canvas' ); + this.view.width = this.width; + this.view.height = this.height; + + // deal with losing context.. + var scope = this; + this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) + this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) + + this.batchs = []; + + try + { + PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { + alpha: this.transparent, + antialias:!!antialias, // SPEED UP?? + premultipliedAlpha:false, + stencil:true + }); + } + catch (e) + { + throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); + } + + PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); + PIXI.initDefaultStripShader(); + + +// PIXI.activateDefaultShader(); + + var gl = this.gl; + PIXI.WebGLRenderer.gl = gl; + + this.batch = new PIXI.WebGLBatch(gl); + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); + + gl.enable(gl.BLEND); + gl.colorMask(true, true, true, this.transparent); + + PIXI.projection = new PIXI.Point(400, 300); + + this.resize(this.width, this.height); + this.contextLost = false; + + PIXI.activateShader(PIXI.defaultShader); + + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + +} + +// constructor +PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; + +/** + * Gets a new WebGLBatch from the pool + * + * @static + * @method getBatch + * @return {WebGLBatch} + * @private + */ +PIXI.WebGLRenderer.getBatch = function() +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(PIXI.WebGLRenderer.gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * Puts a batch back into the pool + * + * @static + * @method returnBatch + * @param batch {WebGLBatch} The batch to return + * @private + */ +PIXI.WebGLRenderer.returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * Renders the stage to its webGL view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.WebGLRenderer.prototype.render = function(stage) +{ + if(this.contextLost)return; + + + // if rendering a new stage clear the batchs.. + if(this.__stage !== stage) + { + // TODO make this work + // dont think this is needed any more? + this.__stage = stage; + this.stageRenderGroup.setRenderable(stage); + } + + // TODO not needed now... + // update children if need be + // best to remove first! + /*for (var i=0; i < stage.__childrenRemoved.length; i++) + { + var group = stage.__childrenRemoved[i].__renderGroup + if(group)group.removeDisplayObject(stage.__childrenRemoved[i]); + }*/ + + // update any textures + PIXI.WebGLRenderer.updateTextures(); + + // update the scene graph + PIXI.visibleCount++; + stage.updateTransform(); + + var gl = this.gl; + + // -- Does this need to be set every frame? -- // + gl.colorMask(true, true, true, this.transparent); + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); + gl.clear(gl.COLOR_BUFFER_BIT); + + // HACK TO TEST + + this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; + this.stageRenderGroup.render(PIXI.projection); + + // interaction + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // after rendering lets confirm all frames that have been uodated.. + if(PIXI.Texture.frameUpdates.length > 0) + { + for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) + { + PIXI.Texture.frameUpdates[i].updateFrame = false; + }; + + PIXI.Texture.frameUpdates = []; + } +} + +/** + * Updates the textures loaded into this webgl renderer + * + * @static + * @method updateTextures + * @private + */ +PIXI.WebGLRenderer.updateTextures = function() +{ + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; +} + +/** + * Updates a loaded webgl texture + * + * @static + * @method updateTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.updateTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(!texture._glTexture) + { + texture._glTexture = gl.createTexture(); + } + + if(texture.hasLoaded) + { + gl.bindTexture(gl.TEXTURE_2D, texture._glTexture); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + + // reguler... + + if(!texture._powerOf2) + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + } + + gl.bindTexture(gl.TEXTURE_2D, null); + } +} + +/** + * Destroys a loaded webgl texture + * + * @method destroyTexture + * @param texture {Texture} The texture to update + * @private + */ +PIXI.WebGLRenderer.destroyTexture = function(texture) +{ + //TODO break this out into a texture manager... + var gl = PIXI.gl; + + if(texture._glTexture) + { + texture._glTexture = gl.createTexture(); + gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + } +} + +/** + * resizes the webGL view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the webGL view + * @param height {Number} the new height of the webGL view + */ +PIXI.WebGLRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; + + this.gl.viewport(0, 0, this.width, this.height); + + //var projectionMatrix = this.projectionMatrix; + + PIXI.projection.x = this.width/2; + PIXI.projection.y = this.height/2; + +// projectionMatrix[0] = 2/this.width; +// projectionMatrix[5] = -2/this.height; +// projectionMatrix[12] = -1; +// projectionMatrix[13] = 1; +} + +/** + * Handles a lost webgl context + * + * @method handleContextLost + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextLost = function(event) +{ + event.preventDefault(); + this.contextLost = true; +} + +/** + * Handles a restored webgl context + * + * @method handleContextRestored + * @param event {Event} + * @private + */ +PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) +{ + this.gl = this.view.getContext("experimental-webgl", { + alpha: true + }); + + this.initShaders(); + + for(var key in PIXI.TextureCache) + { + var texture = PIXI.TextureCache[key].baseTexture; + texture._glTexture = null; + PIXI.WebGLRenderer.updateTexture(texture); + }; + + for (var i=0; i < this.batchs.length; i++) + { + this.batchs[i].restoreLostContext(this.gl)// + this.batchs[i].dirty = true; + }; + + PIXI._restoreBatchs(this.gl); + + this.contextLost = false; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI._batchs = []; + +/** + * @private + */ +PIXI._getBatch = function(gl) +{ + if(PIXI._batchs.length == 0) + { + return new PIXI.WebGLBatch(gl); + } + else + { + return PIXI._batchs.pop(); + } +} + +/** + * @private + */ +PIXI._returnBatch = function(batch) +{ + batch.clean(); + PIXI._batchs.push(batch); +} + +/** + * @private + */ +PIXI._restoreBatchs = function(gl) +{ + for (var i=0; i < PIXI._batchs.length; i++) + { + PIXI._batchs[i].restoreLostContext(gl); + }; +} + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be grouped into a batch. + * All the sprites in a batch can then be drawn in one go by the GPU which is hugely efficient. ALL sprites + * in the webGL renderer are added to a batch even if the batch only contains one sprite. Batching is handled + * automatically by the webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @constructor + * @param gl {WebGLContext} an instance of the webGL context + */ +PIXI.WebGLBatch = function(gl) +{ + this.gl = gl; + + this.size = 0; + + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); + this.blendMode = PIXI.blendModes.NORMAL; + this.dynamicSize = 1; +} + +// constructor +PIXI.WebGLBatch.prototype.constructor = PIXI.WebGLBatch; + +/** + * Cleans the batch so that is can be returned to an object pool and reused + * + * @method clean + */ +PIXI.WebGLBatch.prototype.clean = function() +{ + this.verticies = []; + this.uvs = []; + this.indices = []; + this.colors = []; + this.dynamicSize = 1; + this.texture = null; + this.last = null; + this.size = 0; + this.head; + this.tail; +} + +/** + * Recreates the buffers in the event of a context loss + * + * @method restoreLostContext + * @param gl {WebGLContext} + */ +PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) +{ + this.gl = gl; + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.uvBuffer = gl.createBuffer(); + this.colorBuffer = gl.createBuffer(); +} + +/** + * inits the batch's texture and blend mode based if the supplied sprite + * + * @method init + * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with + * the same base texture and blend mode will be allowed to be added to this batch + */ +PIXI.WebGLBatch.prototype.init = function(sprite) +{ + sprite.batch = this; + this.dirty = true; + this.blendMode = sprite.blendMode; + this.texture = sprite.texture.baseTexture; + this.head = sprite; + this.tail = sprite; + this.size = 1; + + this.growBatch(); +} + +/** + * inserts a sprite before the specified sprite + * + * @method insertBefore + * @param sprite {Sprite} the sprite to be added + * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite + */ +PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + var tempPrev = nextSprite.__prev; + nextSprite.__prev = sprite; + sprite.__next = nextSprite; + + if(tempPrev) + { + sprite.__prev = tempPrev; + tempPrev.__next = sprite; + } + else + { + this.head = sprite; + } +} + +/** + * inserts a sprite after the specified sprite + * + * @method insertAfter + * @param sprite {Sprite} the sprite to be added + * @param previousSprite {Sprite} the first sprite will be inserted after this sprite + */ +PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) +{ + this.size++; + + sprite.batch = this; + this.dirty = true; + + var tempNext = previousSprite.__next; + previousSprite.__next = sprite; + sprite.__prev = previousSprite; + + if(tempNext) + { + sprite.__next = tempNext; + tempNext.__prev = sprite; + } + else + { + this.tail = sprite + } +} + +/** + * removes a sprite from the batch + * + * @method remove + * @param sprite {Sprite} the sprite to be removed + */ +PIXI.WebGLBatch.prototype.remove = function(sprite) +{ + this.size--; + + if(this.size == 0) + { + sprite.batch = null; + sprite.__prev = null; + sprite.__next = null; + return; + } + + if(sprite.__prev) + { + sprite.__prev.__next = sprite.__next; + } + else + { + this.head = sprite.__next; + this.head.__prev = null; + } + + if(sprite.__next) + { + sprite.__next.__prev = sprite.__prev; + } + else + { + this.tail = sprite.__prev; + this.tail.__next = null + } + + sprite.batch = null; + sprite.__next = null; + sprite.__prev = null; + this.dirty = true; +} + +/** + * Splits the batch into two with the specified sprite being the start of the new batch. + * + * @method split + * @param sprite {Sprite} the sprite that indicates where the batch should be split + * @return {WebGLBatch} the new batch + */ +PIXI.WebGLBatch.prototype.split = function(sprite) +{ + this.dirty = true; + + var batch = new PIXI.WebGLBatch(this.gl); + batch.init(sprite); + batch.texture = this.texture; + batch.tail = this.tail; + + this.tail = sprite.__prev; + this.tail.__next = null; + + sprite.__prev = null; + // return a splite batch! + + // TODO this size is wrong! + // need to recalculate :/ problem with a linked list! + // unless it gets calculated in the "clean"? + + // need to loop through items as there is no way to know the length on a linked list :/ + var tempSize = 0; + while(sprite) + { + tempSize++; + sprite.batch = batch; + sprite = sprite.__next; + } + + batch.size = tempSize; + this.size -= tempSize; + + return batch; +} + +/** + * Merges two batchs together + * + * @method merge + * @param batch {WebGLBatch} the batch that will be merged + */ +PIXI.WebGLBatch.prototype.merge = function(batch) +{ + this.dirty = true; + + this.tail.__next = batch.head; + batch.head.__prev = this.tail; + + this.size += batch.size; + + this.tail = batch.tail; + + var sprite = batch.head; + while(sprite) + { + sprite.batch = this; + sprite = sprite.__next; + } +} + +/** + * Grows the size of the batch. As the elements in the batch cannot have a dynamic size this + * function is used to increase the size of the batch. It also creates a little extra room so + * that the batch does not need to be resized every time a sprite is added + * + * @method growBatch + */ +PIXI.WebGLBatch.prototype.growBatch = function() +{ + var gl = this.gl; + if( this.size == 1) + { + this.dynamicSize = 1; + } + else + { + this.dynamicSize = this.size * 1.5 + } + // grow verts + this.verticies = new Float32Array(this.dynamicSize * 8); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); + + this.uvs = new Float32Array( this.dynamicSize * 8 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); + + this.dirtyUVS = true; + + this.colors = new Float32Array( this.dynamicSize * 4 ); + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); + + this.dirtyColors = true; + + this.indices = new Uint16Array(this.dynamicSize * 6); + var length = this.indices.length/6; + + for (var i=0; i < length; i++) + { + var index2 = i * 6; + var index3 = i * 4; + this.indices[index2 + 0] = index3 + 0; + this.indices[index2 + 1] = index3 + 1; + this.indices[index2 + 2] = index3 + 2; + this.indices[index2 + 3] = index3 + 0; + this.indices[index2 + 4] = index3 + 2; + this.indices[index2 + 5] = index3 + 3; + }; + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); +} + +/** + * Refresh's all the data in the batch and sync's it with the webGL buffers + * + * @method refresh + */ +PIXI.WebGLBatch.prototype.refresh = function() +{ + var gl = this.gl; + + if (this.dynamicSize < this.size) + { + this.growBatch(); + } + + var indexRun = 0; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index; + var a, b, c, d, tx, ty; + + var displayObject = this.head; + + while(displayObject) + { + index = indexRun * 8; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + this.uvs[index + 0] = frame.x / tw; + this.uvs[index +1] = frame.y / th; + + this.uvs[index +2] = (frame.x + frame.width) / tw; + this.uvs[index +3] = frame.y / th; + + this.uvs[index +4] = (frame.x + frame.width) / tw; + this.uvs[index +5] = (frame.y + frame.height) / th; + + this.uvs[index +6] = frame.x / tw; + this.uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + + colorIndex = indexRun * 4; + this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; + + displayObject = displayObject.__next; + + indexRun ++; + } + + this.dirtyUVS = true; + this.dirtyColors = true; +} + +/** + * Updates all the relevant geometry and uploads the data to the GPU + * + * @method update + */ +PIXI.WebGLBatch.prototype.update = function() +{ + var gl = this.gl; + var worldTransform, width, height, aX, aY, w0, w1, h0, h1, index, index2, index3 + + var a, b, c, d, tx, ty; + + var indexRun = 0; + + var displayObject = this.head; + + while(displayObject) + { + if(displayObject.vcount === PIXI.visibleCount) + { + width = displayObject.texture.frame.width; + height = displayObject.texture.frame.height; + + // TODO trim?? + aX = displayObject.anchor.x;// - displayObject.texture.trim.x + aY = displayObject.anchor.y; //- displayObject.texture.trim.y + w0 = width * (1-aX); + w1 = width * -aX; + + h0 = height * (1-aY); + h1 = height * -aY; + + index = indexRun * 8; + + worldTransform = displayObject.worldTransform; + + a = worldTransform[0]; + b = worldTransform[3]; + c = worldTransform[1]; + d = worldTransform[4]; + tx = worldTransform[2]; + ty = worldTransform[5]; + + this.verticies[index + 0 ] = a * w1 + c * h1 + tx; + this.verticies[index + 1 ] = d * h1 + b * w1 + ty; + + this.verticies[index + 2 ] = a * w0 + c * h1 + tx; + this.verticies[index + 3 ] = d * h1 + b * w0 + ty; + + this.verticies[index + 4 ] = a * w0 + c * h0 + tx; + this.verticies[index + 5 ] = d * h0 + b * w0 + ty; + + this.verticies[index + 6] = a * w1 + c * h0 + tx; + this.verticies[index + 7] = d * h0 + b * w1 + ty; + + if(displayObject.updateFrame || displayObject.texture.updateFrame) + { + this.dirtyUVS = true; + + var texture = displayObject.texture; + + var frame = texture.frame; + var tw = texture.baseTexture.width; + var th = texture.baseTexture.height; + + this.uvs[index + 0] = frame.x / tw; + this.uvs[index +1] = frame.y / th; + + this.uvs[index +2] = (frame.x + frame.width) / tw; + this.uvs[index +3] = frame.y / th; + + this.uvs[index +4] = (frame.x + frame.width) / tw; + this.uvs[index +5] = (frame.y + frame.height) / th; + + this.uvs[index +6] = frame.x / tw; + this.uvs[index +7] = (frame.y + frame.height) / th; + + displayObject.updateFrame = false; + } + + // TODO this probably could do with some optimisation.... + if(displayObject.cacheAlpha != displayObject.worldAlpha) + { + displayObject.cacheAlpha = displayObject.worldAlpha; + + var colorIndex = indexRun * 4; + this.colors[colorIndex] = this.colors[colorIndex + 1] = this.colors[colorIndex + 2] = this.colors[colorIndex + 3] = displayObject.worldAlpha; + this.dirtyColors = true; + } + } + else + { + index = indexRun * 8; + + this.verticies[index + 0 ] = 0; + this.verticies[index + 1 ] = 0; + + this.verticies[index + 2 ] = 0; + this.verticies[index + 3 ] = 0; + + this.verticies[index + 4 ] = 0; + this.verticies[index + 5 ] = 0; + + this.verticies[index + 6] = 0; + this.verticies[index + 7] = 0; + } + + indexRun++; + displayObject = displayObject.__next; + } +} + +/** + * Draws the batch to the frame buffer + * + * @method render + */ +PIXI.WebGLBatch.prototype.render = function(start, end) +{ + start = start || 0; + + if(end == undefined)end = this.size; + + if(this.dirty) + { + this.refresh(); + this.dirty = false; + } + + if (this.size == 0)return; + + this.update(); + var gl = this.gl; + + //TODO optimize this! + + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); + + // update the verts.. + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + // ok.. + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) + gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); + + if(this.dirtyUVS) + { + this.dirtyUVS = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvs); + } + + gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this.texture._glTexture); + + // update color! + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + + if(this.dirtyColors) + { + this.dirtyColors = false; + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.colors); + } + + gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + var len = end - start; + + // DRAW THAT this! + gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * A WebGLBatch Enables a group of sprites to be drawn using the same settings. + * if a group of sprites all have the same baseTexture and blendMode then they can be + * grouped into a batch. All the sprites in a batch can then be drawn in one go by the + * GPU which is hugely efficient. ALL sprites in the webGL renderer are added to a batch + * even if the batch only contains one sprite. Batching is handled automatically by the + * webGL renderer. A good tip is: the smaller the number of batchs there are, the faster + * the webGL renderer will run. + * + * @class WebGLBatch + * @contructor + * @param gl {WebGLContext} An instance of the webGL context + */ +PIXI.WebGLRenderGroup = function(gl) +{ + this.gl = gl; + this.root; + + this.backgroundColor; + this.batchs = []; + this.toRemove = []; +} + +// constructor +PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; + +/** + * Add a display object to the webgl renderer + * + * @method setRenderable + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) +{ + // has this changed?? + if(this.root)this.removeDisplayObjectAndChildren(this.root); + + displayObject.worldVisible = displayObject.visible; + + // soooooo // + // to check if any batchs exist already?? + + // TODO what if its already has an object? should remove it + this.root = displayObject; + this.addDisplayObjectAndChildren(displayObject); +} + +/** + * Renders the stage to its webgl view + * + * @method render + * @param projection {Object} + */ +PIXI.WebGLRenderGroup.prototype.render = function(projection) +{ + PIXI.WebGLRenderer.updateTextures(); + + var gl = this.gl; + + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + // will render all the elements in the group + var renderable; + for (var i=0; i < this.batchs.length; i++) + { + + renderable = this.batchs[i]; + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + continue; + } + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) + { + if(worldVisible)this.renderTilingSprite(renderable, projection); + } + else if(renderable instanceof PIXI.Strip) + { + if(worldVisible)this.renderStrip(renderable, projection); + } + else if(renderable instanceof PIXI.Graphics) + { + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + } + else if(renderable instanceof PIXI.FilterBlock) + { + this.handleFilterBlock(renderable, projection); + } + } + +} + +/** + * Renders a specific displayObject + * + * @method renderSpecific + * @param displayObject {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection) +{ + PIXI.WebGLRenderer.updateTextures(); + + var gl = this.gl; + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + + // to do! + // render part of the scene... + + var startIndex; + var startBatchIndex; + + var endIndex; + var endBatchIndex; + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.first; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + var startBatch = nextRenderable.batch; + + if(nextRenderable instanceof PIXI.Sprite) + { + startBatch = nextRenderable.batch; + + var head = startBatch.head; + var next = head; + + // ok now we have the batch.. need to find the start index! + if(head == nextRenderable) + { + startIndex = 0; + } + else + { + startIndex = 1; + + while(head.__next != nextRenderable) + { + startIndex++; + head = head.__next; + } + } + } + else + { + startBatch = nextRenderable; + } + + // Get the LAST renderable object + var lastRenderable = displayObject; + var endBatch; + var lastItem = displayObject; + while(lastItem.children.length > 0) + { + lastItem = lastItem.children[lastItem.children.length-1]; + if(lastItem.renderable)lastRenderable = lastItem.last; + } + + if(lastRenderable instanceof PIXI.Sprite) + { + endBatch = lastRenderable.batch; + + var head = endBatch.head; + + if(head == lastRenderable) + { + endIndex = 0; + } + else + { + endIndex = 1; + + while(head.__next != lastRenderable) + { + endIndex++; + head = head.__next; + } + } + } + else + { + endBatch = lastRenderable; + } + + // TODO - need to fold this up a bit! + + if(startBatch == endBatch) + { + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex, endIndex+1); + } + else + { + this.renderSpecial(startBatch, projection); + } + return; + } + + // now we have first and last! + startBatchIndex = this.batchs.indexOf(startBatch); + endBatchIndex = this.batchs.indexOf(endBatch); + + // DO the first batch + if(startBatch instanceof PIXI.WebGLBatch) + { + startBatch.render(startIndex); + } + else + { + this.renderSpecial(startBatch, projection); + } + + // DO the middle batchs.. + for (var i=startBatchIndex+1; i < endBatchIndex; i++) + { + renderable = this.batchs[i]; + + if(renderable instanceof PIXI.WebGLBatch) + { + this.batchs[i].render(); + } + else + { + this.renderSpecial(renderable, projection); + } + } + + // DO the last batch.. + if(endBatch instanceof PIXI.WebGLBatch) + { + endBatch.render(0, endIndex+1); + } + else + { + this.renderSpecial(endBatch, projection); + } +} + +/** + * Renders a specific renderable + * + * @method renderSpecial + * @param renderable {DisplayObject} + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) +{ + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + + if(renderable instanceof PIXI.TilingSprite) + { + if(worldVisible)this.renderTilingSprite(renderable, projection); + } + else if(renderable instanceof PIXI.Strip) + { + if(worldVisible)this.renderStrip(renderable, projection); + } + else if(renderable instanceof PIXI.CustomRenderable) + { + if(worldVisible) renderable.renderWebGL(this, projection); + } + else if(renderable instanceof PIXI.Graphics) + { + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + } + else if(renderable instanceof PIXI.FilterBlock) + { + this.handleFilterBlock(renderable, projection); + } +} + +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; + + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else + { + gl.enable(gl.STENCIL_TEST); + + gl.colorMask(false, false, false, false); + gl.stencilFunc(gl.ALWAYS,1,0xff); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.NOTEQUAL,0,0xff); + gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); + } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else + { + gl.disable(gl.STENCIL_TEST); + } + } +} + +/** + * Updates a webgl texture + * + * @method updateTexture + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) +{ + + // TODO definitely can optimse this function.. + + this.removeObject(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = displayObject.first; + while(previousRenderable != this.root) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + this.insertObject(displayObject, previousRenderable, nextRenderable); +} + +/** + * Adds filter blocks + * + * @method addFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) +{ + start.__renderGroup = this; + end.__renderGroup = this; + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + var previousRenderable = start; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + this.insertAfter(start, previousRenderable); + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var previousRenderable2 = end; + while(previousRenderable2 != this.root.first) + { + previousRenderable2 = previousRenderable2._iPrev; + if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; + } + this.insertAfter(end, previousRenderable2); +} + +/** + * Remove filter blocks + * + * @method removeFilterBlocks + * @param start {FilterBlock} + * @param end {FilterBlock} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) +{ + this.removeObject(start); + this.removeObject(end); +} + +/** + * Adds a display object and children to the webgl context + * + * @method addDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); + + /* + * LOOK FOR THE PREVIOUS RENDERABLE + * This part looks for the closest previous sprite that can go into a batch + * It keeps going back until it finds a sprite or the stage + */ + + var previousRenderable = displayObject.first; + while(previousRenderable != this.root.first) + { + previousRenderable = previousRenderable._iPrev; + if(previousRenderable.renderable && previousRenderable.__renderGroup)break; + } + + /* + * LOOK FOR THE NEXT SPRITE + * This part looks for the closest next sprite that can go into a batch + * it keeps looking until it finds a sprite or gets to the end of the display + * scene graph + */ + var nextRenderable = displayObject.last; + while(nextRenderable._iNext) + { + nextRenderable = nextRenderable._iNext; + if(nextRenderable.renderable && nextRenderable.__renderGroup)break; + } + + // one the display object hits this. we can break the loop + + var tempObject = displayObject.first; + var testObject = displayObject.last._iNext; + do + { + tempObject.__renderGroup = this; + + if(tempObject.renderable) + { + + this.insertObject(tempObject, previousRenderable, nextRenderable); + previousRenderable = tempObject; + } + + tempObject = tempObject._iNext; + } + while(tempObject != testObject) +} + +/** + * Removes a display object and children to the webgl context + * + * @method removeDisplayObjectAndChildren + * @param displayObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) +{ + if(displayObject.__renderGroup != this)return; + +// var displayObject = displayObject.first; + var lastObject = displayObject.last; + do + { + displayObject.__renderGroup = null; + if(displayObject.renderable)this.removeObject(displayObject); + displayObject = displayObject._iNext; + } + while(displayObject) +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertObject + * @param displayObject {DisplayObject} + * @param previousObject {DisplayObject} + * @param nextObject {DisplayObject} + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousObject, nextObject) +{ + // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED + var previousSprite = previousObject; + var nextSprite = nextObject; + + /* + * so now we have the next renderable and the previous renderable + * + */ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch + var nextBatch + + if(previousSprite instanceof PIXI.Sprite) + { + previousBatch = previousSprite.batch; + if(previousBatch) + { + if(previousBatch.texture == displayObject.texture.baseTexture && previousBatch.blendMode == displayObject.blendMode) + { + previousBatch.insertAfter(displayObject, previousSprite); + return; + } + } + } + else + { + // TODO reword! + previousBatch = previousSprite; + } + + if(nextSprite) + { + if(nextSprite instanceof PIXI.Sprite) + { + nextBatch = nextSprite.batch; + + //batch may not exist if item was added to the display list but not to the webGL + if(nextBatch) + { + if(nextBatch.texture == displayObject.texture.baseTexture && nextBatch.blendMode == displayObject.blendMode) + { + nextBatch.insertBefore(displayObject, nextSprite); + return; + } + else + { + if(nextBatch == previousBatch) + { + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(nextSprite); + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var batch = PIXI.WebGLRenderer.getBatch(); + + var index = this.batchs.indexOf( previousBatch ); + batch.init(displayObject); + this.batchs.splice(index+1, 0, batch, splitBatch); + + return; + } + } + } + } + else + { + // TODO re-word! + + nextBatch = nextSprite; + } + } + + /* + * looks like it does not belong to any batch! + * but is also not intersecting one.. + * time to create anew one! + */ + + var batch = PIXI.WebGLRenderer.getBatch(); + batch.init(displayObject); + + if(previousBatch) // if this is invalid it means + { + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, batch); + } + else + { + this.batchs.push(batch); + } + + return; + } + else if(displayObject instanceof PIXI.TilingSprite) + { + + // add to a batch!! + this.initTilingSprite(displayObject); + // this.batchs.push(displayObject); + + } + else if(displayObject instanceof PIXI.Strip) + { + // add to a batch!! + this.initStrip(displayObject); + // this.batchs.push(displayObject); + } + else if(displayObject)// instanceof PIXI.Graphics) + { + //displayObject.initWebGL(this); + + // add to a batch!! + //this.initStrip(displayObject); + //this.batchs.push(displayObject); + } + + this.insertAfter(displayObject, previousSprite); + + // insert and SPLIT! + +} + +/** + * Inserts a displayObject into the linked list + * + * @method insertAfter + * @param item {DisplayObject} + * @param displayObject {DisplayObject} The object to insert + * @private + */ +PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) +{ + if(displayObject instanceof PIXI.Sprite) + { + var previousBatch = displayObject.batch; + + if(previousBatch) + { + // so this object is in a batch! + + // is it not? need to split the batch + if(previousBatch.tail == displayObject) + { + // is it tail? insert in to batchs + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item); + } + else + { + // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // + + // THERE IS A SPLIT IN THIS BATCH! // + var splitBatch = previousBatch.split(displayObject.__next); + + // COOL! + // add it back into the array + /* + * OOPS! + * seems the new sprite is in the middle of a batch + * lets split it.. + */ + var index = this.batchs.indexOf( previousBatch ); + this.batchs.splice(index+1, 0, item, splitBatch); + } + } + else + { + this.batchs.push(item); + } + } + else + { + var index = this.batchs.indexOf( displayObject ); + this.batchs.splice(index+1, 0, item); + } +} + +/** + * Removes a displayObject from the linked list + * + * @method removeObject + * @param displayObject {DisplayObject} The object to remove + * @private + */ +PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) +{ + // loop through children.. + // display object // + + // add a child from the render group.. + // remove it and all its children! + //displayObject.cacheVisible = false;//displayObject.visible; + + /* + * removing is a lot quicker.. + * + */ + var batchToRemove; + + if(displayObject instanceof PIXI.Sprite) + { + // should always have a batch! + var batch = displayObject.batch; + if(!batch)return; // this means the display list has been altered befre rendering + + batch.remove(displayObject); + + if(batch.size==0) + { + batchToRemove = batch; + } + } + else + { + batchToRemove = displayObject; + } + + /* + * Looks like there is somthing that needs removing! + */ + if(batchToRemove) + { + var index = this.batchs.indexOf( batchToRemove ); + if(index == -1)return;// this means it was added then removed before rendered + + // ok so.. check to see if you adjacent batchs should be joined. + // TODO may optimise? + if(index == 0 || index == this.batchs.length-1) + { + // wha - eva! just get of the empty batch! + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + + return; + } + + if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) + { + if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) + { + //console.log("MERGE") + this.batchs[index-1].merge(this.batchs[index+1]); + + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); + this.batchs.splice(index, 2); + return; + } + } + + this.batchs.splice(index, 1); + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); + } +} + + +/** + * Initializes a tiling sprite + * + * @method initTilingSprite + * @param sprite {TilingSprite} The tiling sprite to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) +{ + var gl = this.gl; + + // make the texture tilable.. + + sprite.verticies = new Float32Array([0, 0, + sprite.width, 0, + sprite.width, sprite.height, + 0, sprite.height]); + + sprite.uvs = new Float32Array([0, 0, + 1, 0, + 1, 1, + 0, 1]); + + sprite.colors = new Float32Array([1,1,1,1]); + + sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); + + sprite._vertexBuffer = gl.createBuffer(); + sprite._indexBuffer = gl.createBuffer(); + sprite._uvBuffer = gl.createBuffer(); + sprite._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.uvs, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, sprite.colors, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); + +// return ( (x > 0) && ((x & (x - 1)) == 0) ); + + if(sprite.texture.baseTexture._glTexture) + { + gl.bindTexture(gl.TEXTURE_2D, sprite.texture.baseTexture._glTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + sprite.texture.baseTexture._powerOf2 = true; + } + else + { + sprite.texture.baseTexture._powerOf2 = true; + } +} + +/** + * Renders a Strip + * + * @method renderStrip + * @param strip {Strip} The strip to render + * @param projection {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) +{ + var gl = this.gl; + var shaderProgram = PIXI.stripShaderProgram; + + + gl.useProgram(shaderProgram); + + var m = PIXI.mat3.clone(strip.worldTransform); + + PIXI.mat3.transpose(m); + + // set the matrix transform for the + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); + +/* + if(strip.blendMode == PIXI.blendModes.NORMAL) + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } + else + { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); + } + */ + + + if(!strip.dirty) + { + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) + gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + } + else + { + strip.dirty = false; + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) + gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + + // update the uvs + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) + gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) + gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); + + // dont need to upload! + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); + + } + + gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); + + gl.useProgram(PIXI.currentProgram); +} + +/** + * Renders a TilingSprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tiling sprite to render + * @param projectionMatrix {Object} + * @private + */ +PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projectionMatrix) +{ + var gl = this.gl; + var shaderProgram = PIXI.shaderProgram; + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + var offsetX = tilePosition.x/sprite.texture.baseTexture.width; + var offsetY = tilePosition.y/sprite.texture.baseTexture.height; + + var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; + var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; + + sprite.uvs[0] = 0 - offsetX; + sprite.uvs[1] = 0 - offsetY; + + sprite.uvs[2] = (1 * scaleX) -offsetX; + sprite.uvs[3] = 0 - offsetY; + + sprite.uvs[4] = (1 *scaleX) - offsetX; + sprite.uvs[5] = (1 *scaleY) - offsetY; + + sprite.uvs[6] = 0 - offsetX; + sprite.uvs[7] = (1 *scaleY) - offsetY; + + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) + + this.renderStrip(sprite, projectionMatrix); +} + +/** + * Initializes a strip to be rendered + * + * @method initStrip + * @param strip {Strip} The strip to initialize + * @private + */ +PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) +{ + // build the strip! + var gl = this.gl; + var shaderProgram = this.shaderProgram; + + strip._vertexBuffer = gl.createBuffer(); + strip._indexBuffer = gl.createBuffer(); + strip._uvBuffer = gl.createBuffer(); + strip._colorBuffer = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW); + + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); + + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * the CanvasRenderer draws the stage and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. + * Dont forget to add the view to your DOM or you will not see anything :) + * + * @class CanvasRenderer + * @constructor + * @param width=0 {Number} the width of the canvas view + * @param height=0 {Number} the height of the canvas view + * @param view {Canvas} the canvas to use as a view, optional + * @param transparent=false {Boolean} the transparency of the render view, default false + */ +PIXI.CanvasRenderer = function(width, height, view, transparent) +{ + this.transparent = transparent; + + /** + * The width of the canvas view + * + * @property width + * @type Number + * @default 800 + */ + this.width = width || 800; + + /** + * The height of the canvas view + * + * @property height + * @type Number + * @default 600 + */ + this.height = height || 600; + + /** + * The canvas element that the everything is drawn to + * + * @property view + * @type Canvas + */ + this.view = view || document.createElement( 'canvas' ); + + /** + * The canvas context that the everything is drawn to + * @property context + * @type Canvas 2d Context + */ + this.context = this.view.getContext("2d"); + + this.refresh = true; + // hack to enable some hardware acceleration! + //this.view.style["transform"] = "translatez(0)"; + + this.view.width = this.width; + this.view.height = this.height; + this.count = 0; +} + +// constructor +PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; + +/** + * Renders the stage to its canvas view + * + * @method render + * @param stage {Stage} the Stage element to be rendered + */ +PIXI.CanvasRenderer.prototype.render = function(stage) +{ + + //stage.__childrenAdded = []; + //stage.__childrenRemoved = []; + + // update textures if need be + PIXI.texturesToUpdate = []; + PIXI.texturesToDestroy = []; + + PIXI.visibleCount++; + stage.updateTransform(); + + // update the background color + if(this.view.style.backgroundColor!=stage.backgroundColorString && !this.transparent)this.view.style.backgroundColor = stage.backgroundColorString; + + this.context.setTransform(1,0,0,1,0,0); + this.context.clearRect(0, 0, this.width, this.height) + this.renderDisplayObject(stage); + //as + + // run interaction! + if(stage.interactive) + { + //need to add some events! + if(!stage._interactiveEventsAdded) + { + stage._interactiveEventsAdded = true; + stage.interactionManager.setTarget(this); + } + } + + // remove frame updates.. + if(PIXI.Texture.frameUpdates.length > 0) + { + PIXI.Texture.frameUpdates = []; + } + + +} + +/** + * resizes the canvas view to the specified width and height + * + * @method resize + * @param width {Number} the new width of the canvas view + * @param height {Number} the new height of the canvas view + */ +PIXI.CanvasRenderer.prototype.resize = function(width, height) +{ + this.width = width; + this.height = height; + + this.view.width = width; + this.view.height = height; +} + +/** + * Renders a display object + * + * @method renderDisplayObject + * @param displayObject {DisplayObject} The displayObject to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) +{ + // no loger recurrsive! + var transform; + var context = this.context; + + context.globalCompositeOperation = 'source-over'; + + // one the display object hits this. we can break the loop + var testObject = displayObject.last._iNext; + displayObject = displayObject.first; + + do + { + transform = displayObject.worldTransform; + + if(!displayObject.visible) + { + displayObject = displayObject.last._iNext; + continue; + } + + if(!displayObject.renderable) + { + displayObject = displayObject._iNext; + continue; + } + + if(displayObject instanceof PIXI.Sprite) + { + + var frame = displayObject.texture.frame; + + if(frame && frame.width && frame.height) + { + context.globalAlpha = displayObject.worldAlpha; + + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); + + context.drawImage(displayObject.texture.baseTexture.source, + frame.x, + frame.y, + frame.width, + frame.height, + (displayObject.anchor.x) * -frame.width, + (displayObject.anchor.y) * -frame.height, + frame.width, + frame.height); + } + } + else if(displayObject instanceof PIXI.Strip) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderStrip(displayObject); + } + else if(displayObject instanceof PIXI.TilingSprite) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + this.renderTilingSprite(displayObject); + } + else if(displayObject instanceof PIXI.CustomRenderable) + { + displayObject.renderCanvas(this); + } + else if(displayObject instanceof PIXI.Graphics) + { + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]) + PIXI.CanvasGraphics.renderGraphics(displayObject, context); + } + else if(displayObject instanceof PIXI.FilterBlock) + { + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) + { + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } + } + else + { + // only masks supported right now! + } + } + // count++ + displayObject = displayObject._iNext; + + + } + while(displayObject != testObject) + + +} + +/** + * Renders a flat strip + * + * @method renderStripFlat + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) +{ + var context = this.context; + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + + context.beginPath(); + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + + }; + + context.fillStyle = "#FF0000"; + context.fill(); + context.closePath(); +} + +/** + * Renders a tiling sprite + * + * @method renderTilingSprite + * @param sprite {TilingSprite} The tilingsprite to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) +{ + var context = this.context; + + context.globalAlpha = sprite.worldAlpha; + + if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); + + context.beginPath(); + + var tilePosition = sprite.tilePosition; + var tileScale = sprite.tileScale; + + // offset + context.scale(tileScale.x,tileScale.y); + context.translate(tilePosition.x, tilePosition.y); + + context.fillStyle = sprite.__tilePattern; + context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); + + context.scale(1/tileScale.x, 1/tileScale.y); + context.translate(-tilePosition.x, -tilePosition.y); + + context.closePath(); +} + +/** + * Renders a strip + * + * @method renderStrip + * @param strip {Strip} The Strip to render + * @private + */ +PIXI.CanvasRenderer.prototype.renderStrip = function(strip) +{ + var context = this.context; + + // draw triangles!! + var verticies = strip.verticies; + var uvs = strip.uvs; + + var length = verticies.length/2; + this.count++; + for (var i=1; i < length-2; i++) + { + + // draw some triangles! + var index = i*2; + + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; + var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; + + var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; + var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; + + + context.save(); + context.beginPath(); + context.moveTo(x0, y0); + context.lineTo(x1, y1); + context.lineTo(x2, y2); + context.closePath(); + + context.clip(); + + + // Compute matrix transform + var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; + var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; + var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2; + var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2 - v0*u1*x2 - u0*x1*v2; + var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; + var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; + var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; + + + + + context.transform(delta_a/delta, delta_d/delta, + delta_b/delta, delta_e/delta, + delta_c/delta, delta_f/delta); + + context.drawImage(strip.texture.baseTexture.source, 0, 0); + context.restore(); + }; + +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * A set of functions used by the canvas renderer to draw the primitive graphics data + * + * @class CanvasGraphics + */ +PIXI.CanvasGraphics = function() +{ + +} + + +/* + * Renders the graphics object + * + * @static + * @private + * @method renderGraphics + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphics = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + for (var i=0; i < graphics.graphicsData.length; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); + + context.lineWidth = data.lineWidth; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.RECT) + { + + if(data.fillColor || data.fillColor === 0) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fillRect(points[0], points[1], points[2], points[3]); + + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.strokeRect(points[0], points[1], points[2], points[3]); + } + + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + context.closePath(); + + if(data.fill) + { + context.globalAlpha = data.fillAlpha * worldAlpha; + context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); + context.fill(); + } + if(data.lineWidth) + { + context.globalAlpha = data.lineAlpha * worldAlpha; + context.stroke(); + } + } + + }; +} + +/* + * Renders a graphics mask + * + * @static + * @private + * @method renderGraphicsMask + * @param graphics {Graphics} + * @param context {Context2D} + */ +PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) +{ + var worldAlpha = graphics.worldAlpha; + + var len = graphics.graphicsData.length; + if(len > 1) + { + len = 1; + console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") + } + + for (var i=0; i < 1; i++) + { + var data = graphics.graphicsData[i]; + var points = data.points; + + if(data.type == PIXI.Graphics.POLY) + { + context.beginPath(); + context.moveTo(points[0], points[1]); + + for (var j=1; j < points.length/2; j++) + { + context.lineTo(points[j * 2], points[j * 2 + 1]); + } + + // if the first and last point are the same close the path - much neater :) + if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) + { + context.closePath(); + } + + } + else if(data.type == PIXI.Graphics.RECT) + { + context.beginPath(); + context.rect(points[0], points[1], points[2], points[3]); + context.closePath(); + } + else if(data.type == PIXI.Graphics.CIRC) + { + // TODO - need to be Undefined! + context.beginPath(); + context.arc(points[0], points[1], points[2],0,2*Math.PI); + context.closePath(); + } + else if(data.type == PIXI.Graphics.ELIP) + { + + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + var elipseData = data.points; + + var w = elipseData[2] * 2; + var h = elipseData[3] * 2; + + var x = elipseData[0] - w/2; + var y = elipseData[1] - h/2; + + context.beginPath(); + + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + context.moveTo(x, ym); + context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + context.closePath(); + } + + + }; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * It is important to know that with the webGL renderer only simple polys can be filled at this stage + * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png + * + * @class Graphics + * @extends DisplayObjectContainer + * @constructor + */ +PIXI.Graphics = function() +{ + PIXI.DisplayObjectContainer.call( this ); + + this.renderable = true; + + /** + * The alpha of the fill of this graphics object + * + * @property fillAlpha + * @type Number + */ + this.fillAlpha = 1; + + /** + * The width of any lines drawn + * + * @property lineWidth + * @type Number + */ + this.lineWidth = 0; + + /** + * The color of any lines drawn + * + * @property lineColor + * @type String + */ + this.lineColor = "black"; + + /** + * Graphics data + * + * @property graphicsData + * @type Array + * @private + */ + this.graphicsData = []; + + /** + * Current path + * + * @property currentPath + * @type Object + * @private + */ + this.currentPath = {points:[]}; +} + +// constructor +PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Graphics.prototype.constructor = PIXI.Graphics; + +/** + * Specifies a line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. + * + * @method lineStyle + * @param lineWidth {Number} width of the line to draw, will update the object's stored style + * @param color {Number} color of the line to draw, will update the object's stored style + * @param alpha {Number} alpha of the line to draw, will update the object's stored style + */ +PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.lineWidth = lineWidth || 0; + this.lineColor = color || 0; + this.lineAlpha = (alpha == undefined) ? 1 : alpha; + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.graphicsData.push(this.currentPath); +} + +/** + * Moves the current drawing position to (x, y). + * + * @method moveTo + * @param x {Number} the X coord to move to + * @param y {Number} the Y coord to move to + */ +PIXI.Graphics.prototype.moveTo = function(x, y) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; + + this.currentPath.points.push(x, y); + + this.graphicsData.push(this.currentPath); +} + +/** + * Draws a line using the current line style from the current drawing position to (x, y); + * the current drawing position is then set to (x, y). + * + * @method lineTo + * @param x {Number} the X coord to draw to + * @param y {Number} the Y coord to draw to + */ +PIXI.Graphics.prototype.lineTo = function(x, y) +{ + this.currentPath.points.push(x, y); + this.dirty = true; +} + +/** + * Specifies a simple one-color fill that subsequent calls to other Graphics methods + * (such as lineTo() or drawCircle()) use when drawing. + * + * @method beginFill + * @param color {uint} the color of the fill + * @param alpha {Number} the alpha + */ +PIXI.Graphics.prototype.beginFill = function(color, alpha) +{ + this.filling = true; + this.fillColor = color || 0; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; +} + +/** + * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. + * + * @method endFill + */ +PIXI.Graphics.prototype.endFill = function() +{ + this.filling = false; + this.fillColor = null; + this.fillAlpha = 1; +} + +/** + * @method drawRect + * + * @param x {Number} The X coord of the top-left of the rectangle + * @param y {Number} The Y coord of the top-left of the rectangle + * @param width {Number} The width of the rectangle + * @param height {Number} The height of the rectangle + */ +PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.RECT}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws a circle. + * + * @method drawCircle + * @param x {Number} The X coord of the center of the circle + * @param y {Number} The Y coord of the center of the circle + * @param radius {Number} The radius of the circle + */ +PIXI.Graphics.prototype.drawCircle = function( x, y, radius) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Draws an elipse. + * + * @method drawElipse + * @param x {Number} + * @param y {Number} + * @param width {Number} + * @param height {Number} + */ +PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) +{ + if(this.currentPath.points.length == 0)this.graphicsData.pop(); + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + points:[x, y, width, height], type:PIXI.Graphics.ELIP}; + + this.graphicsData.push(this.currentPath); + this.dirty = true; +} + +/** + * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. + * + * @method clear + */ +PIXI.Graphics.prototype.clear = function() +{ + this.lineWidth = 0; + this.filling = false; + + this.dirty = true; + this.clearDirty = true; + this.graphicsData = []; +} + +// SOME TYPES: +PIXI.Graphics.POLY = 0; +PIXI.Graphics.RECT = 1; +PIXI.Graphics.CIRC = 2; +PIXI.Graphics.ELIP = 3; + +/** + * @author Mat Groves http://matgroves.com/ + */ + +PIXI.Strip = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + this.texture = texture; + this.blendMode = PIXI.blendModes.NORMAL; + + try + { + this.uvs = new Float32Array([0, 1, + 1, 1, + 1, 0, 0,1]); + + this.verticies = new Float32Array([0, 0, + 0,0, + 0,0, 0, + 0, 0]); + + this.colors = new Float32Array([1, 1, 1, 1]); + + this.indices = new Uint16Array([0, 1, 2, 3]); + } + catch(error) + { + this.uvs = [0, 1, + 1, 1, + 1, 0, 0,1]; + + this.verticies = [0, 0, + 0,0, + 0,0, 0, + 0, 0]; + + this.colors = [1, 1, 1, 1]; + + this.indices = [0, 1, 2, 3]; + } + + + /* + this.uvs = new Float32Array() + this.verticies = new Float32Array() + this.colors = new Float32Array() + this.indices = new Uint16Array() +*/ + this.width = width; + this.height = height; + + // load the texture! + if(texture.baseTexture.hasLoaded) + { + this.width = this.texture.frame.width; + this.height = this.texture.frame.height; + this.updateFrame = true; + } + else + { + this.onTextureUpdateBind = this.onTextureUpdate.bind(this); + this.texture.addEventListener( 'update', this.onTextureUpdateBind ); + } + + this.renderable = true; +} + +// constructor +PIXI.Strip.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.Strip.prototype.constructor = PIXI.Strip; + +PIXI.Strip.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.width = texture.frame.width; + this.height = texture.frame.height; + this.updateFrame = true; +} + +PIXI.Strip.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} +// some helper functions.. + + +/** + * @author Mat Groves http://matgroves.com/ + */ + + +PIXI.Rope = function(texture, points) +{ + PIXI.Strip.call( this, texture ); + this.points = points; + + try + { + this.verticies = new Float32Array( points.length * 4); + this.uvs = new Float32Array( points.length * 4); + this.colors = new Float32Array( points.length * 2); + this.indices = new Uint16Array( points.length * 2); + } + catch(error) + { + this.verticies = verticies + + this.uvs = uvs + this.colors = colors + this.indices = indices + } + + this.refresh(); +} + + +// constructor +PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); +PIXI.Rope.prototype.constructor = PIXI.Rope; + +PIXI.Rope.prototype.refresh = function() +{ + var points = this.points; + if(points.length < 1)return; + + var uvs = this.uvs + var indices = this.indices; + var colors = this.colors; + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + + uvs[0] = 0 + uvs[1] = 1 + uvs[2] = 0 + uvs[3] = 1 + + colors[0] = 1; + colors[1] = 1; + + indices[0] = 0; + indices[1] = 1; + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + // time to do some smart drawing! + var amount = i/(total-1) + + if(i%2) + { + uvs[index] = amount; + uvs[index+1] = 0; + + uvs[index+2] = amount + uvs[index+3] = 1 + + } + else + { + uvs[index] = amount + uvs[index+1] = 0 + + uvs[index+2] = amount + uvs[index+3] = 1 + } + + index = i * 2; + colors[index] = 1; + colors[index+1] = 1; + + index = i * 2; + indices[index] = index; + indices[index + 1] = index + 1; + + lastPoint = point; + } +} + +PIXI.Rope.prototype.updateTransform = function() +{ + + var points = this.points; + if(points.length < 1)return; + + var verticies = this.verticies + + var lastPoint = points[0]; + var nextPoint; + var perp = {x:0, y:0}; + var point = points[0]; + + this.count-=0.2; + + verticies[0] = point.x + perp.x + verticies[1] = point.y + perp.y //+ 200 + verticies[2] = point.x - perp.x + verticies[3] = point.y - perp.y//+200 + // time to do some smart drawing! + + var total = points.length; + + for (var i = 1; i < total; i++) + { + + var point = points[i]; + var index = i * 4; + + if(i < points.length-1) + { + nextPoint = points[i+1]; + } + else + { + nextPoint = point + } + + perp.y = -(nextPoint.x - lastPoint.x); + perp.x = nextPoint.y - lastPoint.y; + + var ratio = (1 - (i / (total-1))) * 10; + if(ratio > 1)ratio = 1; + + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); + var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; + perp.x /= perpLength; + perp.y /= perpLength; + + perp.x *= num; + perp.y *= num; + + verticies[index] = point.x + perp.x + verticies[index+1] = point.y + perp.y + verticies[index+2] = point.x - perp.x + verticies[index+3] = point.y - perp.y + + lastPoint = point; + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); +} + +PIXI.Rope.prototype.setTexture = function(texture) +{ + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + + + + + +/** + * @author Mat Groves http://matgroves.com/ + */ + +/** + * A tiling sprite is a fast way of rendering a tiling image + * + * @class TilingSprite + * @extends DisplayObjectContainer + * @constructor + * @param texture {Texture} the texture of the tiling sprite + * @param width {Number} the width of the tiling sprite + * @param height {Number} the height of the tiling sprite + */ +PIXI.TilingSprite = function(texture, width, height) +{ + PIXI.DisplayObjectContainer.call( this ); + + /** + * The texture that the sprite is using + * + * @property texture + * @type Texture + */ + this.texture = texture; + + /** + * The width of the tiling sprite + * + * @property width + * @type Number + */ + this.width = width; + + /** + * The height of the tiling sprite + * + * @property height + * @type Number + */ + this.height = height; + + /** + * The scaling of the image that is being tiled + * + * @property tileScale + * @type Point + */ + this.tileScale = new PIXI.Point(1,1); + + /** + * The offset position of the image that is being tiled + * + * @property tilePosition + * @type Point + */ + this.tilePosition = new PIXI.Point(0,0); + + this.renderable = true; + + this.blendMode = PIXI.blendModes.NORMAL +} + +// constructor +PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); +PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite; + +/** + * Sets the texture of the tiling sprite + * + * @method setTexture + * @param texture {Texture} The PIXI texture that is displayed by the sprite + */ +PIXI.TilingSprite.prototype.setTexture = function(texture) +{ + //TODO SET THE TEXTURES + //TODO VISIBILITY + + // stop current texture + this.texture = texture; + this.updateFrame = true; +} + +/** + * When the texture is updated, this event will fire to update the frame + * + * @method onTextureUpdate + * @param event + * @private + */ +PIXI.TilingSprite.prototype.onTextureUpdate = function(event) +{ + this.updateFrame = true; +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi + * + * Awesome JS run time provided by EsotericSoftware + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +/** + * A class that enables the you to import and run your spine animations in pixi. + * Spine animation data needs to be loaded using the PIXI.AssetLoader or PIXI.SpineLoader before it can be used by this class + * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source + * + * @class Spine + * @extends DisplayObjectContainer + * @constructor + * @param url {String} The url of the spine anim file to be used + */ +PIXI.Spine = function (url) { + PIXI.DisplayObjectContainer.call(this); + + this.spineData = PIXI.AnimCache[url]; + + if (!this.spineData) { + throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); + } + + this.skeleton = new spine.Skeleton(this.spineData); + this.skeleton.updateWorldTransform(); + + this.stateData = new spine.AnimationStateData(this.spineData); + this.state = new spine.AnimationState(this.stateData); + + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +PIXI.Spine.prototype.constructor = PIXI.Spine; + +/* + * Updates the object transform for rendering + * + * @method updateTransform + * @private + */ +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); + this.state.apply(this.skeleton); + this.skeleton.updateWorldTransform(); + + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } + + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; + } + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; + } + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; + +/* + * Awesome JS run time provided by EsotericSoftware + * + * https://github.com/EsotericSoftware/spine-runtimes + * + */ + +var spine = {}; + +spine.BoneData = function (name, parent) { + this.name = name; + this.parent = parent; +}; +spine.BoneData.prototype = { + length: 0, + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1 +}; + +spine.SlotData = function (name, boneData) { + this.name = name; + this.boneData = boneData; +}; +spine.SlotData.prototype = { + r: 1, g: 1, b: 1, a: 1, + attachmentName: null +}; + +spine.Bone = function (boneData, parent) { + this.data = boneData; + this.parent = parent; + this.setToSetupPose(); +}; +spine.Bone.yDown = false; +spine.Bone.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + m00: 0, m01: 0, worldX: 0, // a b x + m10: 0, m11: 0, worldY: 0, // c d y + worldRotation: 0, + worldScaleX: 1, worldScaleY: 1, + updateWorldTransform: function (flipX, flipY) { + var parent = this.parent; + if (parent != null) { + this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; + this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; + this.worldScaleX = parent.worldScaleX * this.scaleX; + this.worldScaleY = parent.worldScaleY * this.scaleY; + this.worldRotation = parent.worldRotation + this.rotation; + } else { + this.worldX = this.x; + this.worldY = this.y; + this.worldScaleX = this.scaleX; + this.worldScaleY = this.scaleY; + this.worldRotation = this.rotation; + } + var radians = this.worldRotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + this.m00 = cos * this.worldScaleX; + this.m10 = sin * this.worldScaleX; + this.m01 = -sin * this.worldScaleY; + this.m11 = cos * this.worldScaleY; + if (flipX) { + this.m00 = -this.m00; + this.m01 = -this.m01; + } + if (flipY) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + if (spine.Bone.yDown) { + this.m10 = -this.m10; + this.m11 = -this.m11; + } + }, + setToSetupPose: function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + } +}; + +spine.Slot = function (slotData, skeleton, bone) { + this.data = slotData; + this.skeleton = skeleton; + this.bone = bone; + this.setToSetupPose(); +}; +spine.Slot.prototype = { + r: 1, g: 1, b: 1, a: 1, + _attachmentTime: 0, + attachment: null, + setAttachment: function (attachment) { + this.attachment = attachment; + this._attachmentTime = this.skeleton.time; + }, + setAttachmentTime: function (time) { + this._attachmentTime = this.skeleton.time - time; + }, + getAttachmentTime: function () { + return this.skeleton.time - this._attachmentTime; + }, + setToSetupPose: function () { + var data = this.data; + this.r = data.r; + this.g = data.g; + this.b = data.b; + this.a = data.a; + + var slotDatas = this.skeleton.data.slots; + for (var i = 0, n = slotDatas.length; i < n; i++) { + if (slotDatas[i] == data) { + this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); + break; + } + } + } +}; + +spine.Skin = function (name) { + this.name = name; + this.attachments = {}; +}; +spine.Skin.prototype = { + addAttachment: function (slotIndex, name, attachment) { + this.attachments[slotIndex + ":" + name] = attachment; + }, + getAttachment: function (slotIndex, name) { + return this.attachments[slotIndex + ":" + name]; + }, + _attachAll: function (skeleton, oldSkin) { + for (var key in oldSkin.attachments) { + var colon = key.indexOf(":"); + var slotIndex = parseInt(key.substring(0, colon)); + var name = key.substring(colon + 1); + var slot = skeleton.slots[slotIndex]; + if (slot.attachment && slot.attachment.name == name) { + var attachment = this.getAttachment(slotIndex, name); + if (attachment) slot.setAttachment(attachment); + } + } + } +}; + +spine.Animation = function (name, timelines, duration) { + this.name = name; + this.timelines = timelines; + this.duration = duration; +}; +spine.Animation.prototype = { + apply: function (skeleton, time, loop) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, 1); + }, + mix: function (skeleton, time, loop, alpha) { + if (loop && this.duration != 0) time %= this.duration; + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, time, alpha); + } +}; + +spine.binarySearch = function (values, target, step) { + var low = 0; + var high = Math.floor(values.length / step) - 2; + if (high == 0) return step; + var current = high >>> 1; + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >>> 1; + } +}; +spine.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; +}; + +spine.Curves = function (frameCount) { + this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... + this.curves.length = (frameCount - 1) * 6; +}; +spine.Curves.prototype = { + setLinear: function (frameIndex) { + this.curves[frameIndex * 6] = 0/*LINEAR*/; + }, + setStepped: function (frameIndex) { + this.curves[frameIndex * 6] = -1/*STEPPED*/; + }, + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { + var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/; + var subdiv_step2 = subdiv_step * subdiv_step; + var subdiv_step3 = subdiv_step2 * subdiv_step; + var pre1 = 3 * subdiv_step; + var pre2 = 3 * subdiv_step2; + var pre4 = 6 * subdiv_step2; + var pre5 = 6 * subdiv_step3; + var tmp1x = -cx1 * 2 + cx2; + var tmp1y = -cy1 * 2 + cy2; + var tmp2x = (cx1 - cx2) * 3 + 1; + var tmp2y = (cy1 - cy2) * 3 + 1; + var i = frameIndex * 6; + var curves = this.curves; + curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; + curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; + curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; + curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; + curves[i + 4] = tmp2x * pre5; + curves[i + 5] = tmp2y * pre5; + }, + getCurvePercent: function (frameIndex, percent) { + percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); + var curveIndex = frameIndex * 6; + var curves = this.curves; + var dfx = curves[curveIndex]; + if (!dfx/*LINEAR*/) return percent; + if (dfx == -1/*STEPPED*/) return 0; + var dfy = curves[curveIndex + 1]; + var ddfx = curves[curveIndex + 2]; + var ddfy = curves[curveIndex + 3]; + var dddfx = curves[curveIndex + 4]; + var dddfy = curves[curveIndex + 5]; + var x = dfx, y = dfy; + var i = 10/*BEZIER_SEGMENTS*/ - 2; + while (true) { + if (x >= percent) { + var lastX = x - dfx; + var lastY = y - dfy; + return lastY + (y - lastY) * (percent - lastX) / (x - lastX); + } + if (i == 0) break; + i--; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } +}; + +spine.RotateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, angle, ... + this.frames.length = frameCount * 2; +}; +spine.RotateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, angle) { + frameIndex *= 2; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = angle; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 2]) { // Time is after last frame. + var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 2); + var lastFrameValue = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); + + var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } +}; + +spine.TranslateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.TranslateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; + } +}; + +spine.ScaleTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.ScaleTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 3); + var lastFrameX = frames[frameIndex - 2]; + var lastFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.scaleY) * alpha; + } +}; + +spine.ColorTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, r, g, b, a, ... + this.frames.length = frameCount * 5; +}; +spine.ColorTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 5; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = r; + this.frames[frameIndex + 2] = g; + this.frames[frameIndex + 3] = b; + this.frames[frameIndex + 4] = a; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var slot = skeleton.slots[this.slotIndex]; + + if (time >= frames[frames.length - 5]) { // Time is after last frame. + var i = frames.length - 1; + slot.r = frames[i - 3]; + slot.g = frames[i - 2]; + slot.b = frames[i - 1]; + slot.a = frames[i]; + return; + } + + // Interpolate between the last frame and the current frame. + var frameIndex = spine.binarySearch(frames, time, 5); + var lastFrameR = frames[frameIndex - 4]; + var lastFrameG = frames[frameIndex - 3]; + var lastFrameB = frames[frameIndex - 2]; + var lastFrameA = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); + + var r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent; + var g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent; + var b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent; + var a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent; + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } +}; + +spine.AttachmentTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, ... + this.frames.length = frameCount; + this.attachmentNames = []; // time, ... + this.attachmentNames.length = frameCount; +}; +spine.AttachmentTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }, + apply: function (skeleton, time, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameIndex; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = spine.binarySearch(frames, time, 1) - 1; + + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); + } +}; + +spine.SkeletonData = function () { + this.bones = []; + this.slots = []; + this.skins = []; + this.animations = []; +}; +spine.SkeletonData.prototype = { + defaultSkin: null, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + if (slots[i].name == slotName) return slot[i]; + } + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) return i; + return -1; + }, + /** @return May be null. */ + findSkin: function (skinName) { + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) + if (skins[i].name == skinName) return skins[i]; + return null; + }, + /** @return May be null. */ + findAnimation: function (animationName) { + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) + if (animations[i].name == animationName) return animations[i]; + return null; + } +}; + +spine.Skeleton = function (skeletonData) { + this.data = skeletonData; + + this.bones = []; + for (var i = 0, n = skeletonData.bones.length; i < n; i++) { + var boneData = skeletonData.bones[i]; + var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; + this.bones.push(new spine.Bone(boneData, parent)); + } + + this.slots = []; + this.drawOrder = []; + for (var i = 0, n = skeletonData.slots.length; i < n; i++) { + var slotData = skeletonData.slots[i]; + var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; + var slot = new spine.Slot(slotData, this, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } +}; +spine.Skeleton.prototype = { + x: 0, y: 0, + skin: null, + r: 1, g: 1, b: 1, a: 1, + time: 0, + flipX: false, flipY: false, + /** Updates the world transform for each bone. */ + updateWorldTransform: function () { + var flipX = this.flipX; + var flipY = this.flipY; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].updateWorldTransform(flipX, flipY); + }, + /** Sets the bones and slots to their setup pose values. */ + setToSetupPose: function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }, + setBonesToSetupPose: function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + }, + setSlotsToSetupPose: function () { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(i); + }, + /** @return May return null. */ + getRootBone: function () { + return this.bones.length == 0 ? null : this.bones[0]; + }, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return slots[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return i; + return -1; + }, + setSkinByName: function (skinName) { + var skin = this.data.findSkin(skinName); + if (!skin) throw "Skin not found: " + skinName; + this.setSkin(skin); + }, + /** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments + * from the new skin are attached if the corresponding attachment from the old skin was attached. + * @param newSkin May be null. */ + setSkin: function (newSkin) { + if (this.skin && newSkin) newSkin._attachAll(this, this.skin); + this.skin = newSkin; + }, + /** @return May be null. */ + getAttachmentBySlotName: function (slotName, attachmentName) { + return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); + }, + /** @return May be null. */ + getAttachmentBySlotIndex: function (slotIndex, attachmentName) { + if (this.skin) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) return attachment; + } + if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }, + /** @param attachmentName May be null. */ + setAttachment: function (slotName, attachmentName) { + var slots = this.slots; + for (var i = 0, n = slots.size; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; + } + slot.setAttachment(attachment); + return; + } + } + throw "Slot not found: " + slotName; + }, + update: function (delta) { + time += delta; + } +}; + +spine.AttachmentType = { + region: 0 +}; + +spine.RegionAttachment = function () { + this.offset = []; + this.offset.length = 8; + this.uvs = []; + this.uvs.length = 8; +}; +spine.RegionAttachment.prototype = { + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + width: 0, height: 0, + rendererObject: null, + regionOffsetX: 0, regionOffsetY: 0, + regionWidth: 0, regionHeight: 0, + regionOriginalWidth: 0, regionOriginalHeight: 0, + setUVs: function (u, v, u2, v2, rotate) { + var uvs = this.uvs; + if (rotate) { + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v2; + uvs[4/*X3*/] = u; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v; + uvs[0/*X1*/] = u2; + uvs[1/*Y1*/] = v2; + } else { + uvs[0/*X1*/] = u; + uvs[1/*Y1*/] = v2; + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v; + uvs[4/*X3*/] = u2; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v2; + } + }, + updateOffset: function () { + var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; + var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; + var localX2 = localX + this.regionWidth * regionScaleX; + var localY2 = localY + this.regionHeight * regionScaleY; + var radians = this.rotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[0/*X1*/] = localXCos - localYSin; + offset[1/*Y1*/] = localYCos + localXSin; + offset[2/*X2*/] = localXCos - localY2Sin; + offset[3/*Y2*/] = localY2Cos + localXSin; + offset[4/*X3*/] = localX2Cos - localY2Sin; + offset[5/*Y3*/] = localY2Cos + localX2Sin; + offset[6/*X4*/] = localX2Cos - localYSin; + offset[7/*Y4*/] = localYCos + localX2Sin; + }, + computeVertices: function (x, y, bone, vertices) { + x += bone.worldX; + y += bone.worldY; + var m00 = bone.m00; + var m01 = bone.m01; + var m10 = bone.m10; + var m11 = bone.m11; + var offset = this.offset; + vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; + vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; + vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; + vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; + vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; + vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; + vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; + vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; + } +} + +spine.AnimationStateData = function (skeletonData) { + this.skeletonData = skeletonData; + this.animationToMixTime = {}; +}; +spine.AnimationStateData.prototype = { + defaultMix: 0, + setMixByName: function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (!from) throw "Animation not found: " + fromName; + var to = this.skeletonData.findAnimation(toName); + if (!to) throw "Animation not found: " + toName; + this.setMix(from, to, duration); + }, + setMix: function (from, to, duration) { + this.animationToMixTime[from.name + ":" + to.name] = duration; + }, + getMix: function (from, to) { + var time = this.animationToMixTime[from.name + ":" + to.name]; + return time ? time : this.defaultMix; + } +}; + +spine.AnimationState = function (stateData) { + this.data = stateData; + this.queue = []; +}; +spine.AnimationState.prototype = { + current: null, + previous: null, + currentTime: 0, + previousTime: 0, + currentLoop: false, + previousLoop: false, + mixTime: 0, + mixDuration: 0, + update: function (delta) { + this.currentTime += delta; + this.previousTime += delta; + this.mixTime += delta; + + if (this.queue.length > 0) { + var entry = this.queue[0]; + if (this.currentTime >= entry.delay) { + this._setAnimation(entry.animation, entry.loop); + this.queue.shift(); + } + } + }, + apply: function (skeleton) { + if (!this.current) return; + if (this.previous) { + this.previous.apply(skeleton, this.previousTime, this.previousLoop); + var alpha = this.mixTime / this.mixDuration; + if (alpha >= 1) { + alpha = 1; + this.previous = null; + } + this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); + } else + this.current.apply(skeleton, this.currentTime, this.currentLoop); + }, + clearAnimation: function () { + this.previous = null; + this.current = null; + this.queue.length = 0; + }, + _setAnimation: function (animation, loop) { + this.previous = null; + if (animation && this.current) { + this.mixDuration = this.data.getMix(this.current, animation); + if (this.mixDuration > 0) { + this.mixTime = 0; + this.previous = this.current; + this.previousTime = this.currentTime; + this.previousLoop = this.currentLoop; + } + } + this.current = animation; + this.currentLoop = loop; + this.currentTime = 0; + }, + /** @see #setAnimation(Animation, Boolean) */ + setAnimationByName: function (animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.setAnimation(animation, loop); + }, + /** Set the current animation. Any queued animations are cleared and the current animation time is set to 0. + * @param animation May be null. */ + setAnimation: function (animation, loop) { + this.queue.length = 0; + this._setAnimation(animation, loop); + }, + /** @see #addAnimation(Animation, Boolean, Number) */ + addAnimationByName: function (animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + this.addAnimation(animation, loop, delay); + }, + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + addAnimation: function (animation, loop, delay) { + var entry = {}; + entry.animation = animation; + entry.loop = loop; + + if (!delay || delay <= 0) { + var previousAnimation = this.queue.length == 0 ? this.current : this.queue[this.queue.length - 1].animation; + if (previousAnimation != null) + delay = previousAnimation.duration - this.data.getMix(previousAnimation, animation) + (delay || 0); + else + delay = 0; + } + entry.delay = delay; + + this.queue.push(entry); + }, + /** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */ + isComplete: function () { + return !this.current || this.currentTime >= this.current.duration; + } +}; + +spine.SkeletonJson = function (attachmentLoader) { + this.attachmentLoader = attachmentLoader; +}; +spine.SkeletonJson.prototype = { + scale: 1, + readSkeletonData: function (root) { + var skeletonData = new spine.SkeletonData(); + + // Bones. + var bones = root["bones"]; + for (var i = 0, n = bones.length; i < n; i++) { + var boneMap = bones[i]; + var parent = null; + if (boneMap["parent"]) { + parent = skeletonData.findBone(boneMap["parent"]); + if (!parent) throw "Parent bone not found: " + boneMap["parent"]; + } + var boneData = new spine.BoneData(boneMap["name"], parent); + boneData.length = (boneMap["length"] || 0) * this.scale; + boneData.x = (boneMap["x"] || 0) * this.scale; + boneData.y = (boneMap["y"] || 0) * this.scale; + boneData.rotation = (boneMap["rotation"] || 0); + boneData.scaleX = boneMap["scaleX"] || 1; + boneData.scaleY = boneMap["scaleY"] || 1; + skeletonData.bones.push(boneData); + } + + // Slots. + var slots = root["slots"]; + for (var i = 0, n = slots.length; i < n; i++) { + var slotMap = slots[i]; + var boneData = skeletonData.findBone(slotMap["bone"]); + if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; + var slotData = new spine.SlotData(slotMap["name"], boneData); + + var color = slotMap["color"]; + if (color) { + slotData.r = spine.SkeletonJson.toColor(color, 0); + slotData.g = spine.SkeletonJson.toColor(color, 1); + slotData.b = spine.SkeletonJson.toColor(color, 2); + slotData.a = spine.SkeletonJson.toColor(color, 3); + } + + slotData.attachmentName = slotMap["attachment"]; + + skeletonData.slots.push(slotData); + } + + // Skins. + var skins = root["skins"]; + for (var skinName in skins) { + if (!skins.hasOwnProperty(skinName)) continue; + var skinMap = skins[skinName]; + var skin = new spine.Skin(skinName); + for (var slotName in skinMap) { + if (!skinMap.hasOwnProperty(slotName)) continue; + var slotIndex = skeletonData.findSlotIndex(slotName); + var slotEntry = skinMap[slotName]; + for (var attachmentName in slotEntry) { + if (!slotEntry.hasOwnProperty(attachmentName)) continue; + var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); + if (attachment != null) skin.addAttachment(slotIndex, attachmentName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + + // Animations. + var animations = root["animations"]; + for (var animationName in animations) { + if (!animations.hasOwnProperty(animationName)) continue; + this.readAnimation(animationName, animations[animationName], skeletonData); + } + + return skeletonData; + }, + readAttachment: function (skin, name, map) { + name = map["name"] || name; + + var type = spine.AttachmentType[map["type"] || "region"]; + + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); + attachment.x = (map["x"] || 0) * this.scale; + attachment.y = (map["y"] || 0) * this.scale; + attachment.scaleX = map["scaleX"] || 1; + attachment.scaleY = map["scaleY"] || 1; + attachment.rotation = map["rotation"] || 0; + attachment.width = (map["width"] || 32) * this.scale; + attachment.height = (map["height"] || 32) * this.scale; + attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; + } + + throw "Unknown attachment type: " + type; + }, + + readAnimation: function (name, map, skeletonData) { + var timelines = []; + var duration = 0; + + var bones = map["bones"]; + for (var boneName in bones) { + if (!bones.hasOwnProperty(boneName)) continue; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) throw "Bone not found: " + boneName; + var boneMap = bones[boneName]; + + for (var timelineName in boneMap) { + if (!boneMap.hasOwnProperty(timelineName)) continue; + var values = boneMap[timelineName]; + if (timelineName == "rotate") { + var timeline = new spine.RotateTimeline(values.length); + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); + + } else if (timelineName == "translate" || timelineName == "scale") { + var timeline; + var timelineScale = 1; + if (timelineName == "scale") + timeline = new spine.ScaleTimeline(values.length); + else { + timeline = new spine.TranslateTimeline(values.length); + timelineScale = this.scale; + } + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var x = (valueMap["x"] || 0) * timelineScale; + var y = (valueMap["y"] || 0) * timelineScale; + timeline.setFrame(frameIndex, valueMap["time"], x, y); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); + + } else + throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; + } + } + var slots = map["slots"]; + for (var slotName in slots) { + if (!slots.hasOwnProperty(slotName)) continue; + var slotMap = slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + + for (var timelineName in slotMap) { + if (!slotMap.hasOwnProperty(timelineName)) continue; + var values = slotMap[timelineName]; + if (timelineName == "color") { + var timeline = new spine.ColorTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var color = valueMap["color"]; + var r = spine.SkeletonJson.toColor(color, 0); + var g = spine.SkeletonJson.toColor(color, 1); + var b = spine.SkeletonJson.toColor(color, 2); + var a = spine.SkeletonJson.toColor(color, 3); + timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); + spine.SkeletonJson.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); + + } else if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + + } else + throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; + } + } + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + } +}; +spine.SkeletonJson.readCurve = function (timeline, frameIndex, valueMap) { + var curve = valueMap["curve"]; + if (!curve) return; + if (curve == "stepped") + timeline.curves.setStepped(frameIndex); + else if (curve instanceof Array) + timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); +}; +spine.SkeletonJson.toColor = function (hexString, colorIndex) { + if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; + return parseInt(hexString.substring(colorIndex * 2, 2), 16) / 255; +}; + +spine.Atlas = function (atlasText, textureLoader) { + this.textureLoader = textureLoader; + this.pages = []; + this.regions = []; + + var reader = new spine.AtlasReader(atlasText); + var tuple = []; + tuple.length = 4; + var page = null; + while (true) { + var line = reader.readLine(); + if (line == null) break; + line = reader.trim(line); + if (line.length == 0) + page = null; + else if (!page) { + page = new spine.AtlasPage(); + page.name = line; + + page.format = spine.Atlas.Format[reader.readValue()]; + + reader.readTuple(tuple); + page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; + page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; + + var direction = reader.readValue(); + page.uWrap = spine.Atlas.TextureWrap.clampToEdge; + page.vWrap = spine.Atlas.TextureWrap.clampToEdge; + if (direction == "x") + page.uWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "y") + page.vWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; + + textureLoader.load(page, line); + + this.pages.push(page); + + } else { + var region = new spine.AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = reader.readValue() == "true"; + + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + + if (reader.readTuple(tuple) == 4) { // split is optional + region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + + region.index = parseInt(reader.readValue()); + + this.regions.push(region); + } + } +}; +spine.Atlas.prototype = { + findRegion: function (name) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) + if (regions[i].name == name) return regions[i]; + return null; + }, + dispose: function () { + var pages = this.pages; + for (var i = 0, n = pages.length; i < n; i++) + this.textureLoader.unload(pages[i].rendererObject); + }, + updateUVs: function (page) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) { + var region = regions[i]; + if (region.page != page) continue; + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.rotate) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + } + } +}; + +spine.Atlas.Format = { + alpha: 0, + intensity: 1, + luminanceAlpha: 2, + rgb565: 3, + rgba4444: 4, + rgb888: 5, + rgba8888: 6 +}; + +spine.Atlas.TextureFilter = { + nearest: 0, + linear: 1, + mipMap: 2, + mipMapNearestNearest: 3, + mipMapLinearNearest: 4, + mipMapNearestLinear: 5, + mipMapLinearLinear: 6 +}; + +spine.Atlas.TextureWrap = { + mirroredRepeat: 0, + clampToEdge: 1, + repeat: 2 +}; + +spine.AtlasPage = function () {}; +spine.AtlasPage.prototype = { + name: null, + format: null, + minFilter: null, + magFilter: null, + uWrap: null, + vWrap: null, + rendererObject: null, + width: 0, + height: 0 +}; + +spine.AtlasRegion = function () {}; +spine.AtlasRegion.prototype = { + page: null, + name: null, + x: 0, y: 0, + width: 0, height: 0, + u: 0, v: 0, u2: 0, v2: 0, + offsetX: 0, offsetY: 0, + originalWidth: 0, originalHeight: 0, + index: 0, + rotate: false, + splits: null, + pads: null, +}; + +spine.AtlasReader = function (text) { + this.lines = text.split(/\r\n|\r|\n/); +}; +spine.AtlasReader.prototype = { + index: 0, + trim: function (value) { + return value.replace(/^\s+|\s+$/g, ""); + }, + readLine: function () { + if (this.index >= this.lines.length) return null; + return this.lines[this.index++]; + }, + readValue: function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + return this.trim(line.substring(colon + 1)); + }, + /** Returns the number of tuple values read (2 or 4). */ + readTuple: function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + var i = 0, lastMatch= colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) { + if (i == 0) throw "Invalid line: " + line; + break; + } + tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); + lastMatch = comma + 1; + } + tuple[i] = this.trim(line.substring(lastMatch)); + return i + 1; + } +} + +spine.AtlasAttachmentLoader = function (atlas) { + this.atlas = atlas; +} +spine.AtlasAttachmentLoader.prototype = { + newAttachment: function (skin, type, name) { + switch (type) { + case spine.AttachmentType.region: + var region = this.atlas.findRegion(name); + if (!region) throw "Region not found in atlas: " + name + " (" + type + ")"; + var attachment = new spine.RegionAttachment(name); + attachment.rendererObject = region; + attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + throw "Unknown attachment type: " + type; + } +} + +PIXI.AnimCache = {}; +spine.Bone.yDown = true; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +/** + * This object is one that will allow you to specify custom rendering functions based on render type + * + * @class CustomRenderable + * @extends DisplayObject + * @constructor + */ +PIXI.CustomRenderable = function() +{ + PIXI.DisplayObject.call( this ); + +} + +// constructor +PIXI.CustomRenderable.prototype = Object.create( PIXI.DisplayObject.prototype ); +PIXI.CustomRenderable.prototype.constructor = PIXI.CustomRenderable; + +/** + * If this object is being rendered by a CanvasRenderer it will call this callback + * + * @method renderCanvas + * @param renderer {CanvasRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderCanvas = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback to initialize + * + * @method initWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.initWebGL = function(renderer) +{ + // override! +} + +/** + * If this object is being rendered by a WebGLRenderer it will call this callback + * + * @method renderWebGL + * @param renderer {WebGLRenderer} The renderer instance + */ +PIXI.CustomRenderable.prototype.renderWebGL = function(renderGroup, projectionMatrix) +{ + // not sure if both needed? but ya have for now! + // override! +} + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.BaseTextureCache = {}; +PIXI.texturesToUpdate = []; +PIXI.texturesToDestroy = []; + +/** + * A texture stores the information that represents an image. All textures have a base texture + * + * @class BaseTexture + * @uses EventTarget + * @constructor + * @param source {String} the source object (image or canvas) + */ +PIXI.BaseTexture = function(source) +{ + PIXI.EventTarget.call( this ); + + /** + * [read-only] The width of the base texture set when the image has loaded + * + * @property width + * @type Number + * @readOnly + */ + this.width = 100; + + /** + * [read-only] The height of the base texture set when the image has loaded + * + * @property height + * @type Number + * @readOnly + */ + this.height = 100; + + /** + * [read-only] Describes if the base texture has loaded or not + * + * @property hasLoaded + * @type Boolean + * @readOnly + */ + this.hasLoaded = false; + + /** + * The source that is loaded to create the texture + * + * @property source + * @type Image + */ + this.source = source; + + if(!source)return; + + if(this.source instanceof Image || this.source instanceof HTMLImageElement) + { + if(this.source.complete) + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + else + { + + var scope = this; + this.source.onload = function(){ + + scope.hasLoaded = true; + scope.width = scope.source.width; + scope.height = scope.source.height; + + // add it to somewhere... + PIXI.texturesToUpdate.push(scope); + scope.dispatchEvent( { type: 'loaded', content: scope } ); + } + // this.image.src = imageUrl; + } + } + else + { + this.hasLoaded = true; + this.width = this.source.width; + this.height = this.source.height; + + PIXI.texturesToUpdate.push(this); + } + + this._powerOf2 = false; +} + +PIXI.BaseTexture.prototype.constructor = PIXI.BaseTexture; + +/** + * Destroys this base texture + * + * @method destroy + */ +PIXI.BaseTexture.prototype.destroy = function() +{ + if(this.source instanceof Image) + { + this.source.src = null; + } + this.source = null; + PIXI.texturesToDestroy.push(this); +} + +/** + * Helper function that returns a base texture based on an image url + * If the image is not in the base texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @return BaseTexture + */ +PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) +{ + var baseTexture = PIXI.BaseTextureCache[imageUrl]; + if(!baseTexture) + { + // new Image() breaks tex loading in some versions of Chrome. + // See https://code.google.com/p/chromium/issues/detail?id=238071 + var image = new Image();//document.createElement('img'); + if (crossorigin) + { + image.crossOrigin = ''; + } + image.src = imageUrl; + baseTexture = new PIXI.BaseTexture(image); + PIXI.BaseTextureCache[imageUrl] = baseTexture; + } + + return baseTexture; +} + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.TextureCache = {}; +PIXI.FrameCache = {}; + +/** + * A texture stores the information that represents an image or part of an image. It cannot be added + * to the display list directly. To do this use PIXI.Sprite. If no frame is provided then the whole image is used + * + * @class Texture + * @uses EventTarget + * @constructor + * @param baseTexture {BaseTexture} The base texture source to create the texture from + * @param frame {Rectangle} The rectangle frame of the texture to show + */ +PIXI.Texture = function(baseTexture, frame) +{ + PIXI.EventTarget.call( this ); + + if(!frame) + { + this.noFrame = true; + frame = new PIXI.Rectangle(0,0,1,1); + } + + if(baseTexture instanceof PIXI.Texture) + baseTexture = baseTexture.baseTexture; + + /** + * The base texture of this texture + * + * @property baseTexture + * @type BaseTexture + */ + this.baseTexture = baseTexture; + + /** + * The frame specifies the region of the base texture that this texture uses + * + * @property frame + * @type Rectangle + */ + this.frame = frame; + + /** + * The trim point + * + * @property trim + * @type Point + */ + this.trim = new PIXI.Point(); + + this.scope = this; + + if(baseTexture.hasLoaded) + { + if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + //console.log(frame) + + this.setFrame(frame); + } + else + { + var scope = this; + baseTexture.addEventListener( 'loaded', function(){ scope.onBaseTextureLoaded()} ); + } +} + +PIXI.Texture.prototype.constructor = PIXI.Texture; + +/** + * Called when the base texture is loaded + * + * @method onBaseTextureLoaded + * @param event + * @private + */ +PIXI.Texture.prototype.onBaseTextureLoaded = function(event) +{ + var baseTexture = this.baseTexture; + baseTexture.removeEventListener( 'loaded', this.onLoaded ); + + if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); + this.noFrame = false; + this.width = this.frame.width; + this.height = this.frame.height; + + this.scope.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Destroys this texture + * + * @method destroy + * @param destroyBase {Boolean} Whether to destroy the base texture as well + */ +PIXI.Texture.prototype.destroy = function(destroyBase) +{ + if(destroyBase)this.baseTexture.destroy(); +} + +/** + * Specifies the rectangle region of the baseTexture + * + * @method setFrame + * @param frame {Rectangle} The frame of the texture to set it to + */ +PIXI.Texture.prototype.setFrame = function(frame) +{ + this.frame = frame; + this.width = frame.width; + this.height = frame.height; + + if(frame.x + frame.width > this.baseTexture.width || frame.y + frame.height > this.baseTexture.height) + { + throw new Error("Texture Error: frame does not fit inside the base Texture dimensions " + this); + } + + this.updateFrame = true; + + PIXI.Texture.frameUpdates.push(this); + //this.dispatchEvent( { type: 'update', content: this } ); +} + +/** + * Helper function that returns a texture based on an image url + * If the image is not in the texture cache it will be created and loaded + * + * @static + * @method fromImage + * @param imageUrl {String} The image url of the texture + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + * @return Texture + */ +PIXI.Texture.fromImage = function(imageUrl, crossorigin) +{ + var texture = PIXI.TextureCache[imageUrl]; + + if(!texture) + { + texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); + PIXI.TextureCache[imageUrl] = texture; + } + + return texture; +} + +/** + * Helper function that returns a texture based on a frame id + * If the frame id is not in the texture cache an error will be thrown + * + * @static + * @method fromFrame + * @param frameId {String} The frame id of the texture + * @return Texture + */ +PIXI.Texture.fromFrame = function(frameId) +{ + var texture = PIXI.TextureCache[frameId]; + if(!texture)throw new Error("The frameId '"+ frameId +"' does not exist in the texture cache " + this); + return texture; +} + +/** + * Helper function that returns a texture based on a canvas element + * If the canvas is not in the texture cache it will be created and loaded + * + * @static + * @method fromCanvas + * @param canvas {Canvas} The canvas element source of the texture + * @return Texture + */ +PIXI.Texture.fromCanvas = function(canvas) +{ + var baseTexture = new PIXI.BaseTexture(canvas); + return new PIXI.Texture(baseTexture); +} + + +/** + * Adds a texture to the textureCache. + * + * @static + * @method addTextureToCache + * @param texture {Texture} + * @param id {String} the id that the texture will be stored against. + */ +PIXI.Texture.addTextureToCache = function(texture, id) +{ + PIXI.TextureCache[id] = texture; +} + +/** + * Remove a texture from the textureCache. + * + * @static + * @method removeTextureFromCache + * @param id {String} the id of the texture to be removed + * @return {Texture} the texture that was removed + */ +PIXI.Texture.removeTextureFromCache = function(id) +{ + var texture = PIXI.TextureCache[id] + PIXI.TextureCache[id] = null; + return texture; +} + +// this is more for webGL.. it contains updated frames.. +PIXI.Texture.frameUpdates = []; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. + + __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. + Otherwise black rectangles will be drawn instead. + + RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: + + var renderTexture = new PIXI.RenderTexture(800, 600); + var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); + sprite.position.x = 800/2; + sprite.position.y = 600/2; + sprite.anchor.x = 0.5; + sprite.anchor.y = 0.5; + renderTexture.render(sprite); + + Sprite in this case will be rendered to 0,0 position. To render this sprite at center DisplayObjectContainer should be used: + + var doc = new PIXI.DisplayObjectContainer(); + doc.addChild(sprite); + renderTexture.render(doc); // Renders to center of renderTexture + + @class RenderTexture + @extends Texture + @constructor + @param width {Number} The width of the render texture + @param height {Number} The height of the render texture + */ +PIXI.RenderTexture = function(width, height) +{ + PIXI.EventTarget.call( this ); + + this.width = width || 100; + this.height = height || 100; + + this.indetityMatrix = PIXI.mat3.create(); + + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + if(PIXI.gl) + { + this.initWebGL(); + } + else + { + this.initCanvas(); + } +} + +PIXI.RenderTexture.prototype = Object.create( PIXI.Texture.prototype ); +PIXI.RenderTexture.prototype.constructor = PIXI.RenderTexture; + +/** + * Initializes the webgl data for this texture + * + * @method initWebGL + * @private + */ +PIXI.RenderTexture.prototype.initWebGL = function() +{ + var gl = PIXI.gl; + this.glFramebuffer = gl.createFramebuffer(); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + this.glFramebuffer.width = this.width; + this.glFramebuffer.height = this.height; + + this.baseTexture = new PIXI.BaseTexture(); + + this.baseTexture.width = this.width; + this.baseTexture.height = this.height; + + this.baseTexture._glTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + this.baseTexture.isRender = true; + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.baseTexture._glTexture, 0); + + // create a projection matrix.. + this.projection = new PIXI.Point(this.width/2 , this.height/2); + + // set the correct render function.. + this.render = this.renderWebGL; + + +} + + +PIXI.RenderTexture.prototype.resize = function(width, height) +{ + + this.width = width; + this.height = height; + + if(PIXI.gl) + { + this.projection.x = this.width/2 + this.projection.y = this.height/2; + + var gl = PIXI.gl; + gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } + else + { + + this.frame.width = this.width + this.frame.height = this.height; + this.renderer.resize(this.width, this.height); + } +} + +/** + * Initializes the canvas data for this texture + * + * @method initCanvas + * @private + */ +PIXI.RenderTexture.prototype.initCanvas = function() +{ + this.renderer = new PIXI.CanvasRenderer(this.width, this.height, null, 0); + + this.baseTexture = new PIXI.BaseTexture(this.renderer.view); + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + + this.render = this.renderCanvas; +} + +/** + * This function will draw the display object to the texture. + * + * @method renderWebGL + * @param displayObject {DisplayObject} The display object to render this texture on + * @param clear {Boolean} If true the texture will be cleared before the displayObject is drawn + * @private + */ +PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, clear) +{ + var gl = PIXI.gl; + + // enable the alpha color mask.. + gl.colorMask(true, true, true, true); + + gl.viewport(0, 0, this.width, this.height); + + gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); + + if(clear) + { + gl.clearColor(0,0,0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + + // THIS WILL MESS WITH HIT TESTING! + var children = displayObject.children; + + //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; + displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; + // modify to flip... + displayObject.worldTransform[4] = -1; + displayObject.worldTransform[5] = this.projection.y * 2; + + + if(position) + { + displayObject.worldTransform[2] = position.x; + displayObject.worldTransform[5] -= position.y; + } + + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + + for(var i=0,j=children.length; i} assetURLs an array of image/sprite sheet urls that you would like loaded + * supported. Supported image formats include "jpeg", "jpg", "png", "gif". Supported + * sprite sheet data formats only include "JSON" at this time. Supported bitmap font + * data formats include "xml" and "fnt". + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.AssetLoader = function(assetURLs, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The array of asset URLs that are going to be loaded + * + * @property assetURLs + * @type Array + */ + this.assetURLs = assetURLs; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * Maps file extension to loader types + * + * @property loadersByType + * @type Object + */ + this.loadersByType = { + "jpg": PIXI.ImageLoader, + "jpeg": PIXI.ImageLoader, + "png": PIXI.ImageLoader, + "gif": PIXI.ImageLoader, + "json": PIXI.JsonLoader, + "anim": PIXI.SpineLoader, + "xml": PIXI.BitmapFontLoader, + "fnt": PIXI.BitmapFontLoader + }; + + +}; + +/** + * Fired when an item has loaded + * @event onProgress + */ + +/** + * Fired when all the assets have loaded + * @event onComplete + */ + +// constructor +PIXI.AssetLoader.prototype.constructor = PIXI.AssetLoader; + +/** + * Starts loading the assets sequentially + * + * @method load + */ +PIXI.AssetLoader.prototype.load = function() +{ + var scope = this; + + this.loadCount = this.assetURLs.length; + + for (var i=0; i < this.assetURLs.length; i++) + { + var fileName = this.assetURLs[i]; + var fileType = fileName.split(".").pop().toLowerCase(); + + var loaderClass = this.loadersByType[fileType]; + if(!loaderClass) + throw new Error(fileType + " is an unsupported file type"); + + var loader = new loaderClass(fileName, this.crossorigin); + + loader.addEventListener("loaded", function() + { + scope.onAssetLoaded(); + }); + loader.load(); + } +}; + +/** + * Invoked after each file is loaded + * + * @method onAssetLoaded + * @private + */ +PIXI.AssetLoader.prototype.onAssetLoaded = function() +{ + this.loadCount--; + this.dispatchEvent({type: "onProgress", content: this}); + if(this.onProgress) this.onProgress(); + + if(this.loadCount == 0) + { + this.dispatchEvent({type: "onComplete", content: this}); + if(this.onComplete) this.onComplete(); + } +}; + + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The json file loader is used to load in JSON data and parsing it + * When loaded this class will dispatch a "loaded" event + * If load failed this class will dispatch a "error" event + * + * @class JsonLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.JsonLoader = function (url, crossorigin) { + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * [read-only] Whether the data has loaded yet + * + * @property loaded + * @type Boolean + * @readOnly + */ + this.loaded = false; + +}; + +// constructor +PIXI.JsonLoader.prototype.constructor = PIXI.JsonLoader; + +/** + * Loads the JSON data + * + * @method load + */ +PIXI.JsonLoader.prototype.load = function () { + this.ajaxRequest = new AjaxRequest(); + var scope = this; + this.ajaxRequest.onreadystatechange = function () { + scope.onJSONLoaded(); + }; + + this.ajaxRequest.open("GET", this.url, true); + if (this.ajaxRequest.overrideMimeType) this.ajaxRequest.overrideMimeType("application/json"); + this.ajaxRequest.send(null); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.JsonLoader.prototype.onJSONLoaded = function () { + if (this.ajaxRequest.readyState == 4) { + if (this.ajaxRequest.status == 200 || window.location.href.indexOf("http") == -1) { + this.json = JSON.parse(this.ajaxRequest.responseText); + + if(this.json.frames) + { + // sprite sheet + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); + + } + else if(this.json.bones) + { + // spine animation + var spineJsonParser = new spine.SkeletonJson(); + var skeletonData = spineJsonParser.readSkeletonData(this.json); + PIXI.AnimCache[this.url] = skeletonData; + this.onLoaded(); + } + else + { + this.onLoaded(); + } + } + else + { + this.onError(); + } + } +}; + +/** + * Invoke when json file loaded + * + * @method onLoaded + * @private + */ +PIXI.JsonLoader.prototype.onLoaded = function () { + this.loaded = true; + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * Invoke when error occured + * + * @method onError + * @private + */ +PIXI.JsonLoader.prototype.onError = function () { + this.dispatchEvent({ + type: "error", + content: this + }); +}; +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The sprite sheet loader is used to load in JSON sprite sheet data + * To generate the data you can use http://www.codeandweb.com/texturepacker and publish the "JSON" format + * There is a free version so thats nice, although the paid version is great value for money. + * It is highly recommended to use Sprite sheets (also know as texture atlas") as it means sprite"s can be batched and drawn together for highly increased rendering speed. + * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * This loader will also load the image file that the Spritesheet points to as well as the data. + * When loaded this class will dispatch a "loaded" event + * + * @class SpriteSheetLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the sprite sheet JSON file + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ + +PIXI.SpriteSheetLoader = function (url, crossorigin) { + /* + * i use texture packer to load the assets.. + * http://www.codeandweb.com/texturepacker + * make sure to set the format as "JSON" + */ + PIXI.EventTarget.call(this); + + /** + * The url of the bitmap font data + * + * @property url + * @type String + */ + this.url = url; + + /** + * Whether the requests should be treated as cross origin + * + * @property crossorigin + * @type Boolean + */ + this.crossorigin = crossorigin; + + /** + * [read-only] The base url of the bitmap font data + * + * @property baseUrl + * @type String + * @readOnly + */ + this.baseUrl = url.replace(/[^\/]*$/, ""); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = null; + + /** + * The frames of the sprite sheet + * + * @property frames + * @type Object + */ + this.frames = {}; +}; + +// constructor +PIXI.SpriteSheetLoader.prototype.constructor = PIXI.SpriteSheetLoader; + +/** + * This will begin loading the JSON file + * + * @method load + */ +PIXI.SpriteSheetLoader.prototype.load = function () { + var scope = this; + var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); + jsonLoader.addEventListener("loaded", function (event) { + scope.json = event.content.json; + scope.onJSONLoaded(); + }); + jsonLoader.load(); +}; + +/** + * Invoke when JSON file is loaded + * + * @method onJSONLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onJSONLoaded = function () { + var scope = this; + var textureUrl = this.baseUrl + this.json.meta.image; + var image = new PIXI.ImageLoader(textureUrl, this.crossorigin); + var frameData = this.json.frames; + + this.texture = image.texture.baseTexture; + image.addEventListener("loaded", function (event) { + scope.onLoaded(); + }); + + for (var i in frameData) { + var rect = frameData[i].frame; + if (rect) { + PIXI.TextureCache[i] = new PIXI.Texture(this.texture, { + x: rect.x, + y: rect.y, + width: rect.w, + height: rect.h + }); + if (frameData[i].trimmed) { + //var realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].realSize = frameData[i].spriteSourceSize; + PIXI.TextureCache[i].trim.x = 0; // (realSize.x / rect.w) + // calculate the offset! + } + } + } + + image.load(); +}; +/** + * Invoke when all files are loaded (json and texture) + * + * @method onLoaded + * @private + */ +PIXI.SpriteSheetLoader.prototype.onLoaded = function () { + this.dispatchEvent({ + type: "loaded", + content: this + }); +}; + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +/** + * The image loader class is responsible for loading images file formats ("jpeg", "jpg", "png" and "gif") + * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though PIXI.Texture.fromFrameId() and PIXI.Sprite.fromFromeId() + * When loaded this class will dispatch a 'loaded' event + * + * @class ImageLoader + * @uses EventTarget + * @constructor + * @param url {String} The url of the image + * @param crossorigin {Boolean} Whether requests should be treated as crossorigin + */ +PIXI.ImageLoader = function(url, crossorigin) +{ + PIXI.EventTarget.call(this); + + /** + * The texture being loaded + * + * @property texture + * @type Texture + */ + this.texture = PIXI.Texture.fromImage(url, crossorigin); + + /** + * if the image is loaded with loadFramedSpriteSheet + * frames will contain the sprite sheet frames + * + */ + this.frames = []; +}; + +// constructor +PIXI.ImageLoader.prototype.constructor = PIXI.ImageLoader; + +/** + * Loads image or takes it from cache + * + * @method load + */ +PIXI.ImageLoader.prototype.load = function() +{ + if(!this.texture.baseTexture.hasLoaded) + { + var scope = this; + this.texture.baseTexture.addEventListener("loaded", function() + { + scope.onLoaded(); + }); + } + else + { + this.onLoaded(); + } +}; + +/** + * Invoked when image file is loaded or it is already cached and ready to use + * + * @method onLoaded + * @private + */ +PIXI.ImageLoader.prototype.onLoaded = function() +{ + this.dispatchEvent({type: "loaded", content: this}); +}; + +/** + * Loads image and split it to uniform sized frames + * + * + * @method loadFramedSpriteSheet + * @param frameWidth {Number} with of each frame + * @param frameHeight {Number} height of each frame + * @param textureName {String} if given, the frames will be cached in - format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y x1 && x < x1 + this.width) + if(x >= x1 && x <= x1 + this.width) { var y1 = this.y; - - if(y > y1 && y < y1 + this.height) + + if(y >= y1 && y <= y1 + this.height) { return true; } @@ -165,7 +165,7 @@ PIXI.Rectangle.prototype.constructor = PIXI.Rectangle; * @class Polygon * @constructor * @param points* {Array|Array|Point...|Number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arugments passed can be + * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be * all the points of the polygon e.g. `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the * arguments passed can be flat x,y values e.g. `new PIXI.Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are * Numbers. @@ -232,9 +232,9 @@ PIXI.Polygon.prototype.contains = function(x, y) return inside; } +// constructor PIXI.Polygon.prototype.constructor = PIXI.Polygon; - /** * @author Chad Engler */ @@ -256,7 +256,7 @@ PIXI.Circle = function(x, y, radius) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number @@ -306,6 +306,7 @@ PIXI.Circle.prototype.contains = function(x, y) return (dx + dy <= r2); } +// constructor PIXI.Circle.prototype.constructor = PIXI.Circle; @@ -320,8 +321,8 @@ PIXI.Circle.prototype.constructor = PIXI.Circle; * @constructor * @param x {Number} The X coord of the upper-left corner of the framing rectangle of this ellipse * @param y {Number} The Y coord of the upper-left corner of the framing rectangle of this ellipse - * @param width {Number} The overall height of this ellipse - * @param height {Number} The overall width of this ellipse + * @param width {Number} The overall width of this ellipse + * @param height {Number} The overall height of this ellipse */ PIXI.Ellipse = function(x, y, width, height) { @@ -331,21 +332,21 @@ PIXI.Ellipse = function(x, y, width, height) * @default 0 */ this.x = x || 0; - + /** * @property y * @type Number * @default 0 */ this.y = y || 0; - + /** * @property width * @type Number * @default 0 */ this.width = width || 0; - + /** * @property height * @type Number @@ -394,11 +395,11 @@ PIXI.Ellipse.getBounds = function() return new PIXI.Rectangle(this.x, this.y, this.width, this.height); } +// constructor PIXI.Ellipse.prototype.constructor = PIXI.Ellipse; - /* * A lighter version of the rad gl-matrix created by Brandon Jones, Colin MacKenzie IV * you both rock! @@ -426,7 +427,7 @@ PIXI.mat3.create = function() matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -442,7 +443,7 @@ PIXI.mat3.identity = function(matrix) matrix[6] = 0; matrix[7] = 0; matrix[8] = 1; - + return matrix; } @@ -469,35 +470,35 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat3.multiply = function (mat, mat2, dest) +PIXI.mat3.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[3], a11 = mat[4], a12 = mat[5], a20 = mat[6], a21 = mat[7], a22 = mat[8], - + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b10 = mat2[3], b11 = mat2[4], b12 = mat2[5], b20 = mat2[6], b21 = mat2[7], b22 = mat2[8]; - + dest[0] = b00 * a00 + b01 * a10 + b02 * a20; dest[1] = b00 * a01 + b01 * a11 + b02 * a21; dest[2] = b00 * a02 + b01 * a12 + b02 * a22; - + dest[3] = b10 * a00 + b11 * a10 + b12 * a20; dest[4] = b10 * a01 + b11 * a11 + b12 * a21; dest[5] = b10 * a02 + b11 * a12 + b12 * a22; - + dest[6] = b20 * a00 + b21 * a10 + b22 * a20; dest[7] = b20 * a01 + b21 * a11 + b22 * a21; dest[8] = b20 * a02 + b21 * a12 + b22 * a22; - + return dest; } @@ -514,11 +515,11 @@ PIXI.mat3.clone = function(mat) matrix[6] = mat[6]; matrix[7] = mat[7]; matrix[8] = mat[8]; - + return matrix; } -PIXI.mat3.transpose = function (mat, dest) +PIXI.mat3.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (!dest || mat === dest) { @@ -546,30 +547,30 @@ PIXI.mat3.transpose = function (mat, dest) return dest; } -PIXI.mat3.toMat4 = function (mat, dest) +PIXI.mat3.toMat4 = function (mat, dest) { if (!dest) { dest = PIXI.mat4.create(); } - + dest[15] = 1; dest[14] = 0; dest[13] = 0; dest[12] = 0; - + dest[11] = 0; dest[10] = mat[8]; dest[9] = mat[7]; dest[8] = mat[6]; - + dest[7] = 0; dest[6] = mat[5]; dest[5] = mat[4]; dest[4] = mat[3]; - + dest[3] = 0; dest[2] = mat[2]; dest[1] = mat[1]; dest[0] = mat[0]; - + return dest; } @@ -597,19 +598,19 @@ PIXI.mat4.create = function() matrix[13] = 0; matrix[14] = 0; matrix[15] = 1; - + return matrix; } -PIXI.mat4.transpose = function (mat, dest) +PIXI.mat4.transpose = function (mat, dest) { // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) + if (!dest || mat === dest) { var a01 = mat[1], a02 = mat[2], a03 = mat[3], a12 = mat[6], a13 = mat[7], a23 = mat[11]; - + mat[1] = mat[4]; mat[2] = mat[8]; mat[3] = mat[12]; @@ -624,7 +625,7 @@ PIXI.mat4.transpose = function (mat, dest) mat[14] = a23; return mat; } - + dest[0] = mat[0]; dest[1] = mat[4]; dest[2] = mat[8]; @@ -644,18 +645,18 @@ PIXI.mat4.transpose = function (mat, dest) return dest; } -PIXI.mat4.multiply = function (mat, mat2, dest) +PIXI.mat4.multiply = function (mat, mat2, dest) { if (!dest) { dest = mat; } - + // Cache the matrix values (makes for huge speed increases!) var a00 = mat[ 0], a01 = mat[ 1], a02 = mat[ 2], a03 = mat[3]; var a10 = mat[ 4], a11 = mat[ 5], a12 = mat[ 6], a13 = mat[7]; var a20 = mat[ 8], a21 = mat[ 9], a22 = mat[10], a23 = mat[11]; var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - + // Cache only the current line of the second matrix - var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; + var b0 = mat2[0], b1 = mat2[1], b2 = mat2[2], b3 = mat2[3]; dest[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; dest[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; dest[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -705,7 +706,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -779,15 +779,6 @@ PIXI.DisplayObject = function() */ this.renderable = false; - /** - * [read-only] The visibility of the object based on world (parent) factors. - * - * @property worldVisible - * @type Boolean - * @readOnly - */ - this.worldVisible = false; - /** * [read-only] The display object container that contains this display object. * @@ -806,15 +797,6 @@ PIXI.DisplayObject = function() */ this.stage = null; - /** - * [read-only] The index of this object in the parent's `children` array - * - * @property childIndex - * @type Number - * @readOnly - */ - this.childIndex = 0; - /** * [read-only] The multiplied alpha of the displayobject * @@ -953,17 +935,6 @@ PIXI.DisplayObject = function() // constructor PIXI.DisplayObject.prototype.constructor = PIXI.DisplayObject; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObject.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - } -});*/ - /** * [Deprecated] Indicates if the sprite will have touch and mouse interactivity. It is false by default * Instead of using this function you can now simply set the interactive property to true or false @@ -1011,16 +982,57 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { }, set: function(value) { - this._mask = value; - + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -1031,19 +1043,21 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); + data.start = start; + data.end = end; - start.mask = mask; - end.mask = mask; + start.data = data; + end.data = data; start.first = start.last = this; end.first = end.last = this; @@ -1051,9 +1065,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) start.open = true; /* - * * insert start - * */ var childFirst = start @@ -1084,9 +1096,7 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) // now insert the end filter block.. /* - * * insert end filter - * */ var childFirst = end var childLast = end @@ -1125,8 +1135,6 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) this.__renderGroup.addFilterBlocks(start, end); } - mask.renderable = false; - } /* @@ -1135,13 +1143,14 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; + var startBlock = data.start; + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; @@ -1151,9 +1160,8 @@ PIXI.DisplayObject.prototype.removeFilter = function() this.first = startBlock._iNext; - // remove the end filter - var lastBlock = this.last; + var lastBlock = data.end; var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; @@ -1162,8 +1170,6 @@ PIXI.DisplayObject.prototype.removeFilter = function() previousObject._iNext = nextObject; // this is always true too! -// if(this.last == lastBlock) - //{ var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; @@ -1174,15 +1180,11 @@ PIXI.DisplayObject.prototype.removeFilter = function() if(!updateLast)break; } - var mask = startBlock.mask - mask.renderable = true; - // if webGL... if(this.__renderGroup) { this.__renderGroup.removeFilterBlocks(startBlock, lastBlock); } - //} } /* @@ -1194,7 +1196,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() PIXI.DisplayObject.prototype.updateTransform = function() { // TODO OPTIMIZE THIS!! with dirty - if(this.rotation != this.rotationCache) + if(this.rotation !== this.rotationCache) { this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); @@ -1236,9 +1238,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; + + this.vcount = PIXI.visibleCount; } +PIXI.visibleCount = 0; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1270,18 +1275,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -1299,11 +1292,10 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } child.parent = this; - child.childIndex = this.children.length; this.children.push(child); - // updae the stage refference.. + // update the stage refference.. if(this.stage) { @@ -1326,7 +1318,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) var previousObject; // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -1338,7 +1330,6 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) nextObject = previousObject._iNext; // always true in this case - //this.last = child.last; // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; @@ -1402,7 +1393,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; @@ -1410,7 +1401,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) if(index == this.children.length) { previousObject = this.last; - var updateLast = this;//.parent; + var updateLast = this; var prevLast = this.last; while(updateLast) { @@ -1539,7 +1530,7 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { // unlink // // modify the list.. - var childFirst = child.first + var childFirst = child.first; var childLast = child.last; var nextObject = childLast._iNext; @@ -1609,7 +1600,6 @@ PIXI.DisplayObjectContainer.prototype.updateTransform = function() this.children[i].updateTransform(); } } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1739,9 +1729,18 @@ PIXI.Sprite.prototype.setTexture = function(texture) if(this.texture.baseTexture != texture.baseTexture) { this.textureChange = true; + this.texture = texture; + + if(this.__renderGroup) + { + this.__renderGroup.updateTexture(this); + } + } + else + { + this.texture = texture; } - this.texture = texture; this.updateFrame = true; } @@ -1798,7 +1797,6 @@ PIXI.Sprite.fromImage = function(imageId) return new PIXI.Sprite(texture); } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1814,7 +1812,7 @@ PIXI.Sprite.fromImage = function(imageId) PIXI.MovieClip = function(textures) { PIXI.Sprite.call(this, textures[0]); - + /** * The array of textures that make up the animation * @@ -1822,7 +1820,7 @@ PIXI.MovieClip = function(textures) * @type Array */ this.textures = textures; - + /** * The speed that the MovieClip will play at. Higher is faster, lower is slower * @@ -1848,7 +1846,7 @@ PIXI.MovieClip = function(textures) * @type Function */ this.onComplete = null; - + /** * [read-only] The index MovieClips current frame (this may not have to be a whole number) * @@ -1857,8 +1855,8 @@ PIXI.MovieClip = function(textures) * @default 0 * @readOnly */ - this.currentFrame = 0; - + this.currentFrame = 0; + /** * [read-only] Indicates if the MovieClip is currently playing * @@ -1873,6 +1871,23 @@ PIXI.MovieClip = function(textures) PIXI.MovieClip.prototype = Object.create( PIXI.Sprite.prototype ); PIXI.MovieClip.prototype.constructor = PIXI.MovieClip; +/** +* [read-only] totalFrames is the total number of frames in the MovieClip. This is the same as number of textures +* assigned to the MovieClip. +* +* @property totalFrames +* @type Number +* @default 0 +* @readOnly +*/ +Object.defineProperty( PIXI.MovieClip.prototype, 'totalFrames', { + get: function() { + + return this.textures.length; + } +}); + + /** * Stops the MovieClip * @@ -1928,11 +1943,13 @@ PIXI.MovieClip.prototype.gotoAndPlay = function(frameNumber) PIXI.MovieClip.prototype.updateTransform = function() { PIXI.Sprite.prototype.updateTransform.call(this); - + if(!this.playing)return; - + this.currentFrame += this.animationSpeed; + var round = (this.currentFrame + 0.5) | 0; + if(this.loop || round < this.textures.length) { this.setTexture(this.textures[round % this.textures.length]); @@ -1952,14 +1969,49 @@ PIXI.MovieClip.prototype.updateTransform = function() -PIXI.FilterBlock = function(mask) +PIXI.FilterBlock = function() { - this.graphics = mask this.visible = true; this.renderable = true; } +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + +PIXI.ColorMatrixFilter = function() +{ + // set the uniforms + this.uniforms = { + matrix: {type: 'mat4', value: [1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1]}, + }; + + this.fragmentSrc = [ + "precision mediump float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform float invert;", + "uniform mat4 matrix;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;", + "gl_FragColor = gl_FragColor * vColor;", + "}" + ]; + +} +Object.defineProperty(PIXI.ColorMatrixFilter.prototype, 'matrix', { + get: function() { + return this.uniforms.matrix.value; + }, + set: function(value) { + this.uniforms.matrix.value = value; + } +}); /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -1988,7 +2040,7 @@ PIXI.Text = function(text, style) this.setText(text); this.setStyle(style); - + this.updateText(); this.dirty = false; }; @@ -2030,7 +2082,7 @@ PIXI.Text.prototype.setStyle = function(style) * @methos setText * @param {String} text The copy that you would like the text to display */ -PIXI.Sprite.prototype.setText = function(text) +PIXI.Text.prototype.setText = function(text) { this.text = text.toString() || " "; this.dirty = true; @@ -2045,9 +2097,9 @@ PIXI.Sprite.prototype.setText = function(text) PIXI.Text.prototype.updateText = function() { this.context.font = this.style.font; - + var outputText = this.text; - + // word wrap // preserve original text if(this.style.wordWrap)outputText = this.wordWrap(this.text); @@ -2065,7 +2117,7 @@ PIXI.Text.prototype.updateText = function() maxLineWidth = Math.max(maxLineWidth, lineWidth); } this.canvas.width = maxLineWidth + this.style.strokeThickness; - + //calculate text height var lineHeight = this.determineFontHeight("font: " + this.style.font + ";") + this.style.strokeThickness; this.canvas.height = lineHeight * lines.length; @@ -2073,7 +2125,7 @@ PIXI.Text.prototype.updateText = function() //set canvas text styles this.context.fillStyle = this.style.fill; this.context.font = this.style.font; - + this.context.strokeStyle = this.style.stroke; this.context.lineWidth = this.style.strokeThickness; @@ -2083,7 +2135,7 @@ PIXI.Text.prototype.updateText = function() for (i = 0; i < lines.length; i++) { var linePosition = new PIXI.Point(this.style.strokeThickness / 2, this.style.strokeThickness / 2 + i * lineHeight); - + if(this.style.align == "right") { linePosition.x += maxLineWidth - lineWidths[i]; @@ -2103,7 +2155,7 @@ PIXI.Text.prototype.updateText = function() this.context.fillText(lines[i], linePosition.x, linePosition.y); } } - + this.updateTexture(); }; @@ -2119,10 +2171,10 @@ PIXI.Text.prototype.updateTexture = function() this.texture.baseTexture.height = this.canvas.height; this.texture.frame.width = this.canvas.width; this.texture.frame.height = this.canvas.height; - + this._width = this.canvas.width; this._height = this.canvas.height; - + PIXI.texturesToUpdate.push(this.texture.baseTexture); }; @@ -2136,10 +2188,10 @@ PIXI.Text.prototype.updateTransform = function() { if(this.dirty) { - this.updateText(); + this.updateText(); this.dirty = false; } - + PIXI.Sprite.prototype.updateTransform.call(this); }; @@ -2151,12 +2203,12 @@ PIXI.Text.prototype.updateTransform = function() * @param fontStyle {Object} * @private */ -PIXI.Text.prototype.determineFontHeight = function(fontStyle) +PIXI.Text.prototype.determineFontHeight = function(fontStyle) { // build a little reference dictionary so if the font style has been used return a // cached version... var result = PIXI.Text.heightCache[fontStyle]; - + if(!result) { var body = document.getElementsByTagName("body")[0]; @@ -2165,13 +2217,13 @@ PIXI.Text.prototype.determineFontHeight = function(fontStyle) dummy.appendChild(dummyText); dummy.setAttribute("style", fontStyle + ';position:absolute;top:0;left:0'); body.appendChild(dummy); - + result = dummy.offsetHeight; PIXI.Text.heightCache[fontStyle] = result; - + body.removeChild(dummy); } - + return result; }; @@ -2191,7 +2243,7 @@ PIXI.Text.prototype.wordWrap = function(text) if(p == start) { return 1; } - + if(ctx.measureText(text.substring(0,p)).width <= wrapWidth) { if(ctx.measureText(text.substring(0,p+1)).width > wrapWidth) @@ -2208,7 +2260,7 @@ PIXI.Text.prototype.wordWrap = function(text) return arguments.callee(ctx, text, start, p, wrapWidth); } }; - + var lineWrap = function(ctx, text, wrapWidth) { if(ctx.measureText(text).width <= wrapWidth || text.length < 1) @@ -2218,14 +2270,14 @@ PIXI.Text.prototype.wordWrap = function(text) var pos = searchWrapPos(ctx, text, 0, text.length, wrapWidth); return text.substring(0, pos) + "\n" + arguments.callee(ctx, text.substring(pos), wrapWidth); }; - + var result = ""; var lines = text.split("\n"); for (var i = 0; i < lines.length; i++) { result += lineWrap(this.context, lines[i], this.style.wordWrapWidth) + "\n"; } - + return result; }; @@ -2241,7 +2293,7 @@ PIXI.Text.prototype.destroy = function(destroyTexture) { this.texture.destroy(); } - + }; PIXI.Text.heightCache = {}; @@ -2252,7 +2304,7 @@ PIXI.Text.heightCache = {}; /** * A Text Object will create a line(s) of text using bitmap font. To split a line you can use "\n", "\r" or "\r\n" - * You can generate the fnt files using + * You can generate the fnt files using * http://www.angelcode.com/products/bmfont/ for windows or * http://www.bmglyph.com/ for mac. * @@ -2342,7 +2394,7 @@ PIXI.BitmapText.prototype.updateText = function() prevCharCode = null; continue; } - + var charData = data.chars[charCode]; if(!charData) continue; @@ -2405,7 +2457,7 @@ PIXI.BitmapText.prototype.updateTransform = function() this.dirty = false; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); }; @@ -2414,10 +2466,8 @@ PIXI.BitmapText.fonts = {}; /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ - - - -/** + + /** * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive * This manager also supports multitouch. * @@ -2451,6 +2501,8 @@ PIXI.InteractionManager = function(stage) */ this.touchs = {}; + + // helpers this.tempPoint = new PIXI.Point(); //this.tempMatrix = mat3.create(); @@ -2461,7 +2513,19 @@ PIXI.InteractionManager = function(stage) this.pool = []; this.interactiveItems = []; + this.interactionDOMElement = null; + //this will make it so that you dont have to call bind all the time + this.onMouseMove = this.onMouseMove.bind( this ); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + this.onTouchMove = this.onTouchMove.bind(this); + + this.last = 0; } @@ -2486,7 +2550,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj { var child = children[i]; - if(child.visible) { +// if(child.visible) { // push all interactive bits if(child.interactive) { @@ -2508,7 +2572,7 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj this.collectInteractiveSprite(child, iParent); } } - } +// } } } @@ -2521,27 +2585,68 @@ PIXI.InteractionManager.prototype.collectInteractiveSprite = function(displayObj */ PIXI.InteractionManager.prototype.setTarget = function(target) { + this.target = target; + + //check if the dom element has been set. If it has don't do anything + if( this.interactionDOMElement === null ) { + + this.setTargetDomElement( target.view ); + } + + document.body.addEventListener('mouseup', this.onMouseUp, true); +} + + +/** + * Sets the dom element which will receive mouse/touch events. This is useful for when you have other DOM + * elements ontop of the renderers Canvas element. With this you'll be able to delegate another dom element + * to receive those events + * + * @method setTargetDomElement + * @param domElement {DOMElement} the dom element which will receive mouse and touch events + * @private + */ +PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) +{ + //remove previouse listeners + if( this.interactionDOMElement !== null ) + { + this.interactionDOMElement.style['-ms-content-zooming'] = ''; + this.interactionDOMElement.style['-ms-touch-action'] = ''; + + this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); + this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); + } + + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. - target.view.style["-ms-content-zooming"] = "none"; - target.view.style["-ms-touch-action"] = "none" + domElement.style['-ms-content-zooming'] = 'none'; + domElement.style['-ms-touch-action'] = 'none'; // DO some window specific touch! } - - this.target = target; - target.view.addEventListener('mousemove', this.onMouseMove.bind(this), true); - target.view.addEventListener('mousedown', this.onMouseDown.bind(this), true); - document.body.addEventListener('mouseup', this.onMouseUp.bind(this), true); - target.view.addEventListener('mouseout', this.onMouseUp.bind(this), true); - - // aint no multi touch just yet! - target.view.addEventListener("touchstart", this.onTouchStart.bind(this), true); - target.view.addEventListener("touchend", this.onTouchEnd.bind(this), true); - target.view.addEventListener("touchmove", this.onTouchMove.bind(this), true); + + this.interactionDOMElement = domElement; + + domElement.addEventListener('mousemove', this.onMouseMove, true); + domElement.addEventListener('mousedown', this.onMouseDown, true); + domElement.addEventListener('mouseout', this.onMouseOut, true); + + // aint no multi touch just yet! + domElement.addEventListener('touchstart', this.onTouchStart, true); + domElement.addEventListener('touchend', this.onTouchEnd, true); + domElement.addEventListener('touchmove', this.onTouchMove, true); } + /** * updates the state of interactive objects * @@ -2583,12 +2688,14 @@ PIXI.InteractionManager.prototype.update = function() // loop through interactive objects! var length = this.interactiveItems.length; - this.target.view.style.cursor = "default"; + this.interactionDOMElement.style.cursor = "default"; for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - if(!item.visible)continue; + + + //if(!item.visible)continue; // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? @@ -2604,7 +2711,7 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode)this.target.view.style.cursor = "pointer"; + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; if(!item.__isOver) { @@ -2639,7 +2746,7 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); @@ -2669,7 +2776,6 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) */ PIXI.InteractionManager.prototype.onMouseDown = function(event) { - event.preventDefault(); this.mouse.originalEvent = event || window.event; //IE uses window.event // loop through inteaction tree... @@ -2706,6 +2812,26 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) } } + +PIXI.InteractionManager.prototype.onMouseOut = function(event) +{ + var length = this.interactiveItems.length; + + this.interactionDOMElement.style.cursor = "default"; + + for (var i = 0; i < length; i++) + { + var item = this.interactiveItems[i]; + + if(item.__isOver) + { + this.mouse.target = item; + if(item.mouseout)item.mouseout(this.mouse); + item.__isOver = false; + } + } +} + /** * Is called when the mouse button is released on the renderer element * @@ -2770,7 +2896,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - if(!item.visible)return false; + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), worldTransform = item.worldTransform, @@ -2840,14 +2966,14 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) */ PIXI.InteractionManager.prototype.onTouchMove = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; + touchData.originalEvent = event || window.event; // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); @@ -2871,10 +2997,7 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) */ PIXI.InteractionManager.prototype.onTouchStart = function(event) { - event.preventDefault(); - this.mouse.originalEvent = event || window.event; //IE uses window.event - - var rect = this.target.view.getBoundingClientRect(); + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2884,6 +3007,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); + touchData.originalEvent = event || window.event; + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); @@ -2921,8 +3046,8 @@ PIXI.InteractionManager.prototype.onTouchStart = function(event) */ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { - this.mouse.originalEvent = event || window.event; //IE uses window.event - var rect = this.target.view.getBoundingClientRect(); + //this.mouse.originalEvent = event || window.event; //IE uses window.event + var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; for (var i=0; i < changedTouches.length; i++) @@ -2943,7 +3068,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(itemTouchData == touchData) { // so this one WAS down... - + touchData.originalEvent = event || window.event; // hitTest?? if(item.touchend || item.tap) @@ -3055,9 +3180,8 @@ PIXI.InteractionData.prototype.constructor = PIXI.InteractionData; * @constructor * @param backgroundColor {Number} the background color of the stage, easiest way to pass this in is in hex format * like: 0xFFFFFF for white - * @param interactive {Boolean} enable / disable interaction (default is false) */ -PIXI.Stage = function(backgroundColor, interactive) +PIXI.Stage = function(backgroundColor) { PIXI.DisplayObjectContainer.call( this ); @@ -3077,7 +3201,7 @@ PIXI.Stage = function(backgroundColor, interactive) * @property interactive * @type Boolean */ - this.interactive = interactive; + this.interactive = true; /** * The interaction manage for this stage, manages all interactive activity on the stage @@ -3113,6 +3237,18 @@ PIXI.Stage = function(backgroundColor, interactive) PIXI.Stage.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Stage.prototype.constructor = PIXI.Stage; +/** + * Sets another DOM element which can receive mouse/touch interactions instead of the default Canvas element. + * This is useful for when you have other DOM elements ontop of the Canvas element. + * + * @method setInteractionDelegate + * @param domElement {DOMElement} This new domElement which will receive mouse/touch events + */ +PIXI.Stage.prototype.setInteractionDelegate = function(domElement) +{ + this.interactionManager.setTargetDomElement( domElement ); +} + /* * Updates the object transform for rendering * @@ -3122,6 +3258,7 @@ PIXI.Stage.prototype.constructor = PIXI.Stage; PIXI.Stage.prototype.updateTransform = function() { this.worldAlpha = 1; + this.vcount = PIXI.visibleCount; for(var i=0,j=this.children.length; i 100) { console.log("BREAK") break } - } + } } @@ -3361,14 +3466,14 @@ PIXI.runList = function(item) PIXI.EventTarget = function () { var listeners = {}; - + this.addEventListener = this.on = function ( type, listener ) { - - + + if ( listeners[ type ] === undefined ) { listeners[ type ] = []; - + } if ( listeners[ type ].indexOf( listener ) === - 1 ) { @@ -3379,11 +3484,17 @@ PIXI.EventTarget = function () { }; this.dispatchEvent = this.emit = function ( event ) { - - for ( var listener in listeners[ event.type ] ) { - listeners[ event.type ][ listener ]( event ); - + if ( !listeners[ event.type ] || !listeners[ event.type ].length ) { + + return; + + } + + for(var i = 0, l = listeners[ event.type ].length; i < l; i++) { + + listeners[ event.type ][ i ]( event ); + } }; @@ -3417,8 +3528,11 @@ PIXI.EventTarget = function () { * @param height {Number} the height of the renderers view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in webGL chrome at the moment) + * + * antialias */ -PIXI.autoDetectRenderer = function(width, height, view, transparent) +PIXI.autoDetectRenderer = function(width, height, view, transparent, antialias) { if(!width)width = 800; if(!height)height = 600; @@ -3429,7 +3543,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) //console.log(webgl); if( webgl ) { - return new PIXI.WebGLRenderer(width, height, view, transparent); + return new PIXI.WebGLRenderer(width, height, view, transparent, antialias); } return new PIXI.CanvasRenderer(width, height, view, transparent); @@ -3441,7 +3555,7 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) PolyK library url: http://polyk.ivank.net Released under MIT licence. - + Copyright (c) 2012 Ivan Kuckir Permission is hereby granted, free of charge, to any person @@ -3465,8 +3579,8 @@ PIXI.autoDetectRenderer = function(width, height, view, transparent) FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - This is an amazing lib! - + This is an amazing lib! + slightly modified by mat groves (matgroves.com); */ @@ -3482,13 +3596,13 @@ PIXI.PolyK = {}; PIXI.PolyK.Triangulate = function(p) { var sign = true; - + var n = p.length>>1; if(n<3) return []; var tgs = []; var avl = []; for(var i=0; i 3) @@ -3496,11 +3610,11 @@ PIXI.PolyK.Triangulate = function(p) var i0 = avl[(i+0)%al]; var i1 = avl[(i+1)%al]; var i2 = avl[(i+2)%al]; - + var ax = p[2*i0], ay = p[2*i0+1]; var bx = p[2*i1], by = p[2*i1+1]; var cx = p[2*i2], cy = p[2*i2+1]; - + var earFound = false; if(PIXI.PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { @@ -3519,7 +3633,7 @@ PIXI.PolyK.Triangulate = function(p) al--; i = 0; } - else if(i++ > 3*al) + else if(i++ > 3*al) { // need to flip flip reverse it! // reset! @@ -3528,17 +3642,17 @@ PIXI.PolyK.Triangulate = function(p) var tgs = []; avl = []; for(var i=0; i= 0) == sign; } - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -3612,13 +3725,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -3658,7 +3769,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -3685,6 +3795,8 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; +PIXI.shaderStack = []; + PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; @@ -3699,27 +3811,26 @@ PIXI.initPrimitiveShader = function() shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } PIXI.initDefaultStripShader = function() @@ -3736,9 +3847,7 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); PIXI.stripShaderProgram = shaderProgram; @@ -3789,35 +3898,135 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) return shaderProgram; } +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); -PIXI.activateDefaultShader = function() + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; +} + + +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; gl.useProgram(shaderProgram); - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - gl.useProgram(PIXI.primitiveProgram); - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); } +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -3887,7 +4096,7 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. @@ -3899,8 +4108,10 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -4243,7 +4454,7 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) verts.push(px , py); verts.push(r, g, b, alpha); - verts.push(p2x - (px-p2x), p2y - (py - p2y));//, 4); + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } @@ -4356,9 +4567,10 @@ PIXI.gl; * @param height=0 {Number} the height of the canvas view * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false + * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) * */ -PIXI.WebGLRenderer = function(width, height, view, transparent) +PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { // do a catch.. only 1 webGL renderer.. @@ -4382,7 +4594,7 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) { PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, - antialias:true, // SPEED UP?? + antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); @@ -4392,11 +4604,12 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -4413,7 +4626,10 @@ PIXI.WebGLRenderer = function(width, height, view, transparent) this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -4469,8 +4685,6 @@ PIXI.WebGLRenderer.prototype.render = function(stage) { // TODO make this work // dont think this is needed any more? - //if(this.__stage)this.checkVisibility(this.__stage, false) - this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } @@ -4487,10 +4701,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) // update any textures PIXI.WebGLRenderer.updateTextures(); - // recursivly loop through all items! - //this.checkVisibility(stage, true); - // update the scene graph + PIXI.visibleCount++; stage.updateTransform(); var gl = this.gl; @@ -4499,16 +4711,12 @@ PIXI.WebGLRenderer.prototype.render = function(stage) gl.colorMask(true, true, true, this.transparent); gl.viewport(0, 0, this.width, this.height); - // set the correct matrix.. - // gl.uniformMatrix4fv(this.shaderProgram.mvMatrixUniform, false, this.projectionMatrix); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - //PIXI.projectionMatrix = this.projectionMatrix; this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); @@ -4546,8 +4754,9 @@ PIXI.WebGLRenderer.prototype.render = function(stage) */ PIXI.WebGLRenderer.updateTextures = function() { - for (var i=0; i < PIXI.texturesToUpdate.length; i++) this.updateTexture(PIXI.texturesToUpdate[i]); - for (var i=0; i < PIXI.texturesToDestroy.length; i++) this.destroyTexture(PIXI.texturesToDestroy[i]); + //TODO break this out into a texture manager... + for (var i=0; i < PIXI.texturesToUpdate.length; i++) PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]); + for (var i=0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; } @@ -4562,6 +4771,7 @@ PIXI.WebGLRenderer.updateTextures = function() */ PIXI.WebGLRenderer.updateTexture = function(texture) { + //TODO break this out into a texture manager... var gl = PIXI.gl; if(!texture._glTexture) @@ -4602,9 +4812,10 @@ PIXI.WebGLRenderer.updateTexture = function(texture) * @param texture {Texture} The texture to update * @private */ -PIXI.WebGLRenderer.prototype.destroyTexture = function(texture) +PIXI.WebGLRenderer.destroyTexture = function(texture) { - var gl = this.gl; + //TODO break this out into a texture manager... + var gl = PIXI.gl; if(texture._glTexture) { @@ -4768,7 +4979,6 @@ PIXI.WebGLBatch.prototype.clean = function() this.uvs = []; this.indices = []; this.colors = []; - //this.sprites = []; this.dynamicSize = 1; this.texture = null; this.last = null; @@ -4805,7 +5015,6 @@ PIXI.WebGLBatch.prototype.init = function(sprite) this.dirty = true; this.blendMode = sprite.blendMode; this.texture = sprite.texture.baseTexture; -// this.sprites.push(sprite); this.head = sprite; this.tail = sprite; this.size = 1; @@ -4838,7 +5047,6 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) else { this.head = sprite; - //this.head.__prev = null } } @@ -4926,7 +5134,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) { this.dirty = true; - var batch = new PIXI.WebGLBatch(this.gl);//PIXI._getBatch(this.gl); + var batch = new PIXI.WebGLBatch(this.gl); batch.init(sprite); batch.texture = this.texture; batch.tail = this.tail; @@ -4936,8 +5144,6 @@ PIXI.WebGLBatch.prototype.split = function(sprite) sprite.__prev = null; // return a splite batch! - //sprite.__prev.__next = null; - //sprite.__prev = null; // TODO this size is wrong! // need to recalculate :/ problem with a linked list! @@ -5007,13 +5213,13 @@ PIXI.WebGLBatch.prototype.growBatch = function() gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER,this.verticies , gl.DYNAMIC_DRAW); - this.uvs = new Float32Array( this.dynamicSize * 8 ) + this.uvs = new Float32Array( this.dynamicSize * 8 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs , gl.DYNAMIC_DRAW); this.dirtyUVS = true; - this.colors = new Float32Array( this.dynamicSize * 4 ) + this.colors = new Float32Array( this.dynamicSize * 4 ); gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors , gl.DYNAMIC_DRAW); @@ -5112,7 +5318,7 @@ PIXI.WebGLBatch.prototype.update = function() while(displayObject) { - if(displayObject.worldVisible) + if(displayObject.vcount === PIXI.visibleCount) { width = displayObject.texture.frame.width; height = displayObject.texture.frame.height; @@ -5214,7 +5420,7 @@ PIXI.WebGLBatch.prototype.update = function() PIXI.WebGLBatch.prototype.render = function(start, end) { start = start || 0; - //end = end || this.size; + if(end == undefined)end = this.size; if(this.dirty) @@ -5230,8 +5436,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -5239,6 +5446,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -5262,13 +5471,11 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - //var startIndex = 0//1; var len = end - start; - // console.log(this.size) + // DRAW THAT this! gl.drawElements(gl.TRIANGLES, len * 6, gl.UNSIGNED_SHORT, start * 2 * 6 ); } @@ -5336,77 +5543,45 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - // TODO remove this by replacing visible with getter setters.. - this.checkVisibility(this.root, this.root.visible); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) { + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); + continue; } - else if(renderable instanceof PIXI.TilingSprite) + + // non sprite batch.. + var worldVisible = renderable.vcount === PIXI.visibleCount; + + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection);//, projectionMatrix); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, false); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } } -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - -} - /** * Renders a specific displayObject * @@ -5420,11 +5595,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project PIXI.WebGLRenderer.updateTextures(); var gl = this.gl; - this.checkVisibility(displayObject, displayObject.visible); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); -// gl.uniformMatrix4fv(PIXI.shaderProgram.mvMatrixUniform, false, projectionMatrix); - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - // to do! // render part of the scene... @@ -5483,7 +5655,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } if(lastRenderable instanceof PIXI.Sprite) @@ -5577,45 +5749,80 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + + var worldVisible = renderable.vcount === PIXI.visibleCount + if(renderable instanceof PIXI.TilingSprite) { - if(renderable.visible)this.renderTilingSprite(renderable, projection); + if(worldVisible)this.renderTilingSprite(renderable, projection); } else if(renderable instanceof PIXI.Strip) { - if(renderable.visible)this.renderStrip(renderable, projection); + if(worldVisible)this.renderStrip(renderable, projection); } else if(renderable instanceof PIXI.CustomRenderable) { - if(renderable.visible) renderable.renderWebGL(this, projection); + if(worldVisible) renderable.renderWebGL(this, projection); } else if(renderable instanceof PIXI.Graphics) { - if(renderable.visible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); + if(worldVisible && renderable.renderable) PIXI.WebGLGraphics.renderGraphics(renderable, projection); } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -5623,42 +5830,6 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } } -/** - * Checks the visibility of a displayObject - * - * @method checkVisibility - * @param displayObject {DisplayObject} - * @param globalVisible {Boolean} - * @private - */ -PIXI.WebGLRenderGroup.prototype.checkVisibility = function(displayObject, globalVisible) -{ - // give the dp a reference to its renderGroup... - var children = displayObject.children; - //displayObject.worldVisible = globalVisible; - for (var i=0; i < children.length; i++) - { - var child = children[i]; - - // TODO optimize... should'nt need to loop through everything all the time - child.worldVisible = child.visible && globalVisible; - - // everything should have a batch! - // time to see whats new! - if(child.textureChange) - { - child.textureChange = false; - if(child.worldVisible)this.updateTexture(child); - // update texture!! - } - - if(child.children.length > 0) - { - this.checkVisibility(child, child.worldVisible); - } - }; -} - /** * Updates a webgl texture * @@ -5719,7 +5890,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; @@ -5733,7 +5904,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -6105,6 +6276,7 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) } } + /** * Initializes a tiling sprite * @@ -6175,23 +6347,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - + var shaderProgram = PIXI.stripShaderProgram; - gl.useProgram(PIXI.stripShaderProgram); + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); PIXI.mat3.transpose(m); // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -6249,11 +6417,10 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } - //console.log(gl.TRIANGLE_STRIP); gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - gl.useProgram(PIXI.shaderProgram); + gl.useProgram(PIXI.currentProgram); } /** @@ -6328,6 +6495,7 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -6401,7 +6569,6 @@ PIXI.CanvasRenderer.prototype.constructor = PIXI.CanvasRenderer; */ PIXI.CanvasRenderer.prototype.render = function(stage) { - // update children if need be //stage.__childrenAdded = []; //stage.__childrenRemoved = []; @@ -6410,6 +6577,7 @@ PIXI.CanvasRenderer.prototype.render = function(stage) PIXI.texturesToUpdate = []; PIXI.texturesToDestroy = []; + PIXI.visibleCount++; stage.updateTransform(); // update the background color @@ -6496,7 +6664,7 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) var frame = displayObject.texture.frame; - if(frame) + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; @@ -6534,31 +6702,34 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - // context.fillStyle = 0xFF0000; - // context.fillRect(0, 0, 200, 200); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; - //context.globalCompositeOperation = 'lighter'; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - //context.globalCompositeOperation = 'source-over'; - context.restore(); + // only masks supported right now! } } // count++ @@ -6651,7 +6822,7 @@ PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) PIXI.CanvasRenderer.prototype.renderStrip = function(strip) { var context = this.context; - //context.globalCompositeOperation = 'lighter'; + // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; @@ -6678,8 +6849,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x2, y2); context.closePath(); - // context.fillStyle = "white"//rgb(1, 1, 1,1)); - // context.fill(); context.clip(); @@ -6703,7 +6872,6 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.restore(); }; -// context.globalCompositeOperation = 'source-over'; } /** @@ -6718,7 +6886,7 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) */ PIXI.CanvasGraphics = function() { - + } @@ -6734,35 +6902,33 @@ PIXI.CanvasGraphics = function() PIXI.CanvasGraphics.renderGraphics = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - - for (var i=0; i < graphics.graphicsData.length; i++) + + for (var i=0; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + context.strokeStyle = color = '#' + ('00000' + ( data.lineColor | 0).toString(16)).substr(-6); context.lineWidth = data.lineWidth; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); - + context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6777,21 +6943,20 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.RECT) { - - // TODO - need to be Undefined! - if(data.fillColor) + + if(data.fillColor || data.fillColor === 0) { context.globalAlpha = data.fillAlpha * worldAlpha; context.fillStyle = color = '#' + ('00000' + ( data.fillColor | 0).toString(16)).substr(-6); context.fillRect(points[0], points[1], points[2], points[3]); - + } if(data.lineWidth) { context.globalAlpha = data.lineAlpha * worldAlpha; context.strokeRect(points[0], points[1], points[2], points[3]); } - + } else if(data.type == PIXI.Graphics.CIRC) { @@ -6799,7 +6964,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.beginPath(); context.arc(points[0], points[1], points[2],0,2*Math.PI); context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6814,19 +6979,19 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - + var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6834,15 +6999,15 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - + context.closePath(); - + if(data.fill) { context.globalAlpha = data.fillAlpha * worldAlpha; @@ -6855,7 +7020,7 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) context.stroke(); } } - + }; } @@ -6871,37 +7036,35 @@ PIXI.CanvasGraphics.renderGraphics = function(graphics, context) PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) { var worldAlpha = graphics.worldAlpha; - + var len = graphics.graphicsData.length; if(len > 1) { len = 1; console.log("Pixi.js warning: masks in canvas can only mask using the first path in the graphics object") } - - for (var i=0; i < 1; i++) + + for (var i=0; i < 1; i++) { var data = graphics.graphicsData[i]; var points = data.points; - + if(data.type == PIXI.Graphics.POLY) { - //if(data.lineWidth <= 0)continue; - context.beginPath(); context.moveTo(points[0], points[1]); - + for (var j=1; j < points.length/2; j++) { context.lineTo(points[j * 2], points[j * 2 + 1]); - } - + } + // if the first and last point are the same close the path - much neater :) if(points[0] == points[points.length-2] && points[1] == points[points.length-1]) { context.closePath(); } - + } else if(data.type == PIXI.Graphics.RECT) { @@ -6918,18 +7081,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) } else if(data.type == PIXI.Graphics.ELIP) { - + // elipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas var elipseData = data.points; - + var w = elipseData[2] * 2; var h = elipseData[3] * 2; - + var x = elipseData[0] - w/2; var y = elipseData[1] - h/2; - + context.beginPath(); - + var kappa = .5522848, ox = (w / 2) * kappa, // control point offset horizontal oy = (h / 2) * kappa, // control point offset vertical @@ -6937,7 +7100,7 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) ye = y + h, // y-end xm = x + w / 2, // x-middle ym = y + h / 2; // y-middle - + context.moveTo(x, ym); context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); @@ -6945,8 +7108,8 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); context.closePath(); } - - + + }; } @@ -6956,18 +7119,18 @@ PIXI.CanvasGraphics.renderGraphicsMask = function(graphics, context) /** - * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. + * The Graphics class contains a set of methods that you can use to create primitive shapes and lines. * It is important to know that with the webGL renderer only simple polys can be filled at this stage * Complex polys will not be filled. Heres an example of a complex poly: http://www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png * - * @class Graphics + * @class Graphics * @extends DisplayObjectContainer * @constructor */ PIXI.Graphics = function() { PIXI.DisplayObjectContainer.call( this ); - + this.renderable = true; /** @@ -7028,14 +7191,14 @@ PIXI.Graphics.prototype.constructor = PIXI.Graphics; PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - + this.lineWidth = lineWidth || 0; this.lineColor = color || 0; this.lineAlpha = (alpha == undefined) ? 1 : alpha; - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.graphicsData.push(this.currentPath); } @@ -7049,12 +7212,12 @@ PIXI.Graphics.prototype.lineStyle = function(lineWidth, color, alpha) PIXI.Graphics.prototype.moveTo = function(x, y) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + + this.currentPath = this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[], type:PIXI.Graphics.POLY}; - + this.currentPath.points.push(x, y); - + this.graphicsData.push(this.currentPath); } @@ -7084,7 +7247,7 @@ PIXI.Graphics.prototype.beginFill = function(color, alpha) { this.filling = true; this.fillColor = color || 0; - this.fillAlpha = alpha || 1; + this.fillAlpha = (alpha == undefined) ? 1 : alpha; } /** @@ -7110,11 +7273,11 @@ PIXI.Graphics.prototype.endFill = function() PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.RECT}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7130,11 +7293,11 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height ) PIXI.Graphics.prototype.drawCircle = function( x, y, radius) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, radius, radius], type:PIXI.Graphics.CIRC}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7151,11 +7314,11 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius) PIXI.Graphics.prototype.drawElipse = function( x, y, width, height) { if(this.currentPath.points.length == 0)this.graphicsData.pop(); - - this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, - fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, + + this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha, + fillColor:this.fillColor, fillAlpha:this.fillAlpha, fill:this.filling, points:[x, y, width, height], type:PIXI.Graphics.ELIP}; - + this.graphicsData.push(this.currentPath); this.dirty = true; } @@ -7169,7 +7332,7 @@ PIXI.Graphics.prototype.clear = function() { this.lineWidth = 0; this.filling = false; - + this.dirty = true; this.clearDirty = true; this.graphicsData = []; @@ -7190,20 +7353,20 @@ PIXI.Strip = function(texture, width, height) PIXI.DisplayObjectContainer.call( this ); this.texture = texture; this.blendMode = PIXI.blendModes.NORMAL; - + try { this.uvs = new Float32Array([0, 1, 1, 1, 1, 0, 0,1]); - + this.verticies = new Float32Array([0, 0, 0,0, 0,0, 0, 0, 0]); - + this.colors = new Float32Array([1, 1, 1, 1]); - + this.indices = new Uint16Array([0, 1, 2, 3]); } catch(error) @@ -7211,18 +7374,18 @@ PIXI.Strip = function(texture, width, height) this.uvs = [0, 1, 1, 1, 1, 0, 0,1]; - + this.verticies = [0, 0, 0,0, 0,0, 0, 0, 0]; - + this.colors = [1, 1, 1, 1]; - + this.indices = [0, 1, 2, 3]; } - - + + /* this.uvs = new Float32Array() this.verticies = new Float32Array() @@ -7231,7 +7394,7 @@ PIXI.Strip = function(texture, width, height) */ this.width = width; this.height = height; - + // load the texture! if(texture.baseTexture.hasLoaded) { @@ -7244,7 +7407,7 @@ PIXI.Strip = function(texture, width, height) this.onTextureUpdateBind = this.onTextureUpdate.bind(this); this.texture.addEventListener( 'update', this.onTextureUpdateBind ); } - + this.renderable = true; } @@ -7256,8 +7419,8 @@ PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; @@ -7280,7 +7443,7 @@ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; - + try { this.verticies = new Float32Array( points.length * 4); @@ -7291,12 +7454,12 @@ PIXI.Rope = function(texture, points) catch(error) { this.verticies = verticies - + this.uvs = uvs this.colors = colors this.indices = indices } - + this.refresh(); } @@ -7309,99 +7472,99 @@ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1)return; - + var uvs = this.uvs var indices = this.indices; var colors = this.colors; - + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - + + uvs[0] = 0 uvs[1] = 1 uvs[2] = 0 uvs[3] = 1 - + colors[0] = 1; colors[1] = 1; - + indices[0] = 0; indices[1] = 1; - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; // time to do some smart drawing! var amount = i/(total-1) - + if(i%2) { uvs[index] = amount; uvs[index+1] = 0; - + uvs[index+2] = amount uvs[index+3] = 1 - + } else { uvs[index] = amount uvs[index+1] = 0 - + uvs[index+2] = amount uvs[index+3] = 1 } - + index = i * 2; colors[index] = 1; colors[index+1] = 1; - + index = i * 2; indices[index] = index; indices[index + 1] = index + 1; - + lastPoint = point; } } PIXI.Rope.prototype.updateTransform = function() { - + var points = this.points; if(points.length < 1)return; - - var verticies = this.verticies - + + var verticies = this.verticies + var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; var point = points[0]; - + this.count-=0.2; - - verticies[0] = point.x + perp.x + + verticies[0] = point.x + perp.x verticies[1] = point.y + perp.y //+ 200 - verticies[2] = point.x - perp.x + verticies[2] = point.x - perp.x verticies[3] = point.y - perp.y//+200 // time to do some smart drawing! - + var total = points.length; - - for (var i = 1; i < total; i++) + + for (var i = 1; i < total; i++) { - + var point = points[i]; var index = i * 4; - + if(i < points.length-1) { nextPoint = points[i+1]; @@ -7410,35 +7573,35 @@ PIXI.Rope.prototype.updateTransform = function() { nextPoint = point } - + perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; - + var ratio = (1 - (i / (total-1))) * 10; if(ratio > 1)ratio = 1; - + var perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); var num = this.texture.height/2//(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; - + perp.x *= num; perp.y *= num; - - verticies[index] = point.x + perp.x + + verticies[index] = point.x + perp.x verticies[index+1] = point.y + perp.y - verticies[index+2] = point.x - perp.x + verticies[index+2] = point.x - perp.x verticies[index+3] = point.y - perp.y lastPoint = point; } - + PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); } PIXI.Rope.prototype.setTexture = function(texture) { - // stop current texture + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7494,7 +7657,7 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tileScale * @type Point - */ + */ this.tileScale = new PIXI.Point(1,1); /** @@ -7502,11 +7665,11 @@ PIXI.TilingSprite = function(texture, width, height) * * @property tilePosition * @type Point - */ + */ this.tilePosition = new PIXI.Point(0,0); this.renderable = true; - + this.blendMode = PIXI.blendModes.NORMAL } @@ -7524,8 +7687,8 @@ PIXI.TilingSprite.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY - - // stop current texture + + // stop current texture this.texture = texture; this.updateFrame = true; } @@ -7546,10 +7709,10 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) /** * @author Mat Groves http://matgroves.com/ @Doormat23 * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * + * * Awesome JS run time provided by EsotericSoftware * https://github.com/EsotericSoftware/spine-runtimes - * + * */ /** @@ -7562,48 +7725,41 @@ PIXI.TilingSprite.prototype.onTextureUpdate = function(event) * @constructor * @param url {String} The url of the spine anim file to be used */ -PIXI.Spine = function(url) -{ +PIXI.Spine = function (url) { PIXI.DisplayObjectContainer.call(this); - + this.spineData = PIXI.AnimCache[url]; - - if(!this.spineData) - { + + if (!this.spineData) { throw new Error("Spine data must be preloaded using PIXI.SpineLoader or PIXI.AssetLoader: " + url); - return; } - - this.count = 0; - - this.sprites = []; - + this.skeleton = new spine.Skeleton(this.spineData); this.skeleton.updateWorldTransform(); - this.stateData = new spine.AnimationStateData(this.spineData); + this.stateData = new spine.AnimationStateData(this.spineData); this.state = new spine.AnimationState(this.stateData); - - // add the sprites.. - for (var i = 0; i < this.skeleton.drawOrder.length; i++) { - - var attachmentName = this.skeleton.drawOrder[i].data.attachmentName; - - // kind of an assumtion here. that its a png - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; - } - - - var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(attachmentName)); - sprite.anchor.x = sprite.anchor.y = 0.5; - this.addChild(sprite); - this.sprites.push(sprite); - }; -} -PIXI.Spine.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); + this.slotContainers = []; + + for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { + var slot = this.skeleton.drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = new PIXI.DisplayObjectContainer(); + this.slotContainers.push(slotContainer); + this.addChild(slotContainer); + if (!(attachment instanceof spine.RegionAttachment)) { + continue; + } + var spriteName = attachment.rendererObject.name; + var sprite = this.createSprite(slot, attachment.rendererObject); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotContainer.addChild(sprite); + } +}; + +PIXI.Spine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Spine.prototype.constructor = PIXI.Spine; /* @@ -7612,55 +7768,74 @@ PIXI.Spine.prototype.constructor = PIXI.Spine; * @method updateTransform * @private */ -PIXI.Spine.prototype.updateTransform = function() -{ - // TODO should make this time based really.. - this.state.update(1/60); +PIXI.Spine.prototype.updateTransform = function () { + this.lastTime = this.lastTime || Date.now(); + var timeDelta = (Date.now() - this.lastTime) * 0.001; + this.lastTime = Date.now(); + this.state.update(timeDelta); this.state.apply(this.skeleton); this.skeleton.updateWorldTransform(); - - for (var i = 0; i < this.skeleton.drawOrder.length; i++) - { - var slot = this.skeleton.drawOrder[i]; + var drawOrder = this.skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.attachment; + var slotContainer = this.slotContainers[i]; + if (!(attachment instanceof spine.RegionAttachment)) { + slotContainer.visible = false; + continue; + } - var x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 + slot.attachment.width * 0.5; - var y = slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11 + slot.attachment.height * 0.5; - //console.log(x + ' : ' + y); - - - //console.log(slot.attachment.name) - if(slot.cacheName != slot.attachment.name) - { - var attachmentName = slot.attachment.name; - - if(!PIXI.TextureCache[attachmentName]) - { - attachmentName += ".png"; + if (attachment.rendererObject) { + if (!slot.currentSpriteName || slot.currentSpriteName != attachment.name) { + var spriteName = attachment.rendererObject.name; + if (slot.currentSprite !== undefined) { + slot.currentSprite.visible = false; } - - this.sprites[i].setTexture(PIXI.TextureCache[attachmentName]); - - slot.cacheName = slot.attachment.name; + slot.sprites = slot.sprites || {}; + if (slot.sprites[spriteName] !== undefined) { + slot.sprites[spriteName].visible = true; + } else { + var sprite = this.createSprite(slot, attachment.rendererObject); + slotContainer.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; } - - x += -((slot.attachment.width * (slot.bone.worldScaleX + slot.attachment.scaleX - 1))>>1); - y += -((slot.attachment.height * (slot.bone.worldScaleY + slot.attachment.scaleY - 1))>>1); - - - this.sprites[i].position.x = x; - this.sprites[i].position.y = y; - this.sprites[i].rotation = (-(slot.bone.worldRotation + slot.attachment.rotation)) * (Math.PI/180); - } - + } + slotContainer.visible = true; + + var bone = slot.bone; + + slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; + slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; + slotContainer.scale.x = bone.worldScaleX; + slotContainer.scale.y = bone.worldScaleY; + + slotContainer.rotation = -(slot.bone.worldRotation * Math.PI / 180); + } + PIXI.DisplayObjectContainer.prototype.updateTransform.call(this); -} +}; + + +PIXI.Spine.prototype.createSprite = function (slot, descriptor) { + var name = PIXI.TextureCache[descriptor.name] ? descriptor.name : descriptor.name + ".png"; + var sprite = new PIXI.Sprite(PIXI.Texture.fromFrame(name)); + sprite.scale = descriptor.scale; + sprite.rotation = descriptor.rotation; + sprite.anchor.x = sprite.anchor.y = 0.5; + + slot.sprites = slot.sprites || {}; + slot.sprites[descriptor.name] = sprite; + return sprite; +}; /* * Awesome JS run time provided by EsotericSoftware - * + * * https://github.com/EsotericSoftware/spine-runtimes - * + * */ var spine = {}; @@ -7770,7 +7945,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -8001,6 +8176,7 @@ spine.TranslateTimeline.prototype = { var frameTime = frames[frameIndex]; var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime); percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha; bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha; } @@ -8025,14 +8201,12 @@ spine.ScaleTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. - + var bone = skeleton.bones[this.boneIndex]; if (time >= frames[frames.length - 3]) { // Time is after last frame. bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha; - - return; } @@ -8070,6 +8244,7 @@ spine.ColorTimeline.prototype = { apply: function (skeleton, time, alpha) { var frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + var slot = skeleton.slots[this.slotIndex]; if (time >= frames[frames.length - 5]) { // Time is after last frame. @@ -8119,7 +8294,7 @@ spine.AttachmentTimeline = function (frameCount) { spine.AttachmentTimeline.prototype = { slotIndex: 0, getFrameCount: function () { - return this.frames.length / 2; + return this.frames.length; }, setFrame: function (frameIndex, time, attachmentName) { this.frames[frameIndex] = time; @@ -8136,11 +8311,6 @@ spine.AttachmentTimeline.prototype = { frameIndex = spine.binarySearch(frames, time, 1) - 1; var attachmentName = this.attachmentNames[frameIndex]; - //console.log(skeleton.slots[this.slotIndex]) - - // change the name! - // skeleton.slots[this.slotIndex].attachmentName = attachmentName; - skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); } }; @@ -8312,11 +8482,9 @@ spine.Skeleton.prototype = { if (slot.data.name == slotName) { var attachment = null; if (attachmentName) { - attachment = this.getAttachment(i, attachmentName); if (attachment == null) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; } - slot.setAttachment(attachment); return; } @@ -8398,7 +8566,6 @@ spine.RegionAttachment.prototype = { offset[7/*Y4*/] = localYCos + localX2Sin; }, computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; y += bone.worldY; var m00 = bone.m00; @@ -8422,6 +8589,7 @@ spine.AnimationStateData = function (skeletonData) { this.animationToMixTime = {}; }; spine.AnimationStateData.prototype = { + defaultMix: 0, setMixByName: function (fromName, toName, duration) { var from = this.skeletonData.findAnimation(fromName); if (!from) throw "Animation not found: " + fromName; @@ -8434,7 +8602,7 @@ spine.AnimationStateData.prototype = { }, getMix: function (from, to) { var time = this.animationToMixTime[from.name + ":" + to.name]; - return time ? time : 0; + return time ? time : this.defaultMix; } }; @@ -8474,7 +8642,7 @@ spine.AnimationState.prototype = { this.previous = null; } this.current.mix(skeleton, this.currentTime, this.currentLoop, alpha); - } else + } else this.current.apply(skeleton, this.currentTime, this.currentLoop); }, clearAnimation: function () { @@ -8620,16 +8788,9 @@ spine.SkeletonJson.prototype = { name = map["name"] || name; var type = spine.AttachmentType[map["type"] || "region"]; - - // @ekelokorpi - // var attachment = this.attachmentLoader.newAttachment(skin, type, name); - var attachment = new spine.RegionAttachment(); - - // @Doormat23 - // add the name of the attachment - attachment.name = name; - + if (type == spine.AttachmentType.region) { + var attachment = new spine.RegionAttachment(); attachment.x = (map["x"] || 0) * this.scale; attachment.y = (map["y"] || 0) * this.scale; attachment.scaleX = map["scaleX"] || 1; @@ -8638,10 +8799,19 @@ spine.SkeletonJson.prototype = { attachment.width = (map["width"] || 32) * this.scale; attachment.height = (map["height"] || 32) * this.scale; attachment.updateOffset(); + + attachment.rendererObject = {}; + attachment.rendererObject.name = name; + attachment.rendererObject.scale = {}; + attachment.rendererObject.scale.x = attachment.scaleX; + attachment.rendererObject.scale.y = attachment.scaleY; + attachment.rendererObject.rotation = -attachment.rotation * Math.PI / 180; + return attachment; } - return attachment; + throw "Unknown attachment type: " + type; }, + readAnimation: function (name, map, skeletonData) { var timelines = []; var duration = 0; @@ -8692,7 +8862,7 @@ spine.SkeletonJson.prototype = { } timelines.push(timeline); duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - + } else throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; } @@ -8735,8 +8905,8 @@ spine.SkeletonJson.prototype = { timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); } timelines.push(timeline); - // PIXI FIX - duration = Math.max(duration, timeline.frames[Math.floor(timeline.getFrameCount()) - 1]); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; } @@ -9005,14 +9175,14 @@ spine.Bone.yDown = true; /** * This object is one that will allow you to specify custom rendering functions based on render type * - * @class CustomRenderable + * @class CustomRenderable * @extends DisplayObject * @constructor */ PIXI.CustomRenderable = function() { PIXI.DisplayObject.call( this ); - + } // constructor @@ -9118,19 +9288,19 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } else { - + var scope = this; this.source.onload = function(){ - + scope.hasLoaded = true; scope.width = scope.source.width; scope.height = scope.source.height; - + // add it to somewhere... PIXI.texturesToUpdate.push(scope); scope.dispatchEvent( { type: 'loaded', content: scope } ); @@ -9143,7 +9313,7 @@ PIXI.BaseTexture = function(source) this.hasLoaded = true; this.width = this.source.width; this.height = this.source.height; - + PIXI.texturesToUpdate.push(this); } @@ -9183,7 +9353,7 @@ PIXI.BaseTexture.fromImage = function(imageUrl, crossorigin) { // new Image() breaks tex loading in some versions of Chrome. // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); + var image = new Image();//document.createElement('img'); if (crossorigin) { image.crossOrigin = ''; @@ -9211,7 +9381,7 @@ PIXI.FrameCache = {}; * @uses EventTarget * @constructor * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param frmae {Rectangle} The rectangle frame of the texture to show + * @param frame {Rectangle} The rectangle frame of the texture to show */ PIXI.Texture = function(baseTexture, frame) { @@ -9256,7 +9426,7 @@ PIXI.Texture = function(baseTexture, frame) { if(this.noFrame)frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height); //console.log(frame) - + this.setFrame(frame); } else @@ -9335,13 +9505,13 @@ PIXI.Texture.prototype.setFrame = function(frame) PIXI.Texture.fromImage = function(imageUrl, crossorigin) { var texture = PIXI.TextureCache[imageUrl]; - + if(!texture) { texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(imageUrl, crossorigin)); PIXI.TextureCache[imageUrl] = texture; } - + return texture; } @@ -9391,7 +9561,7 @@ PIXI.Texture.addTextureToCache = function(texture, id) } /** - * Remove a texture from the textureCache. + * Remove a texture from the textureCache. * * @static * @method removeTextureFromCache @@ -9503,15 +9673,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // create a projection matrix.. this.projection = new PIXI.Point(this.width/2 , this.height/2); -/* - this.projectionMatrix = PIXI.mat4.create(); - this.projectionMatrix[5] = 2/this.height// * 0.5; - this.projectionMatrix[13] = -1; - - this.projectionMatrix[0] = 2/this.width; - this.projectionMatrix[12] = -1; -*/ // set the correct render function.. this.render = this.renderWebGL; @@ -9525,10 +9687,6 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - //this.frame.width = this.width - //this.frame.height = this.height; - - if(PIXI.gl) { this.projection.x = this.width/2 @@ -9592,6 +9750,7 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var children = displayObject.children; //TODO -? create a new one??? dont think so! + var originalWorldTransform = displayObject.worldTransform; displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; @@ -9604,8 +9763,9 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle displayObject.worldTransform[5] -= position.y; } - - + PIXI.visibleCount++; + displayObject.vcount = PIXI.visibleCount; + for(var i=0,j=children.length; i- format + */ +PIXI.ImageLoader.prototype.loadFramedSpriteSheet = function(frameWidth, frameHeight, textureName) +{ + this.frames = []; + var cols = Math.floor(this.texture.width / frameWidth); + var rows = Math.floor(this.texture.height / frameHeight); + + var i=0; + for (var y=0; y= 0; i--) { var child = children[i]; - + // if(child.visible) { // push all interactive bits if(child.interactive) @@ -146,7 +144,7 @@ PIXI.InteractionManager.prototype.setTarget = function(target) PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) { //remove previouse listeners - if( this.interactionDOMElement !== null ) + if( this.interactionDOMElement !== null ) { this.interactionDOMElement.style['-ms-content-zooming'] = ''; this.interactionDOMElement.style['-ms-touch-action'] = ''; @@ -162,12 +160,12 @@ PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) } - if (window.navigator.msPointerEnabled) + if (window.navigator.msPointerEnabled) { // time to remove some of that zoom in ja.. domElement.style['-ms-content-zooming'] = 'none'; domElement.style['-ms-touch-action'] = 'none'; - + // DO some window specific touch! } @@ -193,7 +191,7 @@ PIXI.InteractionManager.prototype.setTargetDomElement = function(domElement) PIXI.InteractionManager.prototype.update = function() { if(!this.target)return; - + // frequency of 30fps?? var now = Date.now(); var diff = now - this.last; @@ -201,44 +199,44 @@ PIXI.InteractionManager.prototype.update = function() if(diff < 1)return; this.last = now; // - + // ok.. so mouse events?? // yes for now :) // OPTIMSE - how often to check?? if(this.dirty) { this.dirty = false; - + var len = this.interactiveItems.length; - + for (var i=0; i < len; i++) { this.interactiveItems[i].interactiveChildren = false; } - + this.interactiveItems = []; - + if(this.stage.interactive)this.interactiveItems.push(this.stage); // go through and collect all the objects that are interactive.. this.collectInteractiveSprite(this.stage, this.stage); } - + // loop through interactive objects! var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - + + this.interactionDOMElement.style.cursor = "default"; + for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - - + + //if(!item.visible)continue; - + // OPTIMISATION - only calculate every time if the mousemove function exists.. // OK so.. does the object have any other interactive functions? // hit-test the clip! - - + + if(item.mouseover || item.mouseout || item.buttonMode) { // ok so there are some functions so lets hit test it.. @@ -248,13 +246,13 @@ PIXI.InteractionManager.prototype.update = function() // loks like there was a hit! if(item.__hit) { - if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; - + if(item.buttonMode) this.interactionDOMElement.style.cursor = "pointer"; + if(!item.__isOver) { - + if(item.mouseover)item.mouseover(this.mouse); - item.__isOver = true; + item.__isOver = true; } } else @@ -263,11 +261,11 @@ PIXI.InteractionManager.prototype.update = function() { // roll out! if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; + item.__isOver = false; } } } - + // ---> } } @@ -284,18 +282,18 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) this.mouse.originalEvent = event || window.event; //IE uses window.event // TODO optimize by not check EVERY TIME! maybe half as often? // var rect = this.interactionDOMElement.getBoundingClientRect(); - + this.mouse.global.x = (event.clientX - rect.left) * (this.target.width / rect.width); this.mouse.global.y = (event.clientY - rect.top) * ( this.target.height / rect.height); - + var length = this.interactiveItems.length; var global = this.mouse.global; - - + + for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - + if(item.mousemove) { //call the function! @@ -314,34 +312,34 @@ PIXI.InteractionManager.prototype.onMouseMove = function(event) PIXI.InteractionManager.prototype.onMouseDown = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event - + // loop through inteaction tree... - // hit test each item! -> + // hit test each item! -> // get interactive items under point?? //stage.__i var length = this.interactiveItems.length; var global = this.mouse.global; - + var index = 0; var parent = this.stage; - - // while - // hit test + + // while + // hit test for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - + if(item.mousedown || item.click) { item.__mouseIsDown = true; item.__hit = this.hitTest(item, this.mouse); - + if(item.__hit) { //call the function! if(item.mousedown)item.mousedown(this.mouse); item.__isDown = true; - + // just the one! if(!item.interactiveChildren)break; } @@ -353,18 +351,18 @@ PIXI.InteractionManager.prototype.onMouseDown = function(event) PIXI.InteractionManager.prototype.onMouseOut = function(event) { var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = "default"; - + + this.interactionDOMElement.style.cursor = "default"; + for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - + if(item.__isOver) { this.mouse.target = item; if(item.mouseout)item.mouseout(this.mouse); - item.__isOver = false; + item.__isOver = false; } } } @@ -379,21 +377,21 @@ PIXI.InteractionManager.prototype.onMouseOut = function(event) PIXI.InteractionManager.prototype.onMouseUp = function(event) { this.mouse.originalEvent = event || window.event; //IE uses window.event - + var global = this.mouse.global; - - + + var length = this.interactiveItems.length; var up = false; - + for (var i = 0; i < length; i++) { var item = this.interactiveItems[i]; - + if(item.mouseup || item.mouseupoutside || item.click) { item.__hit = this.hitTest(item, this.mouse); - + if(item.__hit && !up) { //call the function! @@ -405,7 +403,7 @@ PIXI.InteractionManager.prototype.onMouseUp = function(event) { if(item.click)item.click(this.mouse); } - + if(!item.interactiveChildren)up = true; } else @@ -415,8 +413,8 @@ PIXI.InteractionManager.prototype.onMouseUp = function(event) if(item.mouseupoutside)item.mouseupoutside(this.mouse); } } - - item.__isDown = false; + + item.__isDown = false; } } } @@ -432,7 +430,7 @@ PIXI.InteractionManager.prototype.onMouseUp = function(event) PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) { var global = interactionData.global; - + if(item.vcount !== PIXI.visibleCount)return false; var isSprite = (item instanceof PIXI.Sprite), @@ -444,7 +442,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; interactionData.target = item; - + //a sprite or display object with a hit area defined if(item.hitArea && item.hitArea.contains) { if(item.hitArea.contains(x, y)) { @@ -453,7 +451,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) return true; } - + return false; } // a sprite with no hitarea defined @@ -463,11 +461,11 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) height = item.texture.frame.height, x1 = -width * item.anchor.x, y1; - + if(x > x1 && x < x1 + width) { y1 = -height * item.anchor.y; - + if(y > y1 && y < y1 + height) { // set the target property if a hit is true! @@ -478,7 +476,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) } var length = item.children.length; - + for (var i = 0; i < length; i++) { var tempItem = item.children[i]; @@ -491,7 +489,7 @@ PIXI.InteractionManager.prototype.hitTest = function(item, interactionData) } } - return false; + return false; } /** @@ -505,18 +503,18 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) { var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) + + for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; touchData.originalEvent = event || window.event; - + // update the touch position touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); } - + var length = this.interactiveItems.length; for (var i = 0; i < length; i++) { @@ -535,38 +533,38 @@ PIXI.InteractionManager.prototype.onTouchMove = function(event) PIXI.InteractionManager.prototype.onTouchStart = function(event) { var rect = this.interactionDOMElement.getBoundingClientRect(); - + var changedTouches = event.changedTouches; - for (var i=0; i < changedTouches.length; i++) + for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; - + var touchData = this.pool.pop(); if(!touchData)touchData = new PIXI.InteractionData(); - + touchData.originalEvent = event || window.event; - + this.touchs[touchEvent.identifier] = touchData; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - + var length = this.interactiveItems.length; - + for (var j = 0; j < length; j++) { var item = this.interactiveItems[j]; - + if(item.touchstart || item.tap) { item.__hit = this.hitTest(item, touchData); - + if(item.__hit) { //call the function! if(item.touchstart)item.touchstart(touchData); item.__isDown = true; item.__touchData = touchData; - + if(!item.interactiveChildren)break; } } @@ -586,28 +584,28 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) //this.mouse.originalEvent = event || window.event; //IE uses window.event var rect = this.interactionDOMElement.getBoundingClientRect(); var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) + + for (var i=0; i < changedTouches.length; i++) { var touchEvent = changedTouches[i]; var touchData = this.touchs[touchEvent.identifier]; var up = false; touchData.global.x = (touchEvent.clientX - rect.left) * (this.target.width / rect.width); touchData.global.y = (touchEvent.clientY - rect.top) * (this.target.height / rect.height); - + var length = this.interactiveItems.length; for (var j = 0; j < length; j++) { var item = this.interactiveItems[j]; var itemTouchData = item.__touchData; // <-- Here! item.__hit = this.hitTest(item, touchData); - + if(itemTouchData == touchData) { // so this one WAS down... touchData.originalEvent = event || window.event; // hitTest?? - + if(item.touchend || item.tap) { if(item.__hit && !up) @@ -617,7 +615,7 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) { if(item.tap)item.tap(touchData); } - + if(!item.interactiveChildren)up = true; } else @@ -627,16 +625,16 @@ PIXI.InteractionManager.prototype.onTouchEnd = function(event) if(item.touchendoutside)item.touchendoutside(touchData); } } - + item.__isDown = false; } - + item.__touchData = null; - + } else { - + } } // remove the touch.. @@ -656,11 +654,11 @@ PIXI.InteractionData = function() /** * This point stores the global coords of where the touch/mouse event happened * - * @property global + * @property global * @type Point */ this.global = new PIXI.Point(); - + // this is here for legacy... but will remove this.local = new PIXI.Point(); @@ -692,7 +690,7 @@ PIXI.InteractionData.prototype.getLocalPosition = function(displayObject) { var worldTransform = displayObject.worldTransform; var global = this.global; - + // do a cheeky transform to get the mouse coords; var a00 = worldTransform[0], a01 = worldTransform[1], a02 = worldTransform[2], a10 = worldTransform[3], a11 = worldTransform[4], a12 = worldTransform[5], diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index f7874f3..455284d 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -12,7 +12,6 @@ PIXI.DisplayObject = function() { this.last = this; this.first = this; - /** * The coordinate of the object relative to the local coordinates of the parent. * @@ -50,7 +49,7 @@ PIXI.DisplayObject = function() * * @property alpha * @type Number - */ + */ this.alpha = 1; /** @@ -58,7 +57,7 @@ PIXI.DisplayObject = function() * * @property visible * @type Boolean - */ + */ this.visible = true; /** @@ -67,7 +66,7 @@ PIXI.DisplayObject = function() * * @property hitArea * @type Rectangle|Circle|Ellipse|Polygon - */ + */ this.hitArea = null; /** @@ -92,7 +91,7 @@ PIXI.DisplayObject = function() * @property parent * @type DisplayObjectContainer * @readOnly - */ + */ this.parent = null; /** @@ -101,7 +100,7 @@ PIXI.DisplayObject = function() * @property stage * @type Stage * @readOnly - */ + */ this.stage = null; /** @@ -268,7 +267,7 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'interactive', { }, set: function(value) { this._interactive = value; - + // TODO more to be done here.. // need to sort out a re-crawl! if(this.stage)this.stage.dirty = true; @@ -288,17 +287,58 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { return this._mask; }, set: function(value) { - - this._mask = value; - + + if(value) { + if(this._mask) + { + value.start = this._mask.start; + value.end = this._mask.end; + } + else + { + this.addFilter(value); + value.renderable = false; + } + } + else + { + this.removeFilter(this._mask); + this._mask.renderable = true; + } + + this._mask = value; + } +}); + +/** + * Sets the filters for the displayObject. Currently there's a few limitations. + * 1: At the moment only one filter can be applied at a time.. + * 2: They cannot be nested. + * 3: There's no padding yet. + * 4: this is a webGL only feature. + * @property filters + * @type Array + */ +Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', { + get: function() { + return this._filters; + }, + set: function(value) { + + //if(value == ) + if(value) + { + if(this._filters)this.removeFilter(this._filters); this.addFilter(value) } else { - this.removeFilter(); + if(this._filters)this.removeFilter(this._filters); } + + this._filters = value; } }); @@ -309,54 +349,58 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'mask', { * @param mask {Graphics} the graphics object to use as a filter * @private */ -PIXI.DisplayObject.prototype.addFilter = function(mask) +PIXI.DisplayObject.prototype.addFilter = function(data) { - if(this.filter)return; - this.filter = true; - + //if(this.filter)return; + //this.filter = true; + // insert a filter block.. + // TODO Onject pool thease bad boys.. var start = new PIXI.FilterBlock(); var end = new PIXI.FilterBlock(); - - start.mask = mask; - end.mask = mask; - + + data.start = start; + data.end = end; + + start.data = data; + end.data = data; + start.first = start.last = this; end.first = end.last = this; - + start.open = true; - + /* * insert start */ - + var childFirst = start var childLast = start var nextObject; var previousObject; - + previousObject = this.first._iPrev; - + if(previousObject) { nextObject = previousObject._iNext; childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; + previousObject._iNext = childFirst; } else { nextObject = this; - } - + } + if(nextObject) { nextObject._iPrev = childLast; childLast._iNext = nextObject; } - - + + // now insert the end filter block.. - + /* * insert end filter */ @@ -364,21 +408,21 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) var childLast = end var nextObject = null; var previousObject = null; - + previousObject = this.last; nextObject = previousObject._iNext; - + if(nextObject) { nextObject._iPrev = childLast; childLast._iNext = nextObject; } - + childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; - + previousObject._iNext = childFirst; + var updateLast = this; - + var prevLast = this.last; while(updateLast) { @@ -388,17 +432,15 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) } updateLast = updateLast.parent; } - + this.first = start; - + // if webGL... if(this.__renderGroup) { this.__renderGroup.addFilterBlocks(start, end); } - - mask.renderable = false; - + } /* @@ -407,34 +449,34 @@ PIXI.DisplayObject.prototype.addFilter = function(mask) * @method removeFilter * @private */ -PIXI.DisplayObject.prototype.removeFilter = function() +PIXI.DisplayObject.prototype.removeFilter = function(data) { - if(!this.filter)return; - this.filter = false; - + //if(!this.filter)return; + //this.filter = false; + console.log("YUOIO") // modify the list.. - var startBlock = this.first; - + var startBlock = data.start; + + var nextObject = startBlock._iNext; var previousObject = startBlock._iPrev; - + if(nextObject)nextObject._iPrev = previousObject; - if(previousObject)previousObject._iNext = nextObject; - + if(previousObject)previousObject._iNext = nextObject; + this.first = startBlock._iNext; - - + // remove the end filter - var lastBlock = this.last; - + var lastBlock = data.end; + var nextObject = lastBlock._iNext; var previousObject = lastBlock._iPrev; - + if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - + previousObject._iNext = nextObject; + // this is always true too! - var tempLast = lastBlock._iPrev; + var tempLast = lastBlock._iPrev; // need to make sure the parents last is updated too var updateLast = this; while(updateLast.last == lastBlock) @@ -443,10 +485,7 @@ PIXI.DisplayObject.prototype.removeFilter = function() updateLast = updateLast.parent; if(!updateLast)break; } - - var mask = startBlock.mask - mask.renderable = true; - + // if webGL... if(this.__renderGroup) { @@ -468,8 +507,8 @@ PIXI.DisplayObject.prototype.updateTransform = function() this.rotationCache = this.rotation; this._sr = Math.sin(this.rotation); this._cr = Math.cos(this.rotation); - } - + } + var localTransform = this.localTransform; var parentTransform = this.parent.worldTransform; var worldTransform = this.worldTransform; @@ -478,12 +517,12 @@ PIXI.DisplayObject.prototype.updateTransform = function() localTransform[1] = -this._sr * this.scale.y localTransform[3] = this._sr * this.scale.x; localTransform[4] = this._cr * this.scale.y; - + // TODO --> do we even need a local matrix??? - + var px = this.pivot.x; var py = this.pivot.y; - + // Cache the matrix values (makes for huge speed increases!) var a00 = localTransform[0], a01 = localTransform[1], a02 = this.position.x - localTransform[0] * px - py * localTransform[1], a10 = localTransform[3], a11 = localTransform[4], a12 = this.position.y - localTransform[4] * py - px * localTransform[3], @@ -493,7 +532,7 @@ PIXI.DisplayObject.prototype.updateTransform = function() localTransform[2] = a02 localTransform[5] = a12 - + worldTransform[0] = b00 * a00 + b01 * a10; worldTransform[1] = b00 * a01 + b01 * a11; worldTransform[2] = b00 * a02 + b01 * a12 + b02; @@ -505,7 +544,7 @@ PIXI.DisplayObject.prototype.updateTransform = function() // because we are using affine transformation, we can optimise the matrix concatenation process.. wooo! // mat3.multiply(this.localTransform, this.parent.worldTransform, this.worldTransform); this.worldAlpha = this.alpha * this.parent.worldAlpha; - + this.vcount = PIXI.visibleCount; } diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index a438b3f..68ba15c 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -7,21 +7,21 @@ * A DisplayObjectContainer represents a collection of display objects. * It is the base class of all display objects that act as a container for other objects. * - * @class DisplayObjectContainer + * @class DisplayObjectContainer * @extends DisplayObject * @constructor */ PIXI.DisplayObjectContainer = function() { PIXI.DisplayObject.call( this ); - + /** * [read-only] The of children of this container. * * @property children * @type Array * @readOnly - */ + */ this.children = []; } @@ -29,18 +29,6 @@ PIXI.DisplayObjectContainer = function() PIXI.DisplayObjectContainer.prototype = Object.create( PIXI.DisplayObject.prototype ); PIXI.DisplayObjectContainer.prototype.constructor = PIXI.DisplayObjectContainer; -//TODO make visible a getter setter -/* -Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'visible', { - get: function() { - return this._visible; - }, - set: function(value) { - this._visible = value; - - } -});*/ - /** * Adds a child to the container. * @@ -51,18 +39,18 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) { if(child.parent != undefined) { - + //// COULD BE THIS??? child.parent.removeChild(child); // return; } child.parent = this; - - this.children.push(child); - + + this.children.push(child); + // update the stage refference.. - + if(this.stage) { var tmpChild = child; @@ -71,20 +59,20 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) if(tmpChild.interactive)this.stage.dirty = true; tmpChild.stage = this.stage; tmpChild = tmpChild._iNext; - } + } while(tmpChild) } - + // LINKED LIST // - + // modify the list.. var childFirst = child.first var childLast = child.last; var nextObject; var previousObject; - + // this could be wrong if there is a filter?? - if(this.filter) + if(this._filters) { previousObject = this.last._iPrev; } @@ -94,12 +82,12 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } nextObject = previousObject._iNext; - + // always true in this case // need to make sure the parents last is updated too var updateLast = this; var prevLast = previousObject; - + while(updateLast) { if(updateLast.last == prevLast) @@ -108,15 +96,15 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) } updateLast = updateLast.parent; } - + if(nextObject) { nextObject._iPrev = childLast; childLast._iNext = nextObject; } - + childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; + previousObject._iNext = childFirst; // need to remove any render groups.. if(this.__renderGroup) @@ -126,7 +114,7 @@ PIXI.DisplayObjectContainer.prototype.addChild = function(child) // add them to the new render group.. this.__renderGroup.addDisplayObjectAndChildren(child); } - + } /** @@ -145,7 +133,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) child.parent.removeChild(child); } child.parent = this; - + if(this.stage) { var tmpChild = child; @@ -157,13 +145,13 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) } while(tmpChild) } - + // modify the list.. var childFirst = child.first; var childLast = child.last; var nextObject; var previousObject; - + if(index == this.children.length) { previousObject = this.last; @@ -186,18 +174,18 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) { previousObject = this.children[index-1].last; } - + nextObject = previousObject._iNext; - + // always true in this case if(nextObject) { nextObject._iPrev = childLast; childLast._iNext = nextObject; } - + childFirst._iPrev = previousObject; - previousObject._iNext = childFirst; + previousObject._iNext = childFirst; this.children.splice(index, 0, child); // need to remove any render groups.. @@ -208,7 +196,7 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) // add them to the new render group.. this.__renderGroup.addDisplayObjectAndChildren(child); } - + } else { @@ -227,21 +215,21 @@ PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) { /* - * this funtion needs to be recoded.. + * this funtion needs to be recoded.. * can be done a lot faster.. */ return; - + // need to fix this function :/ /* // TODO I already know this?? var index = this.children.indexOf( child ); var index2 = this.children.indexOf( child2 ); - - if ( index !== -1 && index2 !== -1 ) + + if ( index !== -1 && index2 !== -1 ) { // cool - + /* if(this.stage) { @@ -249,15 +237,15 @@ PIXI.DisplayObjectContainer.prototype.swapChildren = function(child, child2) // TODO sure there is a nicer way to achieve this! this.stage.__removeChild(child); this.stage.__removeChild(child2); - + this.stage.__addChild(child); this.stage.__addChild(child2); } - + // swap the positions.. this.children[index] = child2; this.children[index2] = child; - + } else { @@ -292,22 +280,22 @@ PIXI.DisplayObjectContainer.prototype.getChildAt = function(index) PIXI.DisplayObjectContainer.prototype.removeChild = function(child) { var index = this.children.indexOf( child ); - if ( index !== -1 ) + if ( index !== -1 ) { // unlink // // modify the list.. var childFirst = child.first; var childLast = child.last; - + var nextObject = childLast._iNext; var previousObject = childFirst._iPrev; - + if(nextObject)nextObject._iPrev = previousObject; - previousObject._iNext = nextObject; - + previousObject._iNext = nextObject; + if(this.last == childLast) { - var tempLast = childFirst._iPrev; + var tempLast = childFirst._iPrev; // need to make sure the parents last is updated too var updateLast = this; while(updateLast.last == childLast.last) @@ -317,10 +305,10 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) if(!updateLast)break; } } - + childLast._iNext = null; childFirst._iPrev = null; - + // update the stage reference.. if(this.stage) { @@ -330,16 +318,16 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) if(tmpChild.interactive)this.stage.dirty = true; tmpChild.stage = null; tmpChild = tmpChild._iNext; - } + } while(tmpChild) } - + // webGL trim if(child.__renderGroup) { child.__renderGroup.removeDisplayObjectAndChildren(child); } - + child.parent = undefined; this.children.splice( index, 1 ); } @@ -358,11 +346,11 @@ PIXI.DisplayObjectContainer.prototype.removeChild = function(child) PIXI.DisplayObjectContainer.prototype.updateTransform = function() { if(!this.visible)return; - + PIXI.DisplayObject.prototype.updateTransform.call( this ); - + for(var i=0,j=this.children.length; i 0) { PIXI.Texture.frameUpdates = []; } - - + + } /** @@ -121,7 +121,7 @@ PIXI.CanvasRenderer.prototype.resize = function(width, height) { this.width = width; this.height = height; - + this.view.width = width; this.view.height = height; } @@ -138,50 +138,50 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) // no loger recurrsive! var transform; var context = this.context; - + context.globalCompositeOperation = 'source-over'; - - // one the display object hits this. we can break the loop + + // one the display object hits this. we can break the loop var testObject = displayObject.last._iNext; displayObject = displayObject.first; - - do + + do { transform = displayObject.worldTransform; - + if(!displayObject.visible) { displayObject = displayObject.last._iNext; continue; } - + if(!displayObject.renderable) { displayObject = displayObject._iNext; continue; } - + if(displayObject instanceof PIXI.Sprite) { - + var frame = displayObject.texture.frame; - + if(frame && frame.width && frame.height) { context.globalAlpha = displayObject.worldAlpha; - + context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]); - - context.drawImage(displayObject.texture.baseTexture.source, + + context.drawImage(displayObject.texture.baseTexture.source, frame.x, frame.y, frame.width, frame.height, - (displayObject.anchor.x) * -frame.width, + (displayObject.anchor.x) * -frame.width, (displayObject.anchor.y) * -frame.height, frame.width, frame.height); - } + } } else if(displayObject instanceof PIXI.Strip) { @@ -204,37 +204,44 @@ PIXI.CanvasRenderer.prototype.renderDisplayObject = function(displayObject) } else if(displayObject instanceof PIXI.FilterBlock) { - if(displayObject.open) + if(PIXI.FilterBlock.data instanceof PIXI.Graphics) { - context.save(); - - var cacheAlpha = displayObject.mask.alpha; - var maskTransform = displayObject.mask.worldTransform; - - context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) - - displayObject.mask.worldAlpha = 0.5; - - context.worldAlpha = 0; - - PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); - context.clip(); - - displayObject.mask.worldAlpha = cacheAlpha; + if(displayObject.open) + { + context.save(); + + var cacheAlpha = displayObject.mask.alpha; + var maskTransform = displayObject.mask.worldTransform; + + context.setTransform(maskTransform[0], maskTransform[3], maskTransform[1], maskTransform[4], maskTransform[2], maskTransform[5]) + + displayObject.mask.worldAlpha = 0.5; + + context.worldAlpha = 0; + + PIXI.CanvasGraphics.renderGraphicsMask(displayObject.mask, context); + context.clip(); + + displayObject.mask.worldAlpha = cacheAlpha; + } + else + { + context.restore(); + } } else { - context.restore(); + // only masks supported right now! } } // count++ displayObject = displayObject._iNext; - - + + } while(displayObject != testObject) - + } /** @@ -249,26 +256,26 @@ PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) var context = this.context; var verticies = strip.verticies; var uvs = strip.uvs; - + var length = verticies.length/2; this.count++; - + context.beginPath(); - for (var i=1; i < length-2; i++) + for (var i=1; i < length-2; i++) { - + // draw some triangles! var index = i*2; - + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - + context.moveTo(x0, y0); context.lineTo(x1, y1); context.lineTo(x2, y2); - - }; - + + }; + context.fillStyle = "#FF0000"; context.fill(); context.closePath(); @@ -284,26 +291,26 @@ PIXI.CanvasRenderer.prototype.renderStripFlat = function(strip) PIXI.CanvasRenderer.prototype.renderTilingSprite = function(sprite) { var context = this.context; - + context.globalAlpha = sprite.worldAlpha; - + if(!sprite.__tilePattern) sprite.__tilePattern = context.createPattern(sprite.texture.baseTexture.source, "repeat"); - + context.beginPath(); - + var tilePosition = sprite.tilePosition; var tileScale = sprite.tileScale; - + // offset context.scale(tileScale.x,tileScale.y); context.translate(tilePosition.x, tilePosition.y); - + context.fillStyle = sprite.__tilePattern; context.fillRect(-tilePosition.x,-tilePosition.y,sprite.width / tileScale.x, sprite.height / tileScale.y); - + context.scale(1/tileScale.x, 1/tileScale.y); context.translate(-tilePosition.x, -tilePosition.y); - + context.closePath(); } @@ -321,18 +328,18 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) // draw triangles!! var verticies = strip.verticies; var uvs = strip.uvs; - + var length = verticies.length/2; this.count++; - for (var i=1; i < length-2; i++) + for (var i=1; i < length-2; i++) { - + // draw some triangles! var index = i*2; - + var x0 = verticies[index], x1 = verticies[index+2], x2 = verticies[index+4]; var y0 = verticies[index+1], y1 = verticies[index+3], y2 = verticies[index+5]; - + var u0 = uvs[index] * strip.texture.width, u1 = uvs[index+2] * strip.texture.width, u2 = uvs[index+4]* strip.texture.width; var v0 = uvs[index+1]* strip.texture.height, v1 = uvs[index+3] * strip.texture.height, v2 = uvs[index+5]* strip.texture.height; @@ -343,10 +350,10 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) context.lineTo(x1, y1); context.lineTo(x2, y2); context.closePath(); - + context.clip(); - - + + // Compute matrix transform var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2; var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2; @@ -355,16 +362,16 @@ PIXI.CanvasRenderer.prototype.renderStrip = function(strip) var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2; var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2; var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2 - v0*u1*y2 - u0*y1*v2; - - - - + + + + context.transform(delta_a/delta, delta_d/delta, delta_b/delta, delta_e/delta, delta_c/delta, delta_f/delta); - + context.drawImage(strip.texture.baseTexture.source, 0, 0); context.restore(); }; - + } diff --git a/src/pixi/renderers/webgl/PixiShader.js b/src/pixi/renderers/webgl/PixiShader.js new file mode 100644 index 0000000..97e61a3 --- /dev/null +++ b/src/pixi/renderers/webgl/PixiShader.js @@ -0,0 +1,70 @@ +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + */ + + +PIXI.PixiShader = function() +{ + // the webGL program.. + this.program; + + this.fragmentSrc = [ + "precision lowp float;", + "varying vec2 vTextureCoord;", + "varying float vColor;", + "uniform sampler2D uSampler;", + "void main(void) {", + "gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor;", + "}" + ]; + +} + +PIXI.PixiShader.prototype.init = function() +{ + var program = PIXI.compileProgram(this.vertexSrc || PIXI.shaderVertexSrc, this.fragmentSrc) + + var gl = PIXI.gl; + + gl.useProgram(program); + + // get the default shader bits! + program.vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + program.colorAttribute = gl.getAttribLocation(program, "aColor"); + program.textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord"); + + program.projectionVector = gl.getUniformLocation(program, "projectionVector"); + program.samplerUniform = gl.getUniformLocation(program, "uSampler"); + + // add those custom shaders! + for (var key in this.uniforms) + { + // get the uniform locations.. + program[key] = gl.getUniformLocation(program, key); + } + + this.program = program; +} + +PIXI.PixiShader.prototype.syncUniforms = function() +{ + var gl = PIXI.gl; + + for (var key in this.uniforms) + { + //var + var type = this.uniforms[key].type; + + // need to grow this! + if(type == "f") + { + gl.uniform1f(this.program[key], this.uniforms[key].value); + } + else if(type == "mat4") + { + gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); + } + } + +} + diff --git a/src/pixi/renderers/webgl/WebGLBatch.js b/src/pixi/renderers/webgl/WebGLBatch.js index 8b6305b..7d6758c 100644 --- a/src/pixi/renderers/webgl/WebGLBatch.js +++ b/src/pixi/renderers/webgl/WebGLBatch.js @@ -24,7 +24,7 @@ PIXI._getBatch = function(gl) */ PIXI._returnBatch = function(batch) { - batch.clean(); + batch.clean(); PIXI._batchs.push(batch); } @@ -33,7 +33,7 @@ PIXI._returnBatch = function(batch) */ PIXI._restoreBatchs = function(gl) { - for (var i=0; i < PIXI._batchs.length; i++) + for (var i=0; i < PIXI._batchs.length; i++) { PIXI._batchs[i].restoreLostContext(gl); }; @@ -54,7 +54,7 @@ PIXI._restoreBatchs = function(gl) PIXI.WebGLBatch = function(gl) { this.gl = gl; - + this.size = 0; this.vertexBuffer = gl.createBuffer(); @@ -108,7 +108,7 @@ PIXI.WebGLBatch.prototype.restoreLostContext = function(gl) * @method init * @param sprite {Sprite} the first sprite to be added to the batch. Only sprites with * the same base texture and blend mode will be allowed to be added to this batch - */ + */ PIXI.WebGLBatch.prototype.init = function(sprite) { sprite.batch = this; @@ -128,7 +128,7 @@ PIXI.WebGLBatch.prototype.init = function(sprite) * @method insertBefore * @param sprite {Sprite} the sprite to be added * @param nextSprite {nextSprite} the first sprite will be inserted before this sprite - */ + */ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) { this.size++; @@ -156,7 +156,7 @@ PIXI.WebGLBatch.prototype.insertBefore = function(sprite, nextSprite) * @method insertAfter * @param sprite {Sprite} the sprite to be added * @param previousSprite {Sprite} the first sprite will be inserted after this sprite - */ + */ PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) { this.size++; @@ -184,7 +184,7 @@ PIXI.WebGLBatch.prototype.insertAfter = function(sprite, previousSprite) * * @method remove * @param sprite {Sprite} the sprite to be removed - */ + */ PIXI.WebGLBatch.prototype.remove = function(sprite) { this.size--; @@ -268,7 +268,7 @@ PIXI.WebGLBatch.prototype.split = function(sprite) * Merges two batchs together * * @method merge - * @param batch {WebGLBatch} the batch that will be merged + * @param batch {WebGLBatch} the batch that will be merged */ PIXI.WebGLBatch.prototype.merge = function(batch) { @@ -325,10 +325,10 @@ PIXI.WebGLBatch.prototype.growBatch = function() this.dirtyColors = true; - this.indices = new Uint16Array(this.dynamicSize * 6); + this.indices = new Uint16Array(this.dynamicSize * 6); var length = this.indices.length/6; - for (var i=0; i < length; i++) + for (var i=0; i < length; i++) { var index2 = i * 6; var index3 = i * 4; @@ -381,7 +381,7 @@ PIXI.WebGLBatch.prototype.refresh = function() this.uvs[index +3] = frame.y / th; this.uvs[index +4] = (frame.x + frame.width) / tw; - this.uvs[index +5] = (frame.y + frame.height) / th; + this.uvs[index +5] = (frame.y + frame.height) / th; this.uvs[index +6] = frame.x / tw; this.uvs[index +7] = (frame.y + frame.height) / th; @@ -443,17 +443,17 @@ PIXI.WebGLBatch.prototype.update = function() tx = worldTransform[2]; ty = worldTransform[5]; - this.verticies[index + 0 ] = a * w1 + c * h1 + tx; + this.verticies[index + 0 ] = a * w1 + c * h1 + tx; this.verticies[index + 1 ] = d * h1 + b * w1 + ty; - this.verticies[index + 2 ] = a * w0 + c * h1 + tx; - this.verticies[index + 3 ] = d * h1 + b * w0 + ty; + this.verticies[index + 2 ] = a * w0 + c * h1 + tx; + this.verticies[index + 3 ] = d * h1 + b * w0 + ty; - this.verticies[index + 4 ] = a * w0 + c * h0 + tx; - this.verticies[index + 5 ] = d * h0 + b * w0 + ty; + this.verticies[index + 4 ] = a * w0 + c * h0 + tx; + this.verticies[index + 5 ] = d * h0 + b * w0 + ty; - this.verticies[index + 6] = a * w1 + c * h0 + tx; - this.verticies[index + 7] = d * h0 + b * w1 + ty; + this.verticies[index + 6] = a * w1 + c * h0 + tx; + this.verticies[index + 7] = d * h0 + b * w1 + ty; if(displayObject.updateFrame || displayObject.texture.updateFrame) { @@ -472,7 +472,7 @@ PIXI.WebGLBatch.prototype.update = function() this.uvs[index +3] = frame.y / th; this.uvs[index +4] = (frame.x + frame.width) / tw; - this.uvs[index +5] = (frame.y + frame.height) / th; + this.uvs[index +5] = (frame.y + frame.height) / th; this.uvs[index +6] = frame.x / tw; this.uvs[index +7] = (frame.y + frame.height) / th; @@ -522,7 +522,7 @@ PIXI.WebGLBatch.prototype.render = function(start, end) start = start || 0; if(end == undefined)end = this.size; - + if(this.dirty) { this.refresh(); @@ -536,8 +536,9 @@ PIXI.WebGLBatch.prototype.render = function(start, end) //TODO optimize this! - var shaderProgram = PIXI.shaderProgram; - gl.useProgram(shaderProgram); + var shaderProgram = PIXI.currentShader; + + //gl.useProgram(shaderProgram); // update the verts.. gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); @@ -545,6 +546,8 @@ PIXI.WebGLBatch.prototype.render = function(start, end) gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // update the uvs + var isDefault = (shaderProgram == PIXI.shaderProgram) + gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); if(this.dirtyUVS) @@ -568,7 +571,6 @@ PIXI.WebGLBatch.prototype.render = function(start, end) } gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); diff --git a/src/pixi/renderers/webgl/WebGLGraphics.js b/src/pixi/renderers/webgl/WebGLGraphics.js index 87d98be..55e9661 100644 --- a/src/pixi/renderers/webgl/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/WebGLGraphics.js @@ -9,7 +9,7 @@ */ PIXI.WebGLGraphics = function() { - + } /** @@ -24,62 +24,64 @@ PIXI.WebGLGraphics = function() PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) { var gl = PIXI.gl; - - if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, + + if(!graphics._webGL)graphics._webGL = {points:[], indices:[], lastIndex:0, buffer:gl.createBuffer(), indexBuffer:gl.createBuffer()}; - + if(graphics.dirty) { graphics.dirty = false; - + if(graphics.clearDirty) { graphics.clearDirty = false; - + graphics._webGL.lastIndex = 0; graphics._webGL.points = []; graphics._webGL.indices = []; - + } - + PIXI.WebGLGraphics.updateGraphics(graphics); } - - + + PIXI.activatePrimitiveShader(); - + // This could be speeded up fo sure! var m = PIXI.mat3.clone(graphics.worldTransform); - + PIXI.mat3.transpose(m); - - // set the matrix transform for the + + // set the matrix transform for the gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - + gl.uniformMatrix3fv(PIXI.primitiveProgram.translationMatrix, false, m); - + gl.uniform2f(PIXI.primitiveProgram.projectionVector, projection.x, projection.y); - + gl.uniform1f(PIXI.primitiveProgram.alpha, graphics.worldAlpha); gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); - + // WHY DOES THIS LINE NEED TO BE THERE??? - gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); + //gl.vertexAttribPointer(PIXI.shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); // its not even used.. but need to be set or it breaks? // only on pc though.. - + gl.vertexAttribPointer(PIXI.primitiveProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 4 * 6, 0); gl.vertexAttribPointer(PIXI.primitiveProgram.colorAttribute, 4, gl.FLOAT, false,4 * 6, 2 * 4); - + // set the index buffer! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); - + gl.drawElements(gl.TRIANGLE_STRIP, graphics._webGL.indices.length, gl.UNSIGNED_SHORT, 0 ); - + + PIXI.deactivatePrimitiveShader(); + // return to default shader... - PIXI.activateDefaultShader(); +// PIXI.activateShader(PIXI.defaultShader); } /** @@ -92,18 +94,18 @@ PIXI.WebGLGraphics.renderGraphics = function(graphics, projection) */ PIXI.WebGLGraphics.updateGraphics = function(graphics) { - for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) + for (var i=graphics._webGL.lastIndex; i < graphics.graphicsData.length; i++) { var data = graphics.graphicsData[i]; - + if(data.type == PIXI.Graphics.POLY) { if(data.fill) { - if(data.points.length>3) + if(data.points.length>3) PIXI.WebGLGraphics.buildPoly(data, graphics._webGL); } - + if(data.lineWidth > 0) { PIXI.WebGLGraphics.buildLine(data, graphics._webGL); @@ -118,18 +120,18 @@ PIXI.WebGLGraphics.updateGraphics = function(graphics) PIXI.WebGLGraphics.buildCircle(data, graphics._webGL); } }; - + graphics._webGL.lastIndex = graphics.graphicsData.length; - + var gl = PIXI.gl; graphics._webGL.glPoints = new Float32Array(graphics._webGL.points); - + gl.bindBuffer(gl.ARRAY_BUFFER, graphics._webGL.buffer); gl.bufferData(gl.ARRAY_BUFFER, graphics._webGL.glPoints, gl.STATIC_DRAW); - + graphics._webGL.glIndicies = new Uint16Array(graphics._webGL.indices); - + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, graphics._webGL.glIndicies, gl.STATIC_DRAW); } @@ -147,45 +149,45 @@ PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) { // --- // // need to convert points to a nice regular data - // + // var rectData = graphicsData.points; var x = rectData[0]; var y = rectData[1]; var width = rectData[2]; var height = rectData[3]; - - + + if(graphicsData.fill) { var color = HEXtoRGB(graphicsData.fillColor); var alpha = graphicsData.fillAlpha; - + var r = color[0] * alpha; var g = color[1] * alpha; var b = color[2] * alpha; - + var verts = webGLData.points; var indices = webGLData.indices; - + var vertPos = verts.length/6; - + // start verts.push(x, y); verts.push(r, g, b, alpha); - + verts.push(x + width, y); verts.push(r, g, b, alpha); - + verts.push(x , y + height); verts.push(r, g, b, alpha); - + verts.push(x + width, y + height); verts.push(r, g, b, alpha); - + // insert 2 dead triangles.. indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3) } - + if(graphicsData.lineWidth) { graphicsData.points = [x, y, @@ -193,10 +195,10 @@ PIXI.WebGLGraphics.buildRectangle = function(graphicsData, webGLData) x + width, y + height, x, y + height, x, y]; - + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); } - + } /** @@ -212,16 +214,16 @@ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) { // --- // // need to convert points to a nice regular data - // + // var rectData = graphicsData.points; var x = rectData[0]; var y = rectData[1]; var width = rectData[2]; var height = rectData[3]; - + var totalSegs = 40; var seg = (Math.PI * 2) / totalSegs ; - + if(graphicsData.fill) { var color = HEXtoRGB(graphicsData.fillColor); @@ -230,41 +232,41 @@ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) var r = color[0] * alpha; var g = color[1] * alpha; var b = color[2] * alpha; - + var verts = webGLData.points; var indices = webGLData.indices; - + var vecPos = verts.length/6; - + indices.push(vecPos); - - for (var i=0; i < totalSegs + 1 ; i++) + + for (var i=0; i < totalSegs + 1 ; i++) { verts.push(x,y, r, g, b, alpha); - + verts.push(x + Math.sin(seg * i) * width, y + Math.cos(seg * i) * height, r, g, b, alpha); - + indices.push(vecPos++, vecPos++); }; - + indices.push(vecPos-1); } - + if(graphicsData.lineWidth) { graphicsData.points = []; - - for (var i=0; i < totalSegs + 1; i++) + + for (var i=0; i < totalSegs + 1; i++) { graphicsData.points.push(x + Math.sin(seg * i) * width, y + Math.cos(seg * i) * height) }; - + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); } - + } /** @@ -279,89 +281,89 @@ PIXI.WebGLGraphics.buildCircle = function(graphicsData, webGLData) PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) { // TODO OPTIMISE! - + var wrap = true; var points = graphicsData.points; if(points.length == 0)return; - + // get first and last point.. figure out the middle! var firstPoint = new PIXI.Point( points[0], points[1] ); var lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - + // if the first point is the last point - goona have issues :) if(firstPoint.x == lastPoint.x && firstPoint.y == lastPoint.y) { points.pop(); points.pop(); - + lastPoint = new PIXI.Point( points[points.length - 2], points[points.length - 1] ); - + var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; - + points.unshift(midPointX, midPointY); points.push(midPointX, midPointY) } - + var verts = webGLData.points; var indices = webGLData.indices; var length = points.length / 2; var indexCount = points.length; var indexStart = verts.length/6; - + // DRAW the Line var width = graphicsData.lineWidth / 2; - + // sort color var color = HEXtoRGB(graphicsData.lineColor); var alpha = graphicsData.lineAlpha; var r = color[0] * alpha; var g = color[1] * alpha; var b = color[2] * alpha; - + var p1x, p1y, p2x, p2y, p3x, p3y; var perpx, perpy, perp2x, perp2y, perp3x, perp3y; var ipx, ipy; var a1, b1, c1, a2, b2, c2; var denom, pdist, dist; - + p1x = points[0]; p1y = points[1]; - + p2x = points[2]; p2y = points[3]; - + perpx = -(p1y - p2y); perpy = p1x - p2x; - + dist = Math.sqrt(perpx*perpx + perpy*perpy); - + perpx /= dist; perpy /= dist; perpx *= width; perpy *= width; - + // start verts.push(p1x - perpx , p1y - perpy, r, g, b, alpha); - + verts.push(p1x + perpx , p1y + perpy, r, g, b, alpha); - - for (var i = 1; i < length-1; i++) + + for (var i = 1; i < length-1; i++) { p1x = points[(i-1)*2]; p1y = points[(i-1)*2 + 1]; - + p2x = points[(i)*2] p2y = points[(i)*2 + 1] - + p3x = points[(i+1)*2]; p3y = points[(i+1)*2 + 1]; - + perpx = -(p1y - p2y); perpy = p1x - p2x; - + dist = Math.sqrt(perpx*perpx + perpy*perpy); perpx /= dist; perpy /= dist; @@ -370,91 +372,91 @@ PIXI.WebGLGraphics.buildLine = function(graphicsData, webGLData) perp2x = -(p2y - p3y); perp2y = p2x - p3x; - + dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); perp2x /= dist; perp2y /= dist; perp2x *= width; perp2y *= width; - + a1 = (-perpy + p1y) - (-perpy + p2y); b1 = (-perpx + p2x) - (-perpx + p1x); c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); a2 = (-perp2y + p3y) - (-perp2y + p2y); b2 = (-perp2x + p2x) - (-perp2x + p3x); c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); - + denom = a1*b2 - a2*b1; - + if (denom == 0) { denom+=1; } - + px = (b1*c2 - b2*c1)/denom; py = (a2*c1 - a1*c2)/denom; - + pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); - + if(pdist > 140 * 140) { perp3x = perpx - perp2x; perp3y = perpy - perp2y; - + dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); perp3x /= dist; perp3y /= dist; perp3x *= width; perp3y *= width; - + verts.push(p2x - perp3x, p2y -perp3y); verts.push(r, g, b, alpha); - + verts.push(p2x + perp3x, p2y +perp3y); verts.push(r, g, b, alpha); - + verts.push(p2x - perp3x, p2y -perp3y); verts.push(r, g, b, alpha); - + indexCount++; } else { verts.push(px , py); verts.push(r, g, b, alpha); - + verts.push(p2x - (px-p2x), p2y - (py - p2y)); verts.push(r, g, b, alpha); } } - + p1x = points[(length-2)*2] - p1y = points[(length-2)*2 + 1] - + p1y = points[(length-2)*2 + 1] + p2x = points[(length-1)*2] p2y = points[(length-1)*2 + 1] - + perpx = -(p1y - p2y) perpy = p1x - p2x; - + dist = Math.sqrt(perpx*perpx + perpy*perpy); perpx /= dist; perpy /= dist; perpx *= width; perpy *= width; - + verts.push(p2x - perpx , p2y - perpy) verts.push(r, g, b, alpha); - + verts.push(p2x + perpx , p2y + perpy) verts.push(r, g, b, alpha); - + indices.push(indexStart); - - for (var i=0; i < indexCount; i++) + + for (var i=0; i < indexCount; i++) { indices.push(indexStart++); }; - + indices.push(indexStart-1); } @@ -471,25 +473,25 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) { var points = graphicsData.points; if(points.length < 6)return; - + // get first and last point.. figure out the middle! var verts = webGLData.points; var indices = webGLData.indices; - + var length = points.length / 2; - + // sort color var color = HEXtoRGB(graphicsData.fillColor); var alpha = graphicsData.fillAlpha; var r = color[0] * alpha; var g = color[1] * alpha; var b = color[2] * alpha; - + var triangles = PIXI.PolyK.Triangulate(points); - + var vertPos = verts.length / 6; - - for (var i=0; i < triangles.length; i+=3) + + for (var i=0; i < triangles.length; i+=3) { indices.push(triangles[i] + vertPos); indices.push(triangles[i] + vertPos); @@ -497,8 +499,8 @@ PIXI.WebGLGraphics.buildPoly = function(graphicsData, webGLData) indices.push(triangles[i+2] +vertPos); indices.push(triangles[i+2] + vertPos); }; - - for (var i = 0; i < length; i++) + + for (var i = 0; i < length; i++) { verts.push(points[i * 2], points[i * 2 + 1], r, g, b, alpha); diff --git a/src/pixi/renderers/webgl/WebGLRenderGroup.js b/src/pixi/renderers/webgl/WebGLRenderGroup.js index a6507cf..f661a96 100644 --- a/src/pixi/renderers/webgl/WebGLRenderGroup.js +++ b/src/pixi/renderers/webgl/WebGLRenderGroup.js @@ -19,7 +19,7 @@ PIXI.WebGLRenderGroup = function(gl) { this.gl = gl; this.root; - + this.backgroundColor; this.batchs = []; this.toRemove = []; @@ -33,18 +33,18 @@ PIXI.WebGLRenderGroup.prototype.constructor = PIXI.WebGLRenderGroup; * * @method setRenderable * @param displayObject {DisplayObject} - * @private + * @private */ PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) { // has this changed?? if(this.root)this.removeDisplayObjectAndChildren(this.root); - + displayObject.worldVisible = displayObject.visible; - + // soooooo // // to check if any batchs exist already?? - + // TODO what if its already has an object? should remove it this.root = displayObject; this.addDisplayObjectAndChildren(displayObject); @@ -59,26 +59,24 @@ PIXI.WebGLRenderGroup.prototype.setRenderable = function(displayObject) PIXI.WebGLRenderGroup.prototype.render = function(projection) { PIXI.WebGLRenderer.updateTextures(); - + var gl = this.gl; - - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); + + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - // will render all the elements in the group var renderable; - - for (var i=0; i < this.batchs.length; i++) + for (var i=0; i < this.batchs.length; i++) { - + renderable = this.batchs[i]; if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); continue; } - + // non sprite batch.. var worldVisible = renderable.vcount === PIXI.visibleCount; @@ -96,42 +94,10 @@ PIXI.WebGLRenderGroup.prototype.render = function(projection) } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ - if(renderable.open) - { - gl.enable(gl.STENCIL_TEST); - - gl.colorMask(false, false, false, false); - gl.stencilFunc(gl.ALWAYS,1,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL,0,0xff); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - } - else - { - gl.disable(gl.STENCIL_TEST); - } + this.handleFilterBlock(renderable, projection); } } - -} - -/** - * Renders the stage to its webgl view - * - * @method handleFilter - * @param filter {FilterBlock} - * @private - */ -PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) -{ - + } /** @@ -145,20 +111,19 @@ PIXI.WebGLRenderGroup.prototype.handleFilter = function(filter, projection) PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, projection) { PIXI.WebGLRenderer.updateTextures(); - + var gl = this.gl; - - gl.uniform2f(PIXI.shaderProgram.projectionVector, projection.x, projection.y); - + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + // to do! // render part of the scene... - + var startIndex; var startBatchIndex; - + var endIndex; var endBatchIndex; - + /* * LOOK FOR THE NEXT SPRITE * This part looks for the closest next sprite that can go into a batch @@ -172,14 +137,14 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project if(nextRenderable.renderable && nextRenderable.__renderGroup)break; } var startBatch = nextRenderable.batch; - + if(nextRenderable instanceof PIXI.Sprite) { startBatch = nextRenderable.batch; - + var head = startBatch.head; var next = head; - + // ok now we have the batch.. need to find the start index! if(head == nextRenderable) { @@ -188,7 +153,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project else { startIndex = 1; - + while(head.__next != nextRenderable) { startIndex++; @@ -200,7 +165,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project { startBatch = nextRenderable; } - + // Get the LAST renderable object var lastRenderable = displayObject; var endBatch; @@ -208,15 +173,15 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project while(lastItem.children.length > 0) { lastItem = lastItem.children[lastItem.children.length-1]; - if(lastItem.renderable)lastRenderable = lastItem; + if(lastItem.renderable)lastRenderable = lastItem.last; } - + if(lastRenderable instanceof PIXI.Sprite) { endBatch = lastRenderable.batch; - + var head = endBatch.head; - + if(head == lastRenderable) { endIndex = 0; @@ -224,7 +189,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project else { endIndex = 1; - + while(head.__next != lastRenderable) { endIndex++; @@ -236,9 +201,9 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project { endBatch = lastRenderable; } - + // TODO - need to fold this up a bit! - + if(startBatch == endBatch) { if(startBatch instanceof PIXI.WebGLBatch) @@ -251,11 +216,11 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project } return; } - + // now we have first and last! startBatchIndex = this.batchs.indexOf(startBatch); endBatchIndex = this.batchs.indexOf(endBatch); - + // DO the first batch if(startBatch instanceof PIXI.WebGLBatch) { @@ -265,12 +230,12 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project { this.renderSpecial(startBatch, projection); } - + // DO the middle batchs.. - for (var i=startBatchIndex+1; i < endBatchIndex; i++) + for (var i=startBatchIndex+1; i < endBatchIndex; i++) { renderable = this.batchs[i]; - + if(renderable instanceof PIXI.WebGLBatch) { this.batchs[i].render(); @@ -280,7 +245,7 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project this.renderSpecial(renderable, projection); } } - + // DO the last batch.. if(endBatch instanceof PIXI.WebGLBatch) { @@ -302,6 +267,8 @@ PIXI.WebGLRenderGroup.prototype.renderSpecific = function(displayObject, project */ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) { + var sta = PIXI.shaderStack.length; + var worldVisible = renderable.vcount === PIXI.visibleCount if(renderable instanceof PIXI.TilingSprite) @@ -322,27 +289,58 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) } else if(renderable instanceof PIXI.FilterBlock) { - /* - * for now only masks are supported.. - */ + this.handleFilterBlock(renderable, projection); + } +} - var gl = PIXI.gl; +PIXI.WebGLRenderGroup.prototype.handleFilterBlock = function(renderable, projection) +{ + /* + * for now only masks are supported.. + */ + var gl = PIXI.gl; - if(renderable.open) + if(renderable.open) + { + if(renderable.data instanceof Array) + { + var filter = renderable.data[0]; + + if(!filter.shader) + { + var shader = new PIXI.PixiShader(); + + shader.fragmentSrc = filter.fragmentSrc; + shader.uniforms = filter.uniforms; + shader.init(); + + filter.shader = shader + } + + PIXI.activateShader(filter.shader); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } + else { gl.enable(gl.STENCIL_TEST); - + gl.colorMask(false, false, false, false); gl.stencilFunc(gl.ALWAYS,1,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE); - - PIXI.WebGLGraphics.renderGraphics(renderable.mask, projection); - - // we know this is a render texture so enable alpha too.. + PIXI.WebGLGraphics.renderGraphics(renderable.data, projection); + gl.colorMask(true, true, true, true); gl.stencilFunc(gl.NOTEQUAL,0,0xff); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); } + } + else + { + if(renderable.data instanceof Array) + { + PIXI.popShader(); + gl.uniform2f(PIXI.currentShader.projectionVector, projection.x, projection.y); + } else { gl.disable(gl.STENCIL_TEST); @@ -359,11 +357,11 @@ PIXI.WebGLRenderGroup.prototype.renderSpecial = function(renderable, projection) */ PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) { - + // TODO definitely can optimse this function.. - + this.removeObject(displayObject); - + /* * LOOK FOR THE PREVIOUS RENDERABLE * This part looks for the closest previous sprite that can go into a batch @@ -375,7 +373,7 @@ PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; } - + /* * LOOK FOR THE NEXT SPRITE * This part looks for the closest next sprite that can go into a batch @@ -388,7 +386,7 @@ PIXI.WebGLRenderGroup.prototype.updateTexture = function(displayObject) nextRenderable = nextRenderable._iNext; if(nextRenderable.renderable && nextRenderable.__renderGroup)break; } - + this.insertObject(displayObject, previousRenderable, nextRenderable); } @@ -410,13 +408,13 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * It keeps going back until it finds a sprite or the stage */ var previousRenderable = start; - while(previousRenderable != this.root) + while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; } this.insertAfter(start, previousRenderable); - + /* * LOOK FOR THE NEXT SPRITE * This part looks for the closest next sprite that can go into a batch @@ -424,7 +422,7 @@ PIXI.WebGLRenderGroup.prototype.addFilterBlocks = function(start, end) * scene graph */ var previousRenderable2 = end; - while(previousRenderable2 != this.root) + while(previousRenderable2 != this.root.first) { previousRenderable2 = previousRenderable2._iPrev; if(previousRenderable2.renderable && previousRenderable2.__renderGroup)break; @@ -456,20 +454,20 @@ PIXI.WebGLRenderGroup.prototype.removeFilterBlocks = function(start, end) PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayObject) { if(displayObject.__renderGroup)displayObject.__renderGroup.removeDisplayObjectAndChildren(displayObject); - + /* * LOOK FOR THE PREVIOUS RENDERABLE * This part looks for the closest previous sprite that can go into a batch * It keeps going back until it finds a sprite or the stage */ - + var previousRenderable = displayObject.first; while(previousRenderable != this.root.first) { previousRenderable = previousRenderable._iPrev; if(previousRenderable.renderable && previousRenderable.__renderGroup)break; } - + /* * LOOK FOR THE NEXT SPRITE * This part looks for the closest next sprite that can go into a batch @@ -482,22 +480,22 @@ PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayOb nextRenderable = nextRenderable._iNext; if(nextRenderable.renderable && nextRenderable.__renderGroup)break; } - - // one the display object hits this. we can break the loop - + + // one the display object hits this. we can break the loop + var tempObject = displayObject.first; var testObject = displayObject.last._iNext; - do + do { tempObject.__renderGroup = this; - + if(tempObject.renderable) { - + this.insertObject(tempObject, previousRenderable, nextRenderable); previousRenderable = tempObject; } - + tempObject = tempObject._iNext; } while(tempObject != testObject) @@ -513,10 +511,10 @@ PIXI.WebGLRenderGroup.prototype.addDisplayObjectAndChildren = function(displayOb PIXI.WebGLRenderGroup.prototype.removeDisplayObjectAndChildren = function(displayObject) { if(displayObject.__renderGroup != this)return; - + // var displayObject = displayObject.first; var lastObject = displayObject.last; - do + do { displayObject.__renderGroup = null; if(displayObject.renderable)this.removeObject(displayObject); @@ -539,16 +537,16 @@ PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousO // while looping below THE OBJECT MAY NOT HAVE BEEN ADDED var previousSprite = previousObject; var nextSprite = nextObject; - + /* * so now we have the next renderable and the previous renderable - * + * */ if(displayObject instanceof PIXI.Sprite) { var previousBatch var nextBatch - + if(previousSprite instanceof PIXI.Sprite) { previousBatch = previousSprite.batch; @@ -566,13 +564,13 @@ PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousO // TODO reword! previousBatch = previousSprite; } - + if(nextSprite) { if(nextSprite instanceof PIXI.Sprite) { nextBatch = nextSprite.batch; - + //batch may not exist if item was added to the display list but not to the webGL if(nextBatch) { @@ -588,18 +586,18 @@ PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousO // THERE IS A SPLIT IN THIS BATCH! // var splitBatch = previousBatch.split(nextSprite); // COOL! - // add it back into the array + // add it back into the array /* * OOPS! * seems the new sprite is in the middle of a batch - * lets split it.. + * lets split it.. */ var batch = PIXI.WebGLRenderer.getBatch(); var index = this.batchs.indexOf( previousBatch ); batch.init(displayObject); this.batchs.splice(index+1, 0, batch, splitBatch); - + return; } } @@ -608,21 +606,21 @@ PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousO else { // TODO re-word! - + nextBatch = nextSprite; } } - + /* * looks like it does not belong to any batch! * but is also not intersecting one.. * time to create anew one! */ - + var batch = PIXI.WebGLRenderer.getBatch(); batch.init(displayObject); - if(previousBatch) // if this is invalid it means + if(previousBatch) // if this is invalid it means { var index = this.batchs.indexOf( previousBatch ); this.batchs.splice(index+1, 0, batch); @@ -631,16 +629,16 @@ PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousO { this.batchs.push(batch); } - + return; } else if(displayObject instanceof PIXI.TilingSprite) { - + // add to a batch!! this.initTilingSprite(displayObject); // this.batchs.push(displayObject); - + } else if(displayObject instanceof PIXI.Strip) { @@ -651,14 +649,14 @@ PIXI.WebGLRenderGroup.prototype.insertObject = function(displayObject, previousO else if(displayObject)// instanceof PIXI.Graphics) { //displayObject.initWebGL(this); - + // add to a batch!! //this.initStrip(displayObject); //this.batchs.push(displayObject); } - + this.insertAfter(displayObject, previousSprite); - + // insert and SPLIT! } @@ -676,31 +674,31 @@ PIXI.WebGLRenderGroup.prototype.insertAfter = function(item, displayObject) if(displayObject instanceof PIXI.Sprite) { var previousBatch = displayObject.batch; - + if(previousBatch) { // so this object is in a batch! - + // is it not? need to split the batch if(previousBatch.tail == displayObject) { - // is it tail? insert in to batchs + // is it tail? insert in to batchs var index = this.batchs.indexOf( previousBatch ); this.batchs.splice(index+1, 0, item); } else { // TODO MODIFY ADD / REMOVE CHILD TO ACCOUNT FOR FILTERS (also get prev and next) // - + // THERE IS A SPLIT IN THIS BATCH! // var splitBatch = previousBatch.split(displayObject.__next); - + // COOL! - // add it back into the array + // add it back into the array /* * OOPS! * seems the new sprite is in the middle of a batch - * lets split it.. + * lets split it.. */ var index = this.batchs.indexOf( previousBatch ); this.batchs.splice(index+1, 0, item, splitBatch); @@ -729,25 +727,25 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) { // loop through children.. // display object // - + // add a child from the render group.. // remove it and all its children! //displayObject.cacheVisible = false;//displayObject.visible; /* * removing is a lot quicker.. - * + * */ var batchToRemove; - + if(displayObject instanceof PIXI.Sprite) { // should always have a batch! var batch = displayObject.batch; if(!batch)return; // this means the display list has been altered befre rendering - + batch.remove(displayObject); - + if(batch.size==0) { batchToRemove = batch; @@ -757,15 +755,15 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) { batchToRemove = displayObject; } - + /* * Looks like there is somthing that needs removing! */ - if(batchToRemove) + if(batchToRemove) { var index = this.batchs.indexOf( batchToRemove ); if(index == -1)return;// this means it was added then removed before rendered - + // ok so.. check to see if you adjacent batchs should be joined. // TODO may optimise? if(index == 0 || index == this.batchs.length-1) @@ -773,29 +771,30 @@ PIXI.WebGLRenderGroup.prototype.removeObject = function(displayObject) // wha - eva! just get of the empty batch! this.batchs.splice(index, 1); if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); - + return; } - + if(this.batchs[index-1] instanceof PIXI.WebGLBatch && this.batchs[index+1] instanceof PIXI.WebGLBatch) { if(this.batchs[index-1].texture == this.batchs[index+1].texture && this.batchs[index-1].blendMode == this.batchs[index+1].blendMode) { //console.log("MERGE") this.batchs[index-1].merge(this.batchs[index+1]); - + if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); PIXI.WebGLRenderer.returnBatch(this.batchs[index+1]); this.batchs.splice(index, 2); return; } } - + this.batchs.splice(index, 1); if(batchToRemove instanceof PIXI.WebGLBatch)PIXI.WebGLRenderer.returnBatch(batchToRemove); } } + /** * Initializes a tiling sprite * @@ -808,26 +807,26 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) var gl = this.gl; // make the texture tilable.. - + sprite.verticies = new Float32Array([0, 0, sprite.width, 0, sprite.width, sprite.height, 0, sprite.height]); - + sprite.uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]); - + sprite.colors = new Float32Array([1,1,1,1]); - + sprite.indices = new Uint16Array([0, 1, 3,2])//, 2]); - + sprite._vertexBuffer = gl.createBuffer(); sprite._indexBuffer = gl.createBuffer(); sprite._uvBuffer = gl.createBuffer(); sprite._colorBuffer = gl.createBuffer(); - + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, sprite.verticies, gl.STATIC_DRAW); @@ -839,7 +838,7 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sprite._indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sprite.indices, gl.STATIC_DRAW); - + // return ( (x > 0) && ((x & (x - 1)) == 0) ); if(sprite.texture.baseTexture._glTexture) @@ -866,23 +865,19 @@ PIXI.WebGLRenderGroup.prototype.initTilingSprite = function(sprite) PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) { var gl = this.gl; - var shaderProgram = PIXI.shaderProgram; -// mat - //var mat4Real = PIXI.mat3.toMat4(strip.worldTransform); - //PIXI.mat4.transpose(mat4Real); - //PIXI.mat4.multiply(projectionMatrix, mat4Real, mat4Real ) - - - gl.useProgram(PIXI.stripShaderProgram); + var shaderProgram = PIXI.stripShaderProgram; + + + gl.useProgram(shaderProgram); var m = PIXI.mat3.clone(strip.worldTransform); - + PIXI.mat3.transpose(m); - - // set the matrix transform for the - gl.uniformMatrix3fv(PIXI.stripShaderProgram.translationMatrix, false, m); - gl.uniform2f(PIXI.stripShaderProgram.projectionVector, projection.x, projection.y); - gl.uniform1f(PIXI.stripShaderProgram.alpha, strip.worldAlpha); + + // set the matrix transform for the + gl.uniformMatrix3fv(shaderProgram.translationMatrix, false, m); + gl.uniform2f(shaderProgram.projectionVector, projection.x, projection.y); + gl.uniform1f(shaderProgram.alpha, strip.worldAlpha); /* if(strip.blendMode == PIXI.blendModes.NORMAL) @@ -894,25 +889,25 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); } */ - - + + if(!strip.dirty) { - + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); gl.bufferSubData(gl.ARRAY_BUFFER, 0, strip.verticies) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); - + // update the uvs gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); - + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - + // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); } @@ -922,29 +917,28 @@ PIXI.WebGLRenderGroup.prototype.renderStrip = function(strip, projection) gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.STATIC_DRAW) gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0); - + // update the uvs gl.bindBuffer(gl.ARRAY_BUFFER, strip._uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, strip.uvs, gl.STATIC_DRAW) gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); - + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, strip.texture.baseTexture._glTexture); - + gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW) gl.vertexAttribPointer(shaderProgram.colorAttribute, 1, gl.FLOAT, false, 0, 0); - + // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); - + } - //console.log(gl.TRIANGLE_STRIP); - + gl.drawElements(gl.TRIANGLE_STRIP, strip.indices.length, gl.UNSIGNED_SHORT, 0); - - gl.useProgram(PIXI.shaderProgram); + + gl.useProgram(PIXI.currentProgram); } /** @@ -959,31 +953,31 @@ PIXI.WebGLRenderGroup.prototype.renderTilingSprite = function(sprite, projection { var gl = this.gl; var shaderProgram = PIXI.shaderProgram; - + var tilePosition = sprite.tilePosition; var tileScale = sprite.tileScale; - + var offsetX = tilePosition.x/sprite.texture.baseTexture.width; var offsetY = tilePosition.y/sprite.texture.baseTexture.height; - + var scaleX = (sprite.width / sprite.texture.baseTexture.width) / tileScale.x; var scaleY = (sprite.height / sprite.texture.baseTexture.height) / tileScale.y; sprite.uvs[0] = 0 - offsetX; sprite.uvs[1] = 0 - offsetY; - + sprite.uvs[2] = (1 * scaleX) -offsetX; sprite.uvs[3] = 0 - offsetY; - + sprite.uvs[4] = (1 *scaleX) - offsetX; sprite.uvs[5] = (1 *scaleY) - offsetY; - + sprite.uvs[6] = 0 - offsetX; sprite.uvs[7] = (1 *scaleY) - offsetY; - + gl.bindBuffer(gl.ARRAY_BUFFER, sprite._uvBuffer); gl.bufferSubData(gl.ARRAY_BUFFER, 0, sprite.uvs) - + this.renderStrip(sprite, projectionMatrix); } @@ -999,12 +993,12 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) // build the strip! var gl = this.gl; var shaderProgram = this.shaderProgram; - + strip._vertexBuffer = gl.createBuffer(); strip._indexBuffer = gl.createBuffer(); strip._uvBuffer = gl.createBuffer(); strip._colorBuffer = gl.createBuffer(); - + gl.bindBuffer(gl.ARRAY_BUFFER, strip._vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, strip.verticies, gl.DYNAMIC_DRAW); @@ -1014,7 +1008,8 @@ PIXI.WebGLRenderGroup.prototype.initStrip = function(strip) gl.bindBuffer(gl.ARRAY_BUFFER, strip._colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, strip.colors, gl.STATIC_DRAW); - + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, strip._indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, strip.indices, gl.STATIC_DRAW); } + diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index ad88e5b..84b5c89 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -21,7 +21,7 @@ PIXI.gl; * @param view {Canvas} the canvas to use as a view, optional * @param transparent=false {Boolean} the transparency of the render view, default false * @param antialias=false {Boolean} sets antialias (only applicable in chrome at the moment) - * + * */ PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) { @@ -32,36 +32,37 @@ PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) this.width = width || 800; this.height = height || 600; - this.view = view || document.createElement( 'canvas' ); + this.view = view || document.createElement( 'canvas' ); this.view.width = this.width; this.view.height = this.height; - // deal with losing context.. + // deal with losing context.. var scope = this; this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false) this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false) this.batchs = []; - try + try { - PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { + PIXI.gl = this.gl = this.view.getContext("experimental-webgl", { alpha: this.transparent, antialias:!!antialias, // SPEED UP?? premultipliedAlpha:false, stencil:true }); - } - catch (e) + } + catch (e) { throw new Error(" This browser does not support webGL. Try using the canvas renderer" + this); } - PIXI.initPrimitiveShader(); PIXI.initDefaultShader(); + PIXI.initPrimitiveShader(); PIXI.initDefaultStripShader(); - PIXI.activateDefaultShader(); + +// PIXI.activateDefaultShader(); var gl = this.gl; PIXI.WebGLRenderer.gl = gl; @@ -71,14 +72,17 @@ PIXI.WebGLRenderer = function(width, height, view, transparent, antialias) gl.disable(gl.CULL_FACE); gl.enable(gl.BLEND); - gl.colorMask(true, true, true, this.transparent); + gl.colorMask(true, true, true, this.transparent); PIXI.projection = new PIXI.Point(400, 300); this.resize(this.width, this.height); this.contextLost = false; + PIXI.activateShader(PIXI.defaultShader); + this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl); + } // constructor @@ -90,7 +94,7 @@ PIXI.WebGLRenderer.prototype.constructor = PIXI.WebGLRenderer; * @static * @method getBatch * @return {WebGLBatch} - * @private + * @private */ PIXI.WebGLRenderer.getBatch = function() { @@ -114,7 +118,7 @@ PIXI.WebGLRenderer.getBatch = function() */ PIXI.WebGLRenderer.returnBatch = function(batch) { - batch.clean(); + batch.clean(); PIXI._batchs.push(batch); } @@ -127,8 +131,8 @@ PIXI.WebGLRenderer.returnBatch = function(batch) PIXI.WebGLRenderer.prototype.render = function(stage) { if(this.contextLost)return; - - + + // if rendering a new stage clear the batchs.. if(this.__stage !== stage) { @@ -137,8 +141,8 @@ PIXI.WebGLRenderer.prototype.render = function(stage) this.__stage = stage; this.stageRenderGroup.setRenderable(stage); } - - // TODO not needed now... + + // TODO not needed now... // update children if need be // best to remove first! /*for (var i=0; i < stage.__childrenRemoved.length; i++) @@ -147,29 +151,29 @@ PIXI.WebGLRenderer.prototype.render = function(stage) if(group)group.removeDisplayObject(stage.__childrenRemoved[i]); }*/ - // update any textures + // update any textures PIXI.WebGLRenderer.updateTextures(); - - // update the scene graph + + // update the scene graph PIXI.visibleCount++; stage.updateTransform(); - + var gl = this.gl; - + // -- Does this need to be set every frame? -- // - gl.colorMask(true, true, true, this.transparent); - gl.viewport(0, 0, this.width, this.height); - + gl.colorMask(true, true, true, this.transparent); + gl.viewport(0, 0, this.width, this.height); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); + + gl.clearColor(stage.backgroundColorSplit[0],stage.backgroundColorSplit[1],stage.backgroundColorSplit[2], !this.transparent); gl.clear(gl.COLOR_BUFFER_BIT); // HACK TO TEST - + this.stageRenderGroup.backgroundColor = stage.backgroundColorSplit; this.stageRenderGroup.render(PIXI.projection); - + // interaction // run interaction! if(stage.interactive) @@ -181,15 +185,15 @@ PIXI.WebGLRenderer.prototype.render = function(stage) stage.interactionManager.setTarget(this); } } - + // after rendering lets confirm all frames that have been uodated.. if(PIXI.Texture.frameUpdates.length > 0) { - for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) + for (var i=0; i < PIXI.Texture.frameUpdates.length; i++) { PIXI.Texture.frameUpdates[i].updateFrame = false; }; - + PIXI.Texture.frameUpdates = []; } } @@ -222,7 +226,7 @@ PIXI.WebGLRenderer.updateTexture = function(texture) { //TODO break this out into a texture manager... var gl = PIXI.gl; - + if(!texture._glTexture) { texture._glTexture = gl.createTexture(); @@ -288,7 +292,7 @@ PIXI.WebGLRenderer.prototype.resize = function(width, height) this.view.width = width; this.view.height = height; - this.gl.viewport(0, 0, this.width, this.height); + this.gl.viewport(0, 0, this.width, this.height); //var projectionMatrix = this.projectionMatrix; @@ -323,20 +327,20 @@ PIXI.WebGLRenderer.prototype.handleContextLost = function(event) */ PIXI.WebGLRenderer.prototype.handleContextRestored = function(event) { - this.gl = this.view.getContext("experimental-webgl", { + this.gl = this.view.getContext("experimental-webgl", { alpha: true }); - this.initShaders(); + this.initShaders(); - for(var key in PIXI.TextureCache) + for(var key in PIXI.TextureCache) { var texture = PIXI.TextureCache[key].baseTexture; texture._glTexture = null; PIXI.WebGLRenderer.updateTexture(texture); }; - for (var i=0; i < this.batchs.length; i++) + for (var i=0; i < this.batchs.length; i++) { this.batchs[i].restoreLostContext(this.gl)// this.batchs[i].dirty = true; diff --git a/src/pixi/renderers/webgl/WebGLShaders.js b/src/pixi/renderers/webgl/WebGLShaders.js index 93cf578..4f3724d 100644 --- a/src/pixi/renderers/webgl/WebGLShaders.js +++ b/src/pixi/renderers/webgl/WebGLShaders.js @@ -1,4 +1,3 @@ - /** * @author Mat Groves http://matgroves.com/ @Doormat23 */ @@ -23,13 +22,11 @@ PIXI.shaderVertexSrc = [ "attribute vec2 aVertexPosition;", "attribute vec2 aTextureCoord;", "attribute float aColor;", - //"uniform mat4 uMVMatrix;", - + "uniform vec2 projectionVector;", "varying vec2 vTextureCoord;", "varying float vColor;", "void main(void) {", - // "gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0, 1.0);", "gl_Position = vec4( aVertexPosition.x / projectionVector.x -1.0, aVertexPosition.y / -projectionVector.y + 1.0 , 0.0, 1.0);", "vTextureCoord = aTextureCoord;", "vColor = aColor;", @@ -69,7 +66,6 @@ PIXI.stripShaderVertexSrc = [ "}" ]; - /* * primitive shader.. */ @@ -96,48 +92,49 @@ PIXI.primitiveShaderVertexSrc = [ "}" ]; -PIXI.initPrimitiveShader = function() +PIXI.shaderStack = []; + +PIXI.initPrimitiveShader = function() { var gl = PIXI.gl; var shaderProgram = PIXI.compileProgram(PIXI.primitiveShaderVertexSrc, PIXI.primitiveShaderFragmentSrc) - + gl.useProgram(shaderProgram); shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - + shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); shaderProgram.translationMatrix = gl.getUniformLocation(shaderProgram, "translationMatrix"); - + + + //gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(shaderProgram.colorAttribute); +//gl.enableVertexAttribArray(program.textureCoordAttribute); + shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); PIXI.primitiveProgram = shaderProgram; + + } -PIXI.initDefaultShader = function() +PIXI.initDefaultShader = function() { - var gl = this.gl; - var shaderProgram = PIXI.compileProgram(PIXI.shaderVertexSrc, PIXI.shaderFragmentSrc) - - gl.useProgram(shaderProgram); - - shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); - shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - - // shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - - PIXI.shaderProgram = shaderProgram; + PIXI.defaultShader = new PIXI.PixiShader(); + PIXI.defaultShader.init(); + PIXI.activateShader(PIXI.defaultShader); + /* + PIXI.shaderStack.push(PIXI.defaultShader); + PIXI.current*/ } -PIXI.initDefaultStripShader = function() +PIXI.initDefaultStripShader = function() { var gl = this.gl; var shaderProgram = PIXI.compileProgram(PIXI.stripShaderVertexSrc, PIXI.stripShaderFragmentSrc) - + gl.useProgram(shaderProgram); shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); @@ -147,11 +144,9 @@ PIXI.initDefaultStripShader = function() shaderProgram.alpha = gl.getUniformLocation(shaderProgram, "alpha"); shaderProgram.colorAttribute = gl.getAttribLocation(shaderProgram, "aColor"); - shaderProgram.projectionVector = gl.getUniformLocation(shaderProgram, "projectionVector"); - shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); - + PIXI.stripShaderProgram = shaderProgram; } @@ -186,9 +181,9 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) var gl = PIXI.gl; var fragmentShader = PIXI.CompileFragmentShader(gl, fragmentSrc); var vertexShader = PIXI.CompileVertexShader(gl, vertexSrc); - + var shaderProgram = gl.createProgram(); - + gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); @@ -198,34 +193,64 @@ PIXI.compileProgram = function(vertexSrc, fragmentSrc) } return shaderProgram; +} + +PIXI.activateShader = function(shader) +{ + PIXI.shaderStack.push(shader); + + //console.log(">>>") + var gl = PIXI.gl; + + var shaderProgram = shader.program; + + // map uniforms.. + gl.useProgram(shaderProgram); + + gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + gl.enableVertexAttribArray(shaderProgram.colorAttribute); + gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); + + shader.syncUniforms(); + + PIXI.currentShader = shaderProgram; } -PIXI.activateDefaultShader = function() +PIXI.popShader = function() { var gl = PIXI.gl; - var shaderProgram = PIXI.shaderProgram; - + // activate last program.. + var lastProgram = PIXI.shaderStack.pop(); + + var shaderProgram = PIXI.shaderStack[ PIXI.shaderStack.length-1 ].program; + gl.useProgram(shaderProgram); - - - gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); - gl.enableVertexAttribArray(shaderProgram.colorAttribute); + + PIXI.currentShader = shaderProgram; } - - PIXI.activatePrimitiveShader = function() { var gl = PIXI.gl; - - gl.disableVertexAttribArray(PIXI.shaderProgram.textureCoordAttribute); - gl.disableVertexAttribArray(PIXI.shaderProgram.colorAttribute); - + gl.useProgram(PIXI.primitiveProgram); + + //gl.disableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.disableVertexAttribArray(PIXI.currentShader.colorAttribute); + gl.disableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + + //gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); +} - gl.enableVertexAttribArray(PIXI.primitiveProgram.vertexPositionAttribute); - gl.enableVertexAttribArray(PIXI.primitiveProgram.colorAttribute); -} +PIXI.deactivatePrimitiveShader = function() +{ + var gl = PIXI.gl; + gl.useProgram(PIXI.currentShader); + + gl.enableVertexAttribArray(PIXI.currentShader.textureCoordAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.vertexPositionAttribute); + //gl.enableVertexAttribArray(PIXI.currentShader.colorAttribute); +} \ No newline at end of file diff --git a/src/pixi/textures/RenderTexture.js b/src/pixi/textures/RenderTexture.js index d584420..738c1d7 100644 --- a/src/pixi/textures/RenderTexture.js +++ b/src/pixi/textures/RenderTexture.js @@ -5,11 +5,11 @@ /** A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it. - __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. - Otherwise black rectangles will be drawn instead. - + __Hint__: All DisplayObjects (exmpl. Sprites) that renders on RenderTexture should be preloaded. + Otherwise black rectangles will be drawn instead. + RenderTexture takes snapshot of DisplayObject passed to render method. If DisplayObject is passed to render method, position and rotation of it will be ignored. For example: - + var renderTexture = new PIXI.RenderTexture(800, 600); var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); sprite.position.x = 800/2; @@ -37,9 +37,9 @@ PIXI.RenderTexture = function(width, height) this.width = width || 100; this.height = height || 100; - this.identityMatrix = PIXI.mat3.create(); + this.indetityMatrix = PIXI.mat3.create(); - this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); + this.frame = new PIXI.Rectangle(0, 0, this.width, this.height); if(PIXI.gl) { @@ -68,7 +68,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); this.glFramebuffer.width = this.width; - this.glFramebuffer.height = this.height; + this.glFramebuffer.height = this.height; this.baseTexture = new PIXI.BaseTexture(); @@ -96,7 +96,7 @@ PIXI.RenderTexture.prototype.initWebGL = function() // set the correct render function.. this.render = this.renderWebGL; - + } @@ -105,19 +105,19 @@ PIXI.RenderTexture.prototype.resize = function(width, height) this.width = width; this.height = height; - + if(PIXI.gl) { this.projection.x = this.width/2 this.projection.y = this.height/2; - + var gl = PIXI.gl; gl.bindTexture(gl.TEXTURE_2D, this.baseTexture._glTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); } else { - + this.frame.width = this.width this.frame.height = this.height; this.renderer.resize(this.width, this.height); @@ -153,15 +153,15 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle var gl = PIXI.gl; // enable the alpha color mask.. - gl.colorMask(true, true, true, true); + gl.colorMask(true, true, true, true); - gl.viewport(0, 0, this.width, this.height); + gl.viewport(0, 0, this.width, this.height); gl.bindFramebuffer(gl.FRAMEBUFFER, this.glFramebuffer ); if(clear) { - gl.clearColor(0,0,0, 0); + gl.clearColor(0,0,0, 0); gl.clear(gl.COLOR_BUFFER_BIT); } @@ -170,24 +170,24 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle //TODO -? create a new one??? dont think so! var originalWorldTransform = displayObject.worldTransform; - displayObject.worldTransform = PIXI.mat3.create();//sthis.identityMatrix; + displayObject.worldTransform = PIXI.mat3.create();//sthis.indetityMatrix; // modify to flip... displayObject.worldTransform[4] = -1; displayObject.worldTransform[5] = this.projection.y * 2; - + if(position) { displayObject.worldTransform[2] = position.x; displayObject.worldTransform[5] -= position.y; } - + PIXI.visibleCount++; displayObject.vcount = PIXI.visibleCount; - + for(var i=0,j=children.length; i