From 28eb7a5f402f8cca5d0a92be87214dcdc96c06ae Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 4 Oct 2016 22:36:07 +0100 Subject: [PATCH] Adding in more renderer game objects. --- build/config.php | 6 + src/core/Group.js | 9 ++ src/core/Stage.js | 9 ++ src/gameobjects/Graphics.js | 33 +++++ src/gameobjects/Image.js | 9 ++ src/gameobjects/Sprite.js | 9 ++ src/gameobjects/SpriteBatch.js | 9 ++ src/gameobjects/Text.js | 9 ++ src/pixi/display/DisplayObjectContainer.js | 3 - src/pixi/display/Sprite.js | 3 - src/renderer/canvas/CanvasRenderer.js | 4 +- src/renderer/canvas/gameobjects/Graphics.js | 36 +---- .../canvas/gameobjects/SpriteBatch.js | 2 +- src/renderer/canvas/gameobjects/Stage.js | 34 +++++ src/renderer/canvas/gameobjects/Text.js | 127 ++++++++++++++++++ src/renderer/webgl/gameobjects/Graphics.js | 100 ++++++++++++++ src/renderer/webgl/gameobjects/Sprite.js | 2 +- src/renderer/webgl/gameobjects/Stage.js | 76 +++++++++++ src/renderer/webgl/gameobjects/Text.js | 82 +++++++++++ 19 files changed, 522 insertions(+), 40 deletions(-) create mode 100644 src/renderer/canvas/gameobjects/Stage.js create mode 100644 src/renderer/canvas/gameobjects/Text.js create mode 100644 src/renderer/webgl/gameobjects/Graphics.js create mode 100644 src/renderer/webgl/gameobjects/Stage.js create mode 100644 src/renderer/webgl/gameobjects/Text.js diff --git a/build/config.php b/build/config.php index e506e0079..388752e26 100644 --- a/build/config.php +++ b/build/config.php @@ -136,7 +136,10 @@ EOL; + + + @@ -147,6 +150,9 @@ EOL; + + + EOL; diff --git a/src/core/Group.js b/src/core/Group.js index 14b791eec..35f5a3111 100644 --- a/src/core/Group.js +++ b/src/core/Group.js @@ -291,6 +291,15 @@ Phaser.Group = function (game, parent, name, addToStage, enableBody, physicsBody */ this._sortProperty = 'z'; + if (this.game.renderType === Phaser.CANVAS) + { + this.render = Phaser.Renderer.Canvas.GameObjects.Container.render; + } + else + { + this.render = Phaser.Renderer.WebGL.GameObjects.Container.render; + } + }; Phaser.Group.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); diff --git a/src/core/Stage.js b/src/core/Stage.js index 77046ad48..c18b826e1 100644 --- a/src/core/Stage.js +++ b/src/core/Stage.js @@ -93,6 +93,15 @@ Phaser.Stage = function (game) { this.parseConfig(game.config); } + if (this.game.renderType === Phaser.CANVAS) + { + this.render = Phaser.Renderer.Canvas.GameObjects.Stage.render; + } + else + { + this.render = Phaser.Renderer.WebGL.GameObjects.Stage.render; + } + }; Phaser.Stage.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); diff --git a/src/gameobjects/Graphics.js b/src/gameobjects/Graphics.js index 61d66c374..2c9e3a318 100644 --- a/src/gameobjects/Graphics.js +++ b/src/gameobjects/Graphics.js @@ -201,6 +201,15 @@ Phaser.Graphics = function (game, x, y) { Phaser.Component.Core.init.call(this, game, x, y, '', null); + if (this.game.renderType === Phaser.CANVAS) + { + this.render = Phaser.Renderer.Canvas.GameObjects.Graphics.render; + } + else + { + this.render = Phaser.Renderer.WebGL.GameObjects.Graphics.render; + } + }; Phaser.Graphics.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); @@ -1513,6 +1522,30 @@ Phaser.Graphics.prototype.drawShape = function (shape) { }; +Phaser.Graphics.prototype.updateGraphicsTint = function () { + + if (this.tint === 0xFFFFFF) + { + return; + } + + var tintR = (this.tint >> 16 & 0xFF) / 255; + var tintG = (this.tint >> 8 & 0xFF) / 255; + var tintB = (this.tint & 0xFF) / 255; + + for (var i = 0; i < this.graphicsData.length; i++) + { + var data = this.graphicsData[i]; + + var fillColor = data.fillColor | 0; + var lineColor = data.lineColor | 0; + + data._fillTint = (((fillColor >> 16 & 0xFF) / 255 * tintR * 255 << 16) + ((fillColor >> 8 & 0xFF) / 255 * tintG * 255 << 8) + (fillColor & 0xFF) / 255 * tintB * 255); + data._lineTint = (((lineColor >> 16 & 0xFF) / 255 * tintR * 255 << 16) + ((lineColor >> 8 & 0xFF) / 255 * tintG * 255 << 8) + (lineColor & 0xFF) / 255 * tintB * 255); + } + +}; + /** * When cacheAsBitmap is set to true the graphics object will 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 in exchange for taking up texture memory. diff --git a/src/gameobjects/Image.js b/src/gameobjects/Image.js index 596c0c1eb..2ba7cfd41 100644 --- a/src/gameobjects/Image.js +++ b/src/gameobjects/Image.js @@ -50,6 +50,15 @@ Phaser.Image = function (game, x, y, key, frame) { Phaser.Component.Core.init.call(this, game, x, y, key, frame); + if (this.game.renderType === Phaser.CANVAS) + { + this.render = Phaser.Renderer.Canvas.GameObjects.Sprite.render; + } + else + { + this.render = Phaser.Renderer.WebGL.GameObjects.Sprite.render; + } + }; Phaser.Image.prototype = Object.create(PIXI.Sprite.prototype); diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index 73b83796b..38fddfee2 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -64,6 +64,15 @@ Phaser.Sprite = function (game, x, y, key, frame) { Phaser.Component.Core.init.call(this, game, x, y, key, frame); + if (this.game.renderType === Phaser.CANVAS) + { + this.render = Phaser.Renderer.Canvas.GameObjects.Sprite.render; + } + else + { + this.render = Phaser.Renderer.WebGL.GameObjects.Sprite.render; + } + }; Phaser.Sprite.prototype = Object.create(PIXI.Sprite.prototype); diff --git a/src/gameobjects/SpriteBatch.js b/src/gameobjects/SpriteBatch.js index 5f620f015..19d8ffffc 100644 --- a/src/gameobjects/SpriteBatch.js +++ b/src/gameobjects/SpriteBatch.js @@ -44,6 +44,15 @@ Phaser.SpriteBatch = function (game, parent, name, addToStage) { */ this.ready = false; + if (this.game.renderType === Phaser.CANVAS) + { + this.render = Phaser.Renderer.Canvas.GameObjects.SpriteBatch.render; + } + else + { + this.render = Phaser.Renderer.WebGL.GameObjects.SpriteBatch.render; + } + }; Phaser.SpriteBatch.prototype = Object.create(Phaser.Group.prototype); diff --git a/src/gameobjects/Text.js b/src/gameobjects/Text.js index 2083e9805..a8db74b4d 100644 --- a/src/gameobjects/Text.js +++ b/src/gameobjects/Text.js @@ -190,6 +190,15 @@ Phaser.Text = function (game, x, y, text, style) { this.updateText(); } + if (this.game.renderType === Phaser.CANVAS) + { + this.render = Phaser.Renderer.Canvas.GameObjects.Text.render; + } + else + { + this.render = Phaser.Renderer.WebGL.GameObjects.Text.render; + } + }; Phaser.Text.prototype = Object.create(Phaser.Sprite.prototype); diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index 6a00a4fd1..d67d82ebc 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -33,9 +33,6 @@ PIXI.DisplayObjectContainer = function () { * @default */ this.ignoreChildInput = false; - - // this.render = Phaser.Renderer.Canvas.GameObjects.Container.render; - this.render = Phaser.Renderer.WebGL.GameObjects.Container.render; }; diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index 29a33cea8..49ce59bcb 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -116,9 +116,6 @@ PIXI.Sprite = function (texture) { this.renderable = true; - // this.render = Phaser.Renderer.Canvas.GameObjects.Sprite.render; - this.render = Phaser.Renderer.WebGL.GameObjects.Sprite.render; - }; // constructor diff --git a/src/renderer/canvas/CanvasRenderer.js b/src/renderer/canvas/CanvasRenderer.js index e290897f7..4d8c8b7bc 100644 --- a/src/renderer/canvas/CanvasRenderer.js +++ b/src/renderer/canvas/CanvasRenderer.js @@ -104,9 +104,7 @@ Phaser.Renderer.Canvas = function (game) }; -Phaser.Renderer.Canvas.GameObjects = { - // Populated by the GameObjects classes -}; +Phaser.Renderer.Canvas.GameObjects = {}; Phaser.Renderer.Canvas.prototype.constructor = Phaser.Renderer.Canvas; diff --git a/src/renderer/canvas/gameobjects/Graphics.js b/src/renderer/canvas/gameobjects/Graphics.js index 31c19c632..b729d746d 100644 --- a/src/renderer/canvas/gameobjects/Graphics.js +++ b/src/renderer/canvas/gameobjects/Graphics.js @@ -8,10 +8,12 @@ Phaser.Renderer.Canvas.GameObjects.Graphics = { render: function (renderer) { var context = renderer.context; + var local = Phaser.Renderer.Canvas.GameObjects.Graphics; if (this.dirty) { this.updateGraphicsTint(); + this.dirty = false; } @@ -24,23 +26,23 @@ Phaser.Renderer.Canvas.GameObjects.Graphics = { switch (data.type) { case Phaser.RECTANGLE: - this.drawRectangle(data, context); + local.drawRectangle(data, context); break; case Phaser.CIRCLE: - this.drawCircle(data, context); + local.drawCircle(data, context); break; case Phaser.POLYGON: - this.drawPolygon(data, context); + local.drawPolygon(data, context); break; case Phaser.ELLIPSE: - this.drawEllipse(data, context); + local.drawEllipse(data, context); break; case Phaser.ROUNDEDRECTANGLE: - this.drawRoundedRectangle(data, context); + local.drawRoundedRectangle(data, context); break; } } @@ -218,30 +220,6 @@ Phaser.Renderer.Canvas.GameObjects.Graphics = { context.stroke(); } - }, - - updateGraphicsTint: function () - { - if (this.tint === 0xFFFFFF) - { - return; - } - - var tintR = (this.tint >> 16 & 0xFF) / 255; - var tintG = (this.tint >> 8 & 0xFF) / 255; - var tintB = (this.tint & 0xFF) / 255; - - for (var i = 0; i < this.graphicsData.length; i++) - { - var data = this.graphicsData[i]; - - var fillColor = data.fillColor | 0; - var lineColor = data.lineColor | 0; - - data._fillTint = (((fillColor >> 16 & 0xFF) / 255 * tintR * 255 << 16) + ((fillColor >> 8 & 0xFF) / 255 * tintG * 255 << 8) + (fillColor & 0xFF) / 255 * tintB * 255); - data._lineTint = (((lineColor >> 16 & 0xFF) / 255 * tintR * 255 << 16) + ((lineColor >> 8 & 0xFF) / 255 * tintG * 255 << 8) + (lineColor & 0xFF) / 255 * tintB * 255); - } - } }; diff --git a/src/renderer/canvas/gameobjects/SpriteBatch.js b/src/renderer/canvas/gameobjects/SpriteBatch.js index dd85d8b0a..bc3e95d9a 100644 --- a/src/renderer/canvas/gameobjects/SpriteBatch.js +++ b/src/renderer/canvas/gameobjects/SpriteBatch.js @@ -3,7 +3,7 @@ * For example the Group, Stage, Sprite, etc. because the render function * here is mapped to the prototype for the game object. */ -Phaser.Renderer.Canvas.GameObjects.Container = { +Phaser.Renderer.Canvas.GameObjects.SpriteBatch = { render: function (renderer) { diff --git a/src/renderer/canvas/gameobjects/Stage.js b/src/renderer/canvas/gameobjects/Stage.js new file mode 100644 index 000000000..662cccc31 --- /dev/null +++ b/src/renderer/canvas/gameobjects/Stage.js @@ -0,0 +1,34 @@ +/** +* Note that 'this' in all functions here refer to the owning object. +* For example the Group, Stage, Sprite, etc. because the render function +* here is mapped to the prototype for the game object. +*/ +Phaser.Renderer.Canvas.GameObjects.Stage = { + + render: function (renderer) + { + if (this.visible === false || this.alpha === 0) + { + return; + } + + if (this._mask) + { + renderer.pushMask(this._mask); + } + + for (var i = 0; i < this.children.length; i++) + { + var child = this.children[i]; + + child.render(renderer, child); + } + + if (this._mask) + { + renderer.popMask(); + } + + } + +}; diff --git a/src/renderer/canvas/gameobjects/Text.js b/src/renderer/canvas/gameobjects/Text.js new file mode 100644 index 000000000..e69f1e342 --- /dev/null +++ b/src/renderer/canvas/gameobjects/Text.js @@ -0,0 +1,127 @@ +/** +* Note that 'this' in all functions here refer to the owning object. +* For example the Group, Stage, Sprite, etc. because the render function +* here is mapped to the prototype for the game object. +*/ +Phaser.Renderer.Canvas.GameObjects.Text = { + + render: function (renderer) + { + // If the sprite is not visible or the alpha is 0 then no need to render this element + if (!this.visible || this.alpha === 0 || !this.renderable) + { + return; + } + + // Add back in: || src.texture.crop.width <= 0 || src.texture.crop.height <= 0 + + var wt = this.worldTransform; + + if (this.blendMode !== renderer.currentBlendMode) + { + renderer.currentBlendMode = this.blendMode; + renderer.context.globalCompositeOperation = Phaser.blendModesCanvas[renderer.currentBlendMode]; + } + + // Check if the texture can be rendered + + if (this._mask) + { + renderer.pushMask(this._mask); + } + + var resolution = this.texture.baseTexture.resolution / renderer.game.resolution; + + renderer.context.globalAlpha = this.worldAlpha; + + // If smoothingEnabled is supported and we need to change the smoothing property for src texture + if (renderer.smoothProperty && renderer.currentScaleMode !== this.texture.baseTexture.scaleMode) + { + renderer.currentScaleMode = this.texture.baseTexture.scaleMode; + renderer.context[renderer.smoothProperty] = (renderer.currentScaleMode === Phaser.scaleModes.LINEAR); + } + + // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions + var dx = (this.texture.trim) ? this.texture.trim.x - this.anchor.x * this.texture.trim.width : this.anchor.x * -this.texture.frame.width; + var dy = (this.texture.trim) ? this.texture.trim.y - this.anchor.y * this.texture.trim.height : this.anchor.y * -this.texture.frame.height; + + var tx = (wt.tx * renderer.game.resolution) + renderer.game.camera._shake.x; + var ty = (wt.ty * renderer.game.resolution) + renderer.game.camera._shake.y; + + var cw = this.texture.crop.width; + var ch = this.texture.crop.height; + + if (this.texture.rotated) + { + var a = wt.a; + var b = wt.b; + var c = wt.c; + var d = wt.d; + var e = cw; + + // Offset before rotating + tx = wt.c * ch + tx; + ty = wt.d * ch + ty; + + // Rotate matrix by 90 degrees + // We use precalculated values for sine and cosine of rad(90) + wt.a = a * 6.123233995736766e-17 + -c; + wt.b = b * 6.123233995736766e-17 + -d; + wt.c = a + c * 6.123233995736766e-17; + wt.d = b + d * 6.123233995736766e-17; + + // Update cropping dimensions. + cw = ch; + ch = e; + } + + // Allow for pixel rounding + if (renderer.roundPixels) + { + renderer.context.setTransform(wt.a, wt.b, wt.c, wt.d, tx | 0, ty | 0); + dx |= 0; + dy |= 0; + } + else + { + renderer.context.setTransform(wt.a, wt.b, wt.c, wt.d, tx, ty); + } + + dx /= resolution; + dy /= resolution; + + if (this.tint !== 0xFFFFFF) + { + if (this.texture.requiresReTint || this.cachedTint !== this.tint) + { + this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint); + + this.cachedTint = this.tint; + this.texture.requiresReTint = false; + } + + renderer.context.drawImage(this.tintedTexture, 0, 0, cw, ch, dx, dy, cw / resolution, ch / resolution); + } + else + { + var cx = this.texture.crop.x; + var cy = this.texture.crop.y; + + renderer.context.drawImage(this.texture.baseTexture.source, cx, cy, cw, ch, dx, dy, cw / resolution, ch / resolution); + } + + for (var i = 0; i < this.children.length; i++) + { + var child = this.children[i]; + + child.render(renderer, child); + } + + if (this._mask) + { + renderer.popMask(); + } + + } + +}; diff --git a/src/renderer/webgl/gameobjects/Graphics.js b/src/renderer/webgl/gameobjects/Graphics.js new file mode 100644 index 000000000..37d0db273 --- /dev/null +++ b/src/renderer/webgl/gameobjects/Graphics.js @@ -0,0 +1,100 @@ +/** +* Note that 'this' in all functions here refer to the owning object. +* For example the Group, Stage, Sprite, etc. because the render function +* here is mapped to the prototype for the game object. +*/ +Phaser.Renderer.WebGL.GameObjects.Graphics = { + + render: function (renderer) + { + var local = Phaser.Renderer.Canvas.GameObjects.Graphics; + + if (this.visible === false || this.alpha === 0 || this.isMask === true) + { + return; + } + + if (this._cacheAsBitmap) + { + if (this.dirty || this.cachedSpriteDirty) + { + this._generateCachedSprite(); + + // we will also need to update the texture on the gpu too! + this.updateCachedSpriteTexture(); + + this.cachedSpriteDirty = false; + this.dirty = false; + } + + this._cachedSprite.worldAlpha = this.worldAlpha; + + // PIXI.Sprite.prototype._renderWebGL.call(this._cachedSprite, renderSession); + + return; + } + else + { + renderer.spriteBatch.stop(); + renderer.setBlendMode(this.blendMode); + + if (this._mask) + { + renderer.pushMask(this._mask); + } + + if (this._filters) + { + renderer.filterManager.pushFilter(this._filterBlock); + } + + // check blend mode + if (this.blendMode !== renderer.spriteBatch.currentBlendMode) + { + renderer.spriteBatch.currentBlendMode = this.blendMode; + + var blendModeWebGL = renderer.blendModes[renderer.spriteBatch.currentBlendMode]; + + renderer.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); + } + + // check if the webgl graphic needs to be updated + if (this.webGLDirty) + { + this.dirty = true; + this.webGLDirty = false; + } + + // Merge with this class + // PIXI.WebGLGraphics.renderGraphics(this, renderSession); + + // only render if it has children! + if (this.children.length) + { + renderer.spriteBatch.start(); + + for (var i = 0; i < this.children.length; i++) + { + this.children[i].render(renderer); + } + + renderer.spriteBatch.stop(); + } + + if (this._filters) + { + renderer.filterManager.popFilter(); + } + + if (this._mask) + { + renderer.popMask(this.mask); + } + + renderer.drawCount++; + + renderer.spriteBatch.start(); + } + } + +}; diff --git a/src/renderer/webgl/gameobjects/Sprite.js b/src/renderer/webgl/gameobjects/Sprite.js index b9c1bdb78..229a9ecc1 100644 --- a/src/renderer/webgl/gameobjects/Sprite.js +++ b/src/renderer/webgl/gameobjects/Sprite.js @@ -67,7 +67,7 @@ Phaser.Renderer.WebGL.GameObjects.Sprite = { // Render children! for (i = 0; i < this.children.length; i++) { - this.children[i].render(renderSession); + this.children[i].render(renderer); } } } diff --git a/src/renderer/webgl/gameobjects/Stage.js b/src/renderer/webgl/gameobjects/Stage.js new file mode 100644 index 000000000..4cc386ad1 --- /dev/null +++ b/src/renderer/webgl/gameobjects/Stage.js @@ -0,0 +1,76 @@ +/** +* Note that 'this' in all functions here refer to the owning object. +* For example the Group, Stage, Sprite, etc. because the render function +* here is mapped to the prototype for the game object. +*/ +Phaser.Renderer.WebGL.GameObjects.Stage = { + + render: function (renderer) + { + if (this.visible === false || this.alpha === 0 || this.children.length === 0) + { + return; + } + + var i; + + if (this._mask || this._filters) + { + // push filter first as we need to ensure the stencil buffer is correct for any masking + if (this._filters) + { + renderer.spriteBatch.flush(); + renderer.filterManager.pushFilter(this._filterBlock); + } + + if (this._mask) + { + renderer.spriteBatch.stop(); + renderer.pushMask(this.mask); + renderer.spriteBatch.start(); + } + + // simple render children! + for (i = 0; i < this.children.length; i++) + { + if (!this.children[i].render) + { + console.dir(this.children[i]); + debugger; + } + + this.children[i].render(renderer); + } + + renderer.spriteBatch.stop(); + + if (this._mask) + { + renderer.popMask(this._mask); + } + + if (this._filters) + { + renderer.filterManager.popFilter(); + } + + renderer.spriteBatch.start(); + } + else + { + // simple render children! + for (i = 0; i < this.children.length; i++) + { + if (!this.children[i].render) + { + console.dir(this.children[i]); + debugger; + } + + this.children[i].render(renderer); + } + } + + } + +}; diff --git a/src/renderer/webgl/gameobjects/Text.js b/src/renderer/webgl/gameobjects/Text.js new file mode 100644 index 000000000..05dbe9274 --- /dev/null +++ b/src/renderer/webgl/gameobjects/Text.js @@ -0,0 +1,82 @@ +/** +* Note that 'this' in all functions here refer to the owning object. +* For example the Group, Stage, Sprite, etc. because the render function +* here is mapped to the prototype for the game object. +*/ +Phaser.Renderer.WebGL.GameObjects.Text = { + + render: function (renderer) + { + if (this.dirty) + { + this.updateText(); + this.dirty = false; + } + + // If the sprite is not visible or the alpha is 0 then no need to render this element + if (!this.visible || this.alpha === 0 || !this.renderable) + { + return; + } + + // Add back in: || src.texture.crop.width <= 0 || src.texture.crop.height <= 0 + + var i; + + // Would be good to get this down to 1 check, or even none. + if (this._mask || this._filters) + { + var spriteBatch = renderer.spriteBatch; + + // push filter first as we need to ensure the stencil buffer is correct for any masking + if (this._filters) + { + spriteBatch.flush(); + renderer.filterManager.pushFilter(this._filterBlock); + } + + if (this._mask) + { + spriteBatch.stop(); + renderer.pushMask(this.mask); + spriteBatch.start(); + } + + // add this sprite to the batch + spriteBatch.render(this); + + // now loop through the children and make sure they get rendered + for (i = 0; i < this.children.length; i++) + { + this.children[i].render(renderer); + } + + // time to stop the sprite batch as either a mask element or a filter draw will happen next + spriteBatch.stop(); + + if (this._mask) + { + renderer.popMask(this._mask); + } + + if (this._filters) + { + renderer.filterManager.popFilter(); + } + + spriteBatch.start(); + } + else + { + renderer.spriteBatch.render(this); + + // Render children! + for (i = 0; i < this.children.length; i++) + { + this.children[i].render(renderer); + } + } + + } + +};