diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/src/pixi/loaders/SpriteSheetLoader.js b/src/pixi/loaders/SpriteSheetLoader.js index e9844ce..4f4c802 100644 --- a/src/pixi/loaders/SpriteSheetLoader.js +++ b/src/pixi/loaders/SpriteSheetLoader.js @@ -80,47 +80,9 @@ 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 () { 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(); + jsonLoader.load(); }; /** diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/src/pixi/loaders/SpriteSheetLoader.js b/src/pixi/loaders/SpriteSheetLoader.js index e9844ce..4f4c802 100644 --- a/src/pixi/loaders/SpriteSheetLoader.js +++ b/src/pixi/loaders/SpriteSheetLoader.js @@ -80,47 +80,9 @@ 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 () { 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(); + jsonLoader.load(); }; /** diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index 8fddeab..f336e8f 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -67,21 +67,44 @@ this._webGL = []; this.isMask = false; + + this.bounds = null; + + this.boundsPadding = 10; }; // constructor PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Graphics.prototype.constructor = PIXI.Graphics; -/* -* Not yet implemented -*/ +/** + * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite. + * This is useful if your graphics element does not change often as it will speed up the rendering of the object + * It is also usful as the graphics object will always be aliased because it will be rendered using canvas + * Not recommended if you are conastanly redrawing the graphics element. + * + * @property cacheAsBitmap + * @default false + * @type Boolean + * @private + */ Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { get: function() { return this._cacheAsBitmap; }, set: function(value) { this._cacheAsBitmap = value; + + if(this._cacheAsBitmap) + { + this._generateCachedSprite(); + } + else + { + this.destroyCachedSprite(); + this.dirty = true; + } + } }); @@ -249,34 +272,72 @@ this.bounds = null; //new PIXI.Rectangle(); }; +/** + * Useful function that returns a texture of the graphics object that can then be used to create sprites + * This can be quite useful if your geometry is complicated and needs to be reused multiple times. + * + * @method generateTexture + * @return {Texture} a texture of the graphics object + */ +PIXI.Graphics.prototype.generateTexture = function() +{ + var bounds = this.getBounds(); + + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + canvasBuffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + return texture; +}; PIXI.Graphics.prototype._renderWebGL = function(renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element if(this.visible === false || this.alpha === 0 || this.isMask === true)return; - - renderSession.spriteBatch.stop(); - - if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - - // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + if(this._cacheAsBitmap) { - this.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; - this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - - if(this._filters)renderSession.filterManager.popFilter(); - if(this._mask)renderSession.maskManager.popMask(renderSession); - - renderSession.drawCount++; + + if(this.dirty) + { + this._generateCachedSprite(); + // we will also need to update the texture on the gpu too! + PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl); + + this.dirty = false; + } - renderSession.spriteBatch.start(); + PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderSession.spriteBatch.stop(); + + if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); + if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); + + // check blend mode + if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + { + this.spriteBatch.currentBlendMode = this.blendMode; + var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + if(this._filters)renderSession.filterManager.popFilter(); + if(this._mask)renderSession.maskManager.popMask(renderSession); + + renderSession.drawCount++; + + renderSession.spriteBatch.start(); + } }; PIXI.Graphics.prototype._renderCanvas = function(renderSession) @@ -425,9 +486,50 @@ } } - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + var padding = this.boundsPadding; + this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2); }; +PIXI.Graphics.prototype._generateCachedSprite = function() +{ + var bounds = this.getBounds(); + + if(!this._cachedSprite) + { + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new PIXI.Sprite(texture); + this._cachedSprite.buffer = canvasBuffer; + + this._cachedSprite.worldTransform = this.worldTransform; + } + else + { + this._cachedSprite.buffer.resize(bounds.width, bounds.height); + } + + // leverage the anchor to account for the offest of the element + this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); + this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); + + // this._cachedSprite.buffer.context.save(); + this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + // this._cachedSprite.buffer.context.restore(); +}; + +PIXI.Graphics.prototype.destroyCachedSprite = function() +{ + this._cachedSprite.texture.destroy(true); + + // let the gc collect the unused sprite + // TODO could be object pooled! + this._cachedSprite = null; +}; + + // SOME TYPES: PIXI.Graphics.POLY = 0; PIXI.Graphics.RECT = 1; diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/src/pixi/loaders/SpriteSheetLoader.js b/src/pixi/loaders/SpriteSheetLoader.js index e9844ce..4f4c802 100644 --- a/src/pixi/loaders/SpriteSheetLoader.js +++ b/src/pixi/loaders/SpriteSheetLoader.js @@ -80,47 +80,9 @@ 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 () { 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(); + jsonLoader.load(); }; /** diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index 8fddeab..f336e8f 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -67,21 +67,44 @@ this._webGL = []; this.isMask = false; + + this.bounds = null; + + this.boundsPadding = 10; }; // constructor PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Graphics.prototype.constructor = PIXI.Graphics; -/* -* Not yet implemented -*/ +/** + * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite. + * This is useful if your graphics element does not change often as it will speed up the rendering of the object + * It is also usful as the graphics object will always be aliased because it will be rendered using canvas + * Not recommended if you are conastanly redrawing the graphics element. + * + * @property cacheAsBitmap + * @default false + * @type Boolean + * @private + */ Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { get: function() { return this._cacheAsBitmap; }, set: function(value) { this._cacheAsBitmap = value; + + if(this._cacheAsBitmap) + { + this._generateCachedSprite(); + } + else + { + this.destroyCachedSprite(); + this.dirty = true; + } + } }); @@ -249,34 +272,72 @@ this.bounds = null; //new PIXI.Rectangle(); }; +/** + * Useful function that returns a texture of the graphics object that can then be used to create sprites + * This can be quite useful if your geometry is complicated and needs to be reused multiple times. + * + * @method generateTexture + * @return {Texture} a texture of the graphics object + */ +PIXI.Graphics.prototype.generateTexture = function() +{ + var bounds = this.getBounds(); + + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + canvasBuffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + return texture; +}; PIXI.Graphics.prototype._renderWebGL = function(renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element if(this.visible === false || this.alpha === 0 || this.isMask === true)return; - - renderSession.spriteBatch.stop(); - - if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - - // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + if(this._cacheAsBitmap) { - this.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; - this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - - if(this._filters)renderSession.filterManager.popFilter(); - if(this._mask)renderSession.maskManager.popMask(renderSession); - - renderSession.drawCount++; + + if(this.dirty) + { + this._generateCachedSprite(); + // we will also need to update the texture on the gpu too! + PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl); + + this.dirty = false; + } - renderSession.spriteBatch.start(); + PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderSession.spriteBatch.stop(); + + if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); + if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); + + // check blend mode + if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + { + this.spriteBatch.currentBlendMode = this.blendMode; + var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + if(this._filters)renderSession.filterManager.popFilter(); + if(this._mask)renderSession.maskManager.popMask(renderSession); + + renderSession.drawCount++; + + renderSession.spriteBatch.start(); + } }; PIXI.Graphics.prototype._renderCanvas = function(renderSession) @@ -425,9 +486,50 @@ } } - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + var padding = this.boundsPadding; + this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2); }; +PIXI.Graphics.prototype._generateCachedSprite = function() +{ + var bounds = this.getBounds(); + + if(!this._cachedSprite) + { + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new PIXI.Sprite(texture); + this._cachedSprite.buffer = canvasBuffer; + + this._cachedSprite.worldTransform = this.worldTransform; + } + else + { + this._cachedSprite.buffer.resize(bounds.width, bounds.height); + } + + // leverage the anchor to account for the offest of the element + this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); + this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); + + // this._cachedSprite.buffer.context.save(); + this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + // this._cachedSprite.buffer.context.restore(); +}; + +PIXI.Graphics.prototype.destroyCachedSprite = function() +{ + this._cachedSprite.texture.destroy(true); + + // let the gc collect the unused sprite + // TODO could be object pooled! + this._cachedSprite = null; +}; + + // SOME TYPES: PIXI.Graphics.POLY = 0; PIXI.Graphics.RECT = 1; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index d98e6fd..867b7f9 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -120,8 +120,8 @@ //stage.__childrenRemoved = []; // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; PIXI.visibleCount++; stage.updateTransform(); @@ -149,7 +149,7 @@ // remove frame updates.. if(PIXI.Texture.frameUpdates.length > 0) { - PIXI.Texture.frameUpdates = []; + PIXI.Texture.frameUpdates.length = 0; } }; diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/src/pixi/loaders/SpriteSheetLoader.js b/src/pixi/loaders/SpriteSheetLoader.js index e9844ce..4f4c802 100644 --- a/src/pixi/loaders/SpriteSheetLoader.js +++ b/src/pixi/loaders/SpriteSheetLoader.js @@ -80,47 +80,9 @@ 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 () { 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(); + jsonLoader.load(); }; /** diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index 8fddeab..f336e8f 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -67,21 +67,44 @@ this._webGL = []; this.isMask = false; + + this.bounds = null; + + this.boundsPadding = 10; }; // constructor PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Graphics.prototype.constructor = PIXI.Graphics; -/* -* Not yet implemented -*/ +/** + * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite. + * This is useful if your graphics element does not change often as it will speed up the rendering of the object + * It is also usful as the graphics object will always be aliased because it will be rendered using canvas + * Not recommended if you are conastanly redrawing the graphics element. + * + * @property cacheAsBitmap + * @default false + * @type Boolean + * @private + */ Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { get: function() { return this._cacheAsBitmap; }, set: function(value) { this._cacheAsBitmap = value; + + if(this._cacheAsBitmap) + { + this._generateCachedSprite(); + } + else + { + this.destroyCachedSprite(); + this.dirty = true; + } + } }); @@ -249,34 +272,72 @@ this.bounds = null; //new PIXI.Rectangle(); }; +/** + * Useful function that returns a texture of the graphics object that can then be used to create sprites + * This can be quite useful if your geometry is complicated and needs to be reused multiple times. + * + * @method generateTexture + * @return {Texture} a texture of the graphics object + */ +PIXI.Graphics.prototype.generateTexture = function() +{ + var bounds = this.getBounds(); + + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + canvasBuffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + return texture; +}; PIXI.Graphics.prototype._renderWebGL = function(renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element if(this.visible === false || this.alpha === 0 || this.isMask === true)return; - - renderSession.spriteBatch.stop(); - - if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - - // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + if(this._cacheAsBitmap) { - this.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; - this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - - if(this._filters)renderSession.filterManager.popFilter(); - if(this._mask)renderSession.maskManager.popMask(renderSession); - - renderSession.drawCount++; + + if(this.dirty) + { + this._generateCachedSprite(); + // we will also need to update the texture on the gpu too! + PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl); + + this.dirty = false; + } - renderSession.spriteBatch.start(); + PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderSession.spriteBatch.stop(); + + if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); + if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); + + // check blend mode + if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + { + this.spriteBatch.currentBlendMode = this.blendMode; + var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + if(this._filters)renderSession.filterManager.popFilter(); + if(this._mask)renderSession.maskManager.popMask(renderSession); + + renderSession.drawCount++; + + renderSession.spriteBatch.start(); + } }; PIXI.Graphics.prototype._renderCanvas = function(renderSession) @@ -425,9 +486,50 @@ } } - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + var padding = this.boundsPadding; + this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2); }; +PIXI.Graphics.prototype._generateCachedSprite = function() +{ + var bounds = this.getBounds(); + + if(!this._cachedSprite) + { + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new PIXI.Sprite(texture); + this._cachedSprite.buffer = canvasBuffer; + + this._cachedSprite.worldTransform = this.worldTransform; + } + else + { + this._cachedSprite.buffer.resize(bounds.width, bounds.height); + } + + // leverage the anchor to account for the offest of the element + this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); + this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); + + // this._cachedSprite.buffer.context.save(); + this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + // this._cachedSprite.buffer.context.restore(); +}; + +PIXI.Graphics.prototype.destroyCachedSprite = function() +{ + this._cachedSprite.texture.destroy(true); + + // let the gc collect the unused sprite + // TODO could be object pooled! + this._cachedSprite = null; +}; + + // SOME TYPES: PIXI.Graphics.POLY = 0; PIXI.Graphics.RECT = 1; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index d98e6fd..867b7f9 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -120,8 +120,8 @@ //stage.__childrenRemoved = []; // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; PIXI.visibleCount++; stage.updateTransform(); @@ -149,7 +149,7 @@ // remove frame updates.. if(PIXI.Texture.frameUpdates.length > 0) { - PIXI.Texture.frameUpdates = []; + PIXI.Texture.frameUpdates.length = 0; } }; diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 58210ea..2cb7f99 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -2,13 +2,7 @@ * @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 = null; - - +PIXI.glContexts = []; // this is where we store the webGL contexts for easy access. /** * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer @@ -46,8 +40,6 @@ this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false); this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false); - this.batchs = []; - this.options = { alpha: this.transparent, antialias:!!antialias, // SPEED UP?? @@ -71,6 +63,8 @@ var gl = this.gl; this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + PIXI.glContexts[this.glContextId] = gl; + if(!PIXI.blendModesWebGL) { PIXI.blendModesWebGL = []; @@ -111,8 +105,6 @@ gl.useProgram(this.shaderManager.defaultShader.program); - PIXI.WebGLRenderer.gl = gl; - gl.disable(gl.DEPTH_TEST); gl.disable(gl.CULL_FACE); @@ -242,59 +234,12 @@ for (i = 0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; - PIXI.Texture.frameUpdates = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; + PIXI.Texture.frameUpdates.length = 0; }; /** - * 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 = this.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, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - - // 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 @@ -304,13 +249,19 @@ PIXI.WebGLRenderer.destroyTexture = function(texture) { //TODO break this out into a texture manager... - var gl = PIXI.gl; - if(texture._glTexture) + for (var i = texture._glTextures.length - 1; i >= 0; i--) { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + var glTexture = texture._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } } + + texture._glTextures.length = 0; }; PIXI.WebGLRenderer.updateTextureFrame = function(texture) @@ -373,6 +324,8 @@ gl.bindTexture(gl.TEXTURE_2D, null); } + + return texture._glTextures[gl.id]; }; PIXI.updateWebGLTexture = function(texture, gl) diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/src/pixi/loaders/SpriteSheetLoader.js b/src/pixi/loaders/SpriteSheetLoader.js index e9844ce..4f4c802 100644 --- a/src/pixi/loaders/SpriteSheetLoader.js +++ b/src/pixi/loaders/SpriteSheetLoader.js @@ -80,47 +80,9 @@ 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 () { 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(); + jsonLoader.load(); }; /** diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index 8fddeab..f336e8f 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -67,21 +67,44 @@ this._webGL = []; this.isMask = false; + + this.bounds = null; + + this.boundsPadding = 10; }; // constructor PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Graphics.prototype.constructor = PIXI.Graphics; -/* -* Not yet implemented -*/ +/** + * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite. + * This is useful if your graphics element does not change often as it will speed up the rendering of the object + * It is also usful as the graphics object will always be aliased because it will be rendered using canvas + * Not recommended if you are conastanly redrawing the graphics element. + * + * @property cacheAsBitmap + * @default false + * @type Boolean + * @private + */ Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { get: function() { return this._cacheAsBitmap; }, set: function(value) { this._cacheAsBitmap = value; + + if(this._cacheAsBitmap) + { + this._generateCachedSprite(); + } + else + { + this.destroyCachedSprite(); + this.dirty = true; + } + } }); @@ -249,34 +272,72 @@ this.bounds = null; //new PIXI.Rectangle(); }; +/** + * Useful function that returns a texture of the graphics object that can then be used to create sprites + * This can be quite useful if your geometry is complicated and needs to be reused multiple times. + * + * @method generateTexture + * @return {Texture} a texture of the graphics object + */ +PIXI.Graphics.prototype.generateTexture = function() +{ + var bounds = this.getBounds(); + + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + canvasBuffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + return texture; +}; PIXI.Graphics.prototype._renderWebGL = function(renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element if(this.visible === false || this.alpha === 0 || this.isMask === true)return; - - renderSession.spriteBatch.stop(); - - if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - - // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + if(this._cacheAsBitmap) { - this.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; - this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - - if(this._filters)renderSession.filterManager.popFilter(); - if(this._mask)renderSession.maskManager.popMask(renderSession); - - renderSession.drawCount++; + + if(this.dirty) + { + this._generateCachedSprite(); + // we will also need to update the texture on the gpu too! + PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl); + + this.dirty = false; + } - renderSession.spriteBatch.start(); + PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderSession.spriteBatch.stop(); + + if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); + if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); + + // check blend mode + if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + { + this.spriteBatch.currentBlendMode = this.blendMode; + var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + if(this._filters)renderSession.filterManager.popFilter(); + if(this._mask)renderSession.maskManager.popMask(renderSession); + + renderSession.drawCount++; + + renderSession.spriteBatch.start(); + } }; PIXI.Graphics.prototype._renderCanvas = function(renderSession) @@ -425,9 +486,50 @@ } } - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + var padding = this.boundsPadding; + this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2); }; +PIXI.Graphics.prototype._generateCachedSprite = function() +{ + var bounds = this.getBounds(); + + if(!this._cachedSprite) + { + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new PIXI.Sprite(texture); + this._cachedSprite.buffer = canvasBuffer; + + this._cachedSprite.worldTransform = this.worldTransform; + } + else + { + this._cachedSprite.buffer.resize(bounds.width, bounds.height); + } + + // leverage the anchor to account for the offest of the element + this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); + this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); + + // this._cachedSprite.buffer.context.save(); + this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + // this._cachedSprite.buffer.context.restore(); +}; + +PIXI.Graphics.prototype.destroyCachedSprite = function() +{ + this._cachedSprite.texture.destroy(true); + + // let the gc collect the unused sprite + // TODO could be object pooled! + this._cachedSprite = null; +}; + + // SOME TYPES: PIXI.Graphics.POLY = 0; PIXI.Graphics.RECT = 1; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index d98e6fd..867b7f9 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -120,8 +120,8 @@ //stage.__childrenRemoved = []; // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; PIXI.visibleCount++; stage.updateTransform(); @@ -149,7 +149,7 @@ // remove frame updates.. if(PIXI.Texture.frameUpdates.length > 0) { - PIXI.Texture.frameUpdates = []; + PIXI.Texture.frameUpdates.length = 0; } }; diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 58210ea..2cb7f99 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -2,13 +2,7 @@ * @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 = null; - - +PIXI.glContexts = []; // this is where we store the webGL contexts for easy access. /** * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer @@ -46,8 +40,6 @@ this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false); this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false); - this.batchs = []; - this.options = { alpha: this.transparent, antialias:!!antialias, // SPEED UP?? @@ -71,6 +63,8 @@ var gl = this.gl; this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + PIXI.glContexts[this.glContextId] = gl; + if(!PIXI.blendModesWebGL) { PIXI.blendModesWebGL = []; @@ -111,8 +105,6 @@ gl.useProgram(this.shaderManager.defaultShader.program); - PIXI.WebGLRenderer.gl = gl; - gl.disable(gl.DEPTH_TEST); gl.disable(gl.CULL_FACE); @@ -242,59 +234,12 @@ for (i = 0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; - PIXI.Texture.frameUpdates = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; + PIXI.Texture.frameUpdates.length = 0; }; /** - * 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 = this.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, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - - // 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 @@ -304,13 +249,19 @@ PIXI.WebGLRenderer.destroyTexture = function(texture) { //TODO break this out into a texture manager... - var gl = PIXI.gl; - if(texture._glTexture) + for (var i = texture._glTextures.length - 1; i >= 0; i--) { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + var glTexture = texture._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } } + + texture._glTextures.length = 0; }; PIXI.WebGLRenderer.updateTextureFrame = function(texture) @@ -373,6 +324,8 @@ gl.bindTexture(gl.TEXTURE_2D, null); } + + return texture._glTextures[gl.id]; }; PIXI.updateWebGLTexture = function(texture, gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index fff1223..72fd085 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -193,13 +193,18 @@ if(graphicsData.lineWidth) { + var tempPoints = graphicsData.points; + graphicsData.points = [x, y, x + width, y, x + width, y + height, x, y + height, x, y]; + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + + graphicsData.points = tempPoints; } }; @@ -260,6 +265,8 @@ if(graphicsData.lineWidth) { + var tempPoints = graphicsData.points; + graphicsData.points = []; for (i = 0; i < totalSegs + 1; i++) @@ -269,6 +276,8 @@ } PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + + graphicsData.points = tempPoints; } }; diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/src/pixi/loaders/SpriteSheetLoader.js b/src/pixi/loaders/SpriteSheetLoader.js index e9844ce..4f4c802 100644 --- a/src/pixi/loaders/SpriteSheetLoader.js +++ b/src/pixi/loaders/SpriteSheetLoader.js @@ -80,47 +80,9 @@ 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 () { 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(); + jsonLoader.load(); }; /** diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index 8fddeab..f336e8f 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -67,21 +67,44 @@ this._webGL = []; this.isMask = false; + + this.bounds = null; + + this.boundsPadding = 10; }; // constructor PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Graphics.prototype.constructor = PIXI.Graphics; -/* -* Not yet implemented -*/ +/** + * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite. + * This is useful if your graphics element does not change often as it will speed up the rendering of the object + * It is also usful as the graphics object will always be aliased because it will be rendered using canvas + * Not recommended if you are conastanly redrawing the graphics element. + * + * @property cacheAsBitmap + * @default false + * @type Boolean + * @private + */ Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { get: function() { return this._cacheAsBitmap; }, set: function(value) { this._cacheAsBitmap = value; + + if(this._cacheAsBitmap) + { + this._generateCachedSprite(); + } + else + { + this.destroyCachedSprite(); + this.dirty = true; + } + } }); @@ -249,34 +272,72 @@ this.bounds = null; //new PIXI.Rectangle(); }; +/** + * Useful function that returns a texture of the graphics object that can then be used to create sprites + * This can be quite useful if your geometry is complicated and needs to be reused multiple times. + * + * @method generateTexture + * @return {Texture} a texture of the graphics object + */ +PIXI.Graphics.prototype.generateTexture = function() +{ + var bounds = this.getBounds(); + + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + canvasBuffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + return texture; +}; PIXI.Graphics.prototype._renderWebGL = function(renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element if(this.visible === false || this.alpha === 0 || this.isMask === true)return; - - renderSession.spriteBatch.stop(); - - if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - - // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + if(this._cacheAsBitmap) { - this.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; - this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - - if(this._filters)renderSession.filterManager.popFilter(); - if(this._mask)renderSession.maskManager.popMask(renderSession); - - renderSession.drawCount++; + + if(this.dirty) + { + this._generateCachedSprite(); + // we will also need to update the texture on the gpu too! + PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl); + + this.dirty = false; + } - renderSession.spriteBatch.start(); + PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderSession.spriteBatch.stop(); + + if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); + if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); + + // check blend mode + if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + { + this.spriteBatch.currentBlendMode = this.blendMode; + var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + if(this._filters)renderSession.filterManager.popFilter(); + if(this._mask)renderSession.maskManager.popMask(renderSession); + + renderSession.drawCount++; + + renderSession.spriteBatch.start(); + } }; PIXI.Graphics.prototype._renderCanvas = function(renderSession) @@ -425,9 +486,50 @@ } } - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + var padding = this.boundsPadding; + this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2); }; +PIXI.Graphics.prototype._generateCachedSprite = function() +{ + var bounds = this.getBounds(); + + if(!this._cachedSprite) + { + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new PIXI.Sprite(texture); + this._cachedSprite.buffer = canvasBuffer; + + this._cachedSprite.worldTransform = this.worldTransform; + } + else + { + this._cachedSprite.buffer.resize(bounds.width, bounds.height); + } + + // leverage the anchor to account for the offest of the element + this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); + this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); + + // this._cachedSprite.buffer.context.save(); + this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + // this._cachedSprite.buffer.context.restore(); +}; + +PIXI.Graphics.prototype.destroyCachedSprite = function() +{ + this._cachedSprite.texture.destroy(true); + + // let the gc collect the unused sprite + // TODO could be object pooled! + this._cachedSprite = null; +}; + + // SOME TYPES: PIXI.Graphics.POLY = 0; PIXI.Graphics.RECT = 1; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index d98e6fd..867b7f9 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -120,8 +120,8 @@ //stage.__childrenRemoved = []; // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; PIXI.visibleCount++; stage.updateTransform(); @@ -149,7 +149,7 @@ // remove frame updates.. if(PIXI.Texture.frameUpdates.length > 0) { - PIXI.Texture.frameUpdates = []; + PIXI.Texture.frameUpdates.length = 0; } }; diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 58210ea..2cb7f99 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -2,13 +2,7 @@ * @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 = null; - - +PIXI.glContexts = []; // this is where we store the webGL contexts for easy access. /** * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer @@ -46,8 +40,6 @@ this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false); this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false); - this.batchs = []; - this.options = { alpha: this.transparent, antialias:!!antialias, // SPEED UP?? @@ -71,6 +63,8 @@ var gl = this.gl; this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + PIXI.glContexts[this.glContextId] = gl; + if(!PIXI.blendModesWebGL) { PIXI.blendModesWebGL = []; @@ -111,8 +105,6 @@ gl.useProgram(this.shaderManager.defaultShader.program); - PIXI.WebGLRenderer.gl = gl; - gl.disable(gl.DEPTH_TEST); gl.disable(gl.CULL_FACE); @@ -242,59 +234,12 @@ for (i = 0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; - PIXI.Texture.frameUpdates = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; + PIXI.Texture.frameUpdates.length = 0; }; /** - * 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 = this.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, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - - // 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 @@ -304,13 +249,19 @@ PIXI.WebGLRenderer.destroyTexture = function(texture) { //TODO break this out into a texture manager... - var gl = PIXI.gl; - if(texture._glTexture) + for (var i = texture._glTextures.length - 1; i >= 0; i--) { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + var glTexture = texture._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } } + + texture._glTextures.length = 0; }; PIXI.WebGLRenderer.updateTextureFrame = function(texture) @@ -373,6 +324,8 @@ gl.bindTexture(gl.TEXTURE_2D, null); } + + return texture._glTextures[gl.id]; }; PIXI.updateWebGLTexture = function(texture, gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index fff1223..72fd085 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -193,13 +193,18 @@ if(graphicsData.lineWidth) { + var tempPoints = graphicsData.points; + graphicsData.points = [x, y, x + width, y, x + width, y + height, x, y + height, x, y]; + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + + graphicsData.points = tempPoints; } }; @@ -260,6 +265,8 @@ if(graphicsData.lineWidth) { + var tempPoints = graphicsData.points; + graphicsData.points = []; for (i = 0; i < totalSegs + 1; i++) @@ -269,6 +276,8 @@ } PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + + graphicsData.points = tempPoints; } }; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index 93614cf..8e6f46c 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -29,7 +29,7 @@ this.maskStack.push(maskData); - gl.colorMask(false, false, false, false); + gl.colorMask(false, false, false, true); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); PIXI.WebGLGraphics.renderGraphics(maskData, renderSession); diff --git a/Gruntfile.js b/Gruntfile.js index e733fe7..8f53bd3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -61,6 +61,7 @@ '<%= dirs.src %>/loaders/BitmapFontLoader.js', '<%= dirs.src %>/loaders/SpineLoader.js', '<%= dirs.src %>/filters/AbstractFilter.js', + '<%= dirs.src %>/filters/AlphaMaskFilter.js', '<%= dirs.src %>/filters/ColorMatrixFilter.js', '<%= dirs.src %>/filters/GrayFilter.js', '<%= dirs.src %>/filters/DisplacementFilter.js', diff --git a/src/pixi/display/DisplayObject.js b/src/pixi/display/DisplayObject.js index 989410c..e353b85 100644 --- a/src/pixi/display/DisplayObject.js +++ b/src/pixi/display/DisplayObject.js @@ -446,6 +446,11 @@ return bounds; }; +PIXI.DisplayObject.prototype.setStageReference = function(stage) +{ + this.stage = stage; + if(this._interactive)this.stage.dirty = true; +}; PIXI.DisplayObject.prototype._renderWebGL = function(renderSession) { diff --git a/src/pixi/display/Stage.js b/src/pixi/display/Stage.js index d220684..934cba3 100644 --- a/src/pixi/display/Stage.js +++ b/src/pixi/display/Stage.js @@ -50,9 +50,6 @@ */ this.dirty = true; - this.__childrenAdded = []; - this.__childrenRemoved = []; - //the stage is it's own stage this.stage = this; @@ -60,7 +57,6 @@ this.stage.hitArea = new PIXI.Rectangle(0,0,100000, 100000); this.setBackgroundColor(backgroundColor); - this.worldVisible = true; }; // constructor diff --git a/src/pixi/filters/AlphaMaskFilter.js b/src/pixi/filters/AlphaMaskFilter.js index c1cab2f..cd1dff9 100644 --- a/src/pixi/filters/AlphaMaskFilter.js +++ b/src/pixi/filters/AlphaMaskFilter.js @@ -21,17 +21,15 @@ // set the uniforms //console.log() this.uniforms = { - displacementMap: {type: 'sampler2D', value:texture}, - scale: {type: '2f', value:{x:30, y:30}}, - offset: {type: '2f', value:{x:0, y:0}}, + mask: {type: 'sampler2D', value:texture}, mapDimensions: {type: '2f', value:{x:1, y:5112}}, dimensions: {type: '4fv', value:[0,0,0,0]} }; if(texture.baseTexture.hasLoaded) { - this.uniforms.mapDimensions.value.x = texture.width; - this.uniforms.mapDimensions.value.y = texture.height; + this.uniforms.mask.value.x = texture.width; + this.uniforms.mask.value.y = texture.height; } else { @@ -44,30 +42,25 @@ 'precision mediump float;', 'varying vec2 vTextureCoord;', 'varying vec4 vColor;', - 'uniform sampler2D displacementMap;', + 'uniform sampler2D mask;', 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', 'uniform vec2 offset;', 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', + 'uniform vec2 mapDimensions;', 'void main(void) {', ' vec2 mapCords = vTextureCoord.xy;', - //' mapCords -= ;', ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', ' mapCords.y *= -1.0;', ' mapCords.y += 1.0;', - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - ' vec2 cord = vTextureCoord;', + ' mapCords *= dimensions.xy / mapDimensions;', - //' gl_FragColor = texture2D(displacementMap, cord);', - // ' gl_FragColor = gl_FragColor;', + ' vec4 original = texture2D(uSampler, vTextureCoord);', + ' float maskAlpha = texture2D(mask, mapCords).r;', + ' original *= maskAlpha;', + //' original.rgb *= maskAlpha;', + ' gl_FragColor = original;', + //' gl_FragColor = gl_FragColor;', '}' ]; }; @@ -77,10 +70,10 @@ PIXI.AlphaMaskFilter.prototype.onTextureLoaded = function() { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; + this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; + this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); + this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); }; /** @@ -91,39 +84,10 @@ */ Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'map', { get: function() { - return this.uniforms.displacementMap.value; + return this.uniforms.mask.value; }, set: function(value) { - this.uniforms.displacementMap.value = value; + this.uniforms.mask.value = value; } }); -/** - * The multiplier used to scale the displacement result from the map calculation. - * - * @property scale - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'scale', { - get: function() { - return this.uniforms.scale.value; - }, - set: function(value) { - this.uniforms.scale.value = value; - } -}); - -/** - * The offset used to move the displacement map. - * - * @property offset - * @type Point - */ -Object.defineProperty(PIXI.AlphaMaskFilter.prototype, 'offset', { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } -}); diff --git a/src/pixi/loaders/SpineLoader.js b/src/pixi/loaders/SpineLoader.js index f0a38ca..0f1f3c9 100644 --- a/src/pixi/loaders/SpineLoader.js +++ b/src/pixi/loaders/SpineLoader.js @@ -64,7 +64,7 @@ var jsonLoader = new PIXI.JsonLoader(this.url, this.crossorigin); jsonLoader.addEventListener("loaded", function (event) { scope.json = event.content.json; - scope.onJSONLoaded(); + scope.onLoaded(); }); jsonLoader.load(); }; @@ -72,21 +72,6 @@ /** * Invoke when JSON file is loaded * - * @method onJSONLoaded - * @private - */ -PIXI.SpineLoader.prototype.onJSONLoaded = function () { - var spineJsonParser = new spine.SkeletonJson(); - var skeletonData = spineJsonParser.readSkeletonData(this.json); - - PIXI.AnimCache[this.url] = skeletonData; - - this.onLoaded(); -}; - -/** - * Invoke when JSON file is loaded - * * @method onLoaded * @private */ diff --git a/src/pixi/loaders/SpriteSheetLoader.js b/src/pixi/loaders/SpriteSheetLoader.js index e9844ce..4f4c802 100644 --- a/src/pixi/loaders/SpriteSheetLoader.js +++ b/src/pixi/loaders/SpriteSheetLoader.js @@ -80,47 +80,9 @@ 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 () { 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(); + jsonLoader.load(); }; /** diff --git a/src/pixi/primitives/Graphics.js b/src/pixi/primitives/Graphics.js index 8fddeab..f336e8f 100644 --- a/src/pixi/primitives/Graphics.js +++ b/src/pixi/primitives/Graphics.js @@ -67,21 +67,44 @@ this._webGL = []; this.isMask = false; + + this.bounds = null; + + this.boundsPadding = 10; }; // constructor PIXI.Graphics.prototype = Object.create( PIXI.DisplayObjectContainer.prototype ); PIXI.Graphics.prototype.constructor = PIXI.Graphics; -/* -* Not yet implemented -*/ +/** + * If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite. + * This is useful if your graphics element does not change often as it will speed up the rendering of the object + * It is also usful as the graphics object will always be aliased because it will be rendered using canvas + * Not recommended if you are conastanly redrawing the graphics element. + * + * @property cacheAsBitmap + * @default false + * @type Boolean + * @private + */ Object.defineProperty(PIXI.Graphics.prototype, "cacheAsBitmap", { get: function() { return this._cacheAsBitmap; }, set: function(value) { this._cacheAsBitmap = value; + + if(this._cacheAsBitmap) + { + this._generateCachedSprite(); + } + else + { + this.destroyCachedSprite(); + this.dirty = true; + } + } }); @@ -249,34 +272,72 @@ this.bounds = null; //new PIXI.Rectangle(); }; +/** + * Useful function that returns a texture of the graphics object that can then be used to create sprites + * This can be quite useful if your geometry is complicated and needs to be reused multiple times. + * + * @method generateTexture + * @return {Texture} a texture of the graphics object + */ +PIXI.Graphics.prototype.generateTexture = function() +{ + var bounds = this.getBounds(); + + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + canvasBuffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, canvasBuffer.context); + + return texture; +}; PIXI.Graphics.prototype._renderWebGL = function(renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element if(this.visible === false || this.alpha === 0 || this.isMask === true)return; - - renderSession.spriteBatch.stop(); - - if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); - if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); - - // check blend mode - if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + if(this._cacheAsBitmap) { - this.spriteBatch.currentBlendMode = this.blendMode; - var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; - this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - PIXI.WebGLGraphics.renderGraphics(this, renderSession); - - if(this._filters)renderSession.filterManager.popFilter(); - if(this._mask)renderSession.maskManager.popMask(renderSession); - - renderSession.drawCount++; + + if(this.dirty) + { + this._generateCachedSprite(); + // we will also need to update the texture on the gpu too! + PIXI.updateWebGLTexture(this._cachedSprite.texture.baseTexture, renderSession.gl); + + this.dirty = false; + } - renderSession.spriteBatch.start(); + PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderSession.spriteBatch.stop(); + + if(this._mask)renderSession.maskManager.pushMask(this.mask, renderSession); + if(this._filters)renderSession.filterManager.pushFilter(this._filterBlock); + + // check blend mode + if(this.blendMode !== renderSession.spriteBatch.currentBlendMode) + { + this.spriteBatch.currentBlendMode = this.blendMode; + var blendModeWebGL = PIXI.blendModesWebGL[renderSession.spriteBatch.currentBlendMode]; + this.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + if(this._filters)renderSession.filterManager.popFilter(); + if(this._mask)renderSession.maskManager.popMask(renderSession); + + renderSession.drawCount++; + + renderSession.spriteBatch.start(); + } }; PIXI.Graphics.prototype._renderCanvas = function(renderSession) @@ -425,9 +486,50 @@ } } - this.bounds = new PIXI.Rectangle(minX, minY, maxX - minX, maxY - minY); + var padding = this.boundsPadding; + this.bounds = new PIXI.Rectangle(minX - padding, minY - padding, (maxX - minX) + padding * 2, (maxY - minY) + padding * 2); }; +PIXI.Graphics.prototype._generateCachedSprite = function() +{ + var bounds = this.getBounds(); + + if(!this._cachedSprite) + { + var canvasBuffer = new PIXI.CanvasBuffer(bounds.width, bounds.height); + var texture = PIXI.Texture.fromCanvas(canvasBuffer.canvas); + + this._cachedSprite = new PIXI.Sprite(texture); + this._cachedSprite.buffer = canvasBuffer; + + this._cachedSprite.worldTransform = this.worldTransform; + } + else + { + this._cachedSprite.buffer.resize(bounds.width, bounds.height); + } + + // leverage the anchor to account for the offest of the element + this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); + this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); + + // this._cachedSprite.buffer.context.save(); + this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); + + PIXI.CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); + // this._cachedSprite.buffer.context.restore(); +}; + +PIXI.Graphics.prototype.destroyCachedSprite = function() +{ + this._cachedSprite.texture.destroy(true); + + // let the gc collect the unused sprite + // TODO could be object pooled! + this._cachedSprite = null; +}; + + // SOME TYPES: PIXI.Graphics.POLY = 0; PIXI.Graphics.RECT = 1; diff --git a/src/pixi/renderers/canvas/CanvasRenderer.js b/src/pixi/renderers/canvas/CanvasRenderer.js index d98e6fd..867b7f9 100644 --- a/src/pixi/renderers/canvas/CanvasRenderer.js +++ b/src/pixi/renderers/canvas/CanvasRenderer.js @@ -120,8 +120,8 @@ //stage.__childrenRemoved = []; // update textures if need be - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; PIXI.visibleCount++; stage.updateTransform(); @@ -149,7 +149,7 @@ // remove frame updates.. if(PIXI.Texture.frameUpdates.length > 0) { - PIXI.Texture.frameUpdates = []; + PIXI.Texture.frameUpdates.length = 0; } }; diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 58210ea..2cb7f99 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -2,13 +2,7 @@ * @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 = null; - - +PIXI.glContexts = []; // this is where we store the webGL contexts for easy access. /** * the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer @@ -46,8 +40,6 @@ this.view.addEventListener('webglcontextlost', function(event) { scope.handleContextLost(event); }, false); this.view.addEventListener('webglcontextrestored', function(event) { scope.handleContextRestored(event); }, false); - this.batchs = []; - this.options = { alpha: this.transparent, antialias:!!antialias, // SPEED UP?? @@ -71,6 +63,8 @@ var gl = this.gl; this.glContextId = gl.id = PIXI.WebGLRenderer.glContextId ++; + PIXI.glContexts[this.glContextId] = gl; + if(!PIXI.blendModesWebGL) { PIXI.blendModesWebGL = []; @@ -111,8 +105,6 @@ gl.useProgram(this.shaderManager.defaultShader.program); - PIXI.WebGLRenderer.gl = gl; - gl.disable(gl.DEPTH_TEST); gl.disable(gl.CULL_FACE); @@ -242,59 +234,12 @@ for (i = 0; i < PIXI.texturesToDestroy.length; i++) PIXI.WebGLRenderer.destroyTexture(PIXI.texturesToDestroy[i]); - PIXI.texturesToUpdate = []; - PIXI.texturesToDestroy = []; - PIXI.Texture.frameUpdates = []; + PIXI.texturesToUpdate.length = 0; + PIXI.texturesToDestroy.length = 0; + PIXI.Texture.frameUpdates.length = 0; }; /** - * 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 = this.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, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.BaseTexture.SCALE_MODE.LINEAR ? gl.LINEAR : gl.NEAREST); - - // 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 @@ -304,13 +249,19 @@ PIXI.WebGLRenderer.destroyTexture = function(texture) { //TODO break this out into a texture manager... - var gl = PIXI.gl; - if(texture._glTexture) + for (var i = texture._glTextures.length - 1; i >= 0; i--) { - texture._glTexture = gl.createTexture(); - gl.deleteTexture(gl.TEXTURE_2D, texture._glTexture); + var glTexture = texture._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if(gl && glTexture) + { + gl.deleteTexture(glTexture); + } } + + texture._glTextures.length = 0; }; PIXI.WebGLRenderer.updateTextureFrame = function(texture) @@ -373,6 +324,8 @@ gl.bindTexture(gl.TEXTURE_2D, null); } + + return texture._glTextures[gl.id]; }; PIXI.updateWebGLTexture = function(texture, gl) diff --git a/src/pixi/renderers/webgl/utils/WebGLGraphics.js b/src/pixi/renderers/webgl/utils/WebGLGraphics.js index fff1223..72fd085 100644 --- a/src/pixi/renderers/webgl/utils/WebGLGraphics.js +++ b/src/pixi/renderers/webgl/utils/WebGLGraphics.js @@ -193,13 +193,18 @@ if(graphicsData.lineWidth) { + var tempPoints = graphicsData.points; + graphicsData.points = [x, y, x + width, y, x + width, y + height, x, y + height, x, y]; + PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + + graphicsData.points = tempPoints; } }; @@ -260,6 +265,8 @@ if(graphicsData.lineWidth) { + var tempPoints = graphicsData.points; + graphicsData.points = []; for (i = 0; i < totalSegs + 1; i++) @@ -269,6 +276,8 @@ } PIXI.WebGLGraphics.buildLine(graphicsData, webGLData); + + graphicsData.points = tempPoints; } }; diff --git a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js index 93614cf..8e6f46c 100644 --- a/src/pixi/renderers/webgl/utils/WebGLMaskManager.js +++ b/src/pixi/renderers/webgl/utils/WebGLMaskManager.js @@ -29,7 +29,7 @@ this.maskStack.push(maskData); - gl.colorMask(false, false, false, false); + gl.colorMask(false, false, false, true); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); PIXI.WebGLGraphics.renderGraphics(maskData, renderSession); diff --git a/src/pixi/utils/Detector.js b/src/pixi/utils/Detector.js index d6046a3..6fad22f 100644 --- a/src/pixi/utils/Detector.js +++ b/src/pixi/utils/Detector.js @@ -31,13 +31,15 @@ } } )(); - if(webgl) + // used to detect ie 11 - no longer required + /* if(webgl) { var ie = (navigator.userAgent.toLowerCase().indexOf('trident') !== -1); webgl = !ie; } + */ - //console.log(webgl); + if( webgl ) { return new PIXI.WebGLRenderer(width, height, view, transparent, antialias);