From 1da95994a58467c24d6338a912a902733a3ff388 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Mon, 3 Oct 2016 12:44:54 +0100 Subject: [PATCH] First pass of the newly re-structured Canvas Renderer (still using old texture system though). --- build/config.php | 4 + src/Phaser.js | 8 +- src/core/Game.js | 7 +- src/gameobjects/components/Children.js | 5 + src/pixi/display/DisplayObjectContainer.js | 2 + src/pixi/display/Sprite.js | 2 + src/pixi/renderers/webgl/WebGLRenderer.js | 2 + src/renderer/canvas/CanvasRenderer.js | 277 +++++++++++++++++++ src/renderer/canvas/gameobjects/Container.js | 49 ++++ src/renderer/canvas/gameobjects/Sprite.js | 241 ++++++++-------- src/textures/Frame.js | 3 + src/textures/Texture.js | 27 -- src/textures/TextureManager.js | 95 +++++++ 13 files changed, 575 insertions(+), 147 deletions(-) create mode 100644 src/renderer/canvas/CanvasRenderer.js create mode 100644 src/renderer/canvas/gameobjects/Container.js diff --git a/build/config.php b/build/config.php index 539c93e10..7c781f64a 100644 --- a/build/config.php +++ b/build/config.php @@ -133,6 +133,10 @@ EOL; + + + + EOL; diff --git a/src/Phaser.js b/src/Phaser.js index 0e19552d4..9feb52049 100644 --- a/src/Phaser.js +++ b/src/Phaser.js @@ -542,7 +542,13 @@ var Phaser = Phaser || { // jshint ignore:line NEAREST: 1 }, - PIXI: PIXI || {}, + Renderer: { + + }, + + PIXI: PIXI || { + + }, // Used to create IDs for various Pixi objects. _UID: 0 diff --git a/src/core/Game.js b/src/core/Game.js index 0c01f1d19..036ef6d65 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -685,10 +685,12 @@ Phaser.Game.prototype = { return; } + var c = (this.renderType === Phaser.CANVAS) ? 'Canvas' : 'WebGL'; + if (!this.device.ie) { var args = [ - '%c %c %c %c %c Phaser v' + Phaser.VERSION + ' / Pixi.js %c http://phaser.io', + '%c %c %c %c %c Phaser v' + Phaser.VERSION + ' / Pixi.js / ' + c + ' %c http://phaser.io', 'background: #ff0000', 'background: #ffff00', 'background: #00ff00', @@ -739,7 +741,8 @@ Phaser.Game.prototype = { // They requested Canvas and their browser supports it this.renderType = Phaser.CANVAS; - this.renderer = new PIXI.CanvasRenderer(this); + // this.renderer = new PIXI.CanvasRenderer(this); + this.renderer = new Phaser.Renderer.Canvas(this); this.context = this.renderer.context; } diff --git a/src/gameobjects/components/Children.js b/src/gameobjects/components/Children.js index 0aad208f5..e7994eda1 100644 --- a/src/gameobjects/components/Children.js +++ b/src/gameobjects/components/Children.js @@ -46,6 +46,11 @@ Phaser.Component.Children.prototype = { addAt: function (child, index) { + if (this.list.length === 0) + { + return this.add(child); + } + if (index >= 0 && index <= this.list.length) { if (child.parent) diff --git a/src/pixi/display/DisplayObjectContainer.js b/src/pixi/display/DisplayObjectContainer.js index d67d82ebc..15a5ea5d0 100644 --- a/src/pixi/display/DisplayObjectContainer.js +++ b/src/pixi/display/DisplayObjectContainer.js @@ -33,6 +33,8 @@ PIXI.DisplayObjectContainer = function () { * @default */ this.ignoreChildInput = false; + + this.render = Phaser.Renderer.Canvas.GameObjects.Container.render; }; diff --git a/src/pixi/display/Sprite.js b/src/pixi/display/Sprite.js index 49ce59bcb..97b52ca26 100644 --- a/src/pixi/display/Sprite.js +++ b/src/pixi/display/Sprite.js @@ -116,6 +116,8 @@ PIXI.Sprite = function (texture) { this.renderable = true; + this.render = Phaser.Renderer.Canvas.GameObjects.Sprite.render; + }; // constructor diff --git a/src/pixi/renderers/webgl/WebGLRenderer.js b/src/pixi/renderers/webgl/WebGLRenderer.js index 36f640f4f..8c7758474 100644 --- a/src/pixi/renderers/webgl/WebGLRenderer.js +++ b/src/pixi/renderers/webgl/WebGLRenderer.js @@ -499,6 +499,8 @@ PIXI.WebGLRenderer.prototype.updateCompressedTexture = function (texture) { }; /** + * Note: Moved to TextureManager class. + * * Updates and Creates a WebGL texture for the renderers context. * * @method updateTexture diff --git a/src/renderer/canvas/CanvasRenderer.js b/src/renderer/canvas/CanvasRenderer.js new file mode 100644 index 000000000..ef7e7c28b --- /dev/null +++ b/src/renderer/canvas/CanvasRenderer.js @@ -0,0 +1,277 @@ +/** +* @author Richard Davey +* @author Mat Groves (@Doormat23) +* @copyright 2016 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** +* A Camera is your view into the game world. It has a position and size and renders only those objects within its field of view. +* The game automatically creates a single Stage sized camera on boot. Move the camera around the world with Phaser.Camera.x/y +* +* @class Phaser.Camera +* @constructor +* @param {Phaser.Game} game - Game reference to the currently running game. +*/ +Phaser.Renderer.Canvas = function (game) +{ + console.log('CanvasRenderer Alive'); + + /** + * @property {Phaser.Game} game - A reference to the currently running Game. + */ + this.game = game; + + this.type = Phaser.CANVAS; + + // this.resolution = game.resolution; + + /** + * This sets if the CanvasRenderer will clear the canvas or not before the new render pass. + * If the Stage is NOT transparent Pixi will use a canvas sized fillRect operation every frame to set the canvas background color. + * If the Stage is transparent Pixi will use clearRect to clear the canvas every frame. + * Disable this by setting this to false. For example if your game has a canvas filling background image you often don't need this set. + * + * @property clearBeforeRender + * @type Boolean + * @default + */ + this.clearBeforeRender = game.clearBeforeRender; + + /** + * Whether the render view is transparent + * + * @property transparent + * @type Boolean + */ + this.transparent = game.transparent; + + /** + * Whether the render view should be resized automatically + * + * @property autoResize + * @type Boolean + */ + this.autoResize = false; + + /** + * The width of the canvas view + * + * @property width + * @type Number + * @default 800 + */ + this.width = game.width * game.resolution; + + /** + * The height of the canvas view + * + * @property height + * @type Number + * @default 600 + */ + this.height = game.height * game.resolution; + + /** + * The canvas element that everything is drawn to. + * + * @property view + * @type HTMLCanvasElement + */ + this.view = game.canvas; + + /** + * The canvas 2d context that everything is drawn with + * @property context + * @type CanvasRenderingContext2D + */ + this.context = this.view.getContext('2d', { + alpha: this.transparent + }); + + this.smoothProperty = Phaser.Canvas.getSmoothingPrefix(this.context); + + this.roundPixels = false; + + var so = 'source-over'; + + this.blendModes = [ so, 'lighter', so, so, so, so, so, so, so, so, so, so, so, so, so, so, so ]; + + this.currentBlendMode = 0; + this.currentScaleMode = 0; + + if (this.game.device.canUseMultiply) + { + this.mapBlendModes(); + } + + this.resize(this.width, this.height); + + // this.renderTypes = []; + // this.renderTypes[Phaser.GROUP] = Phaser.Renderer.Canvas.GameObjects.Container; + // this.renderTypes[Phaser.SPRITE] = Phaser.Renderer.Canvas.GameObjects.Sprite; + +}; + +Phaser.Renderer.Canvas.GameObjects = { + // Populated by the GameObjects classes +}; + +Phaser.Renderer.Canvas.prototype.constructor = Phaser.Renderer.Canvas; + +Phaser.Renderer.Canvas.prototype = { + + /** + * Maps Blend modes to Canvas blend modes. + * + * @method mapBlendModes + * @private + */ + mapBlendModes: function () + { + var modes = Phaser.blendModes; + + this.blendModes[modes.MULTIPLY] = 'multiply'; + this.blendModes[modes.SCREEN] = 'screen'; + this.blendModes[modes.OVERLAY] = 'overlay'; + this.blendModes[modes.DARKEN] = 'darken'; + this.blendModes[modes.LIGHTEN] = 'lighten'; + this.blendModes[modes.COLOR_DODGE] = 'color-dodge'; + this.blendModes[modes.COLOR_BURN] = 'color-burn'; + this.blendModes[modes.HARD_LIGHT] = 'hard-light'; + this.blendModes[modes.SOFT_LIGHT] = 'soft-light'; + this.blendModes[modes.DIFFERENCE] = 'difference'; + this.blendModes[modes.EXCLUSION] = 'exclusion'; + this.blendModes[modes.HUE] = 'hue'; + this.blendModes[modes.SATURATION] = 'saturation'; + this.blendModes[modes.COLOR] = 'color'; + this.blendModes[modes.LUMINOSITY] = 'luminosity'; + + }, + + resize: function (width, height) + { + this.width = width * this.game.resolution; + this.height = height * this.game.resolution; + + this.view.width = this.width; + this.view.height = this.height; + + if (this.autoResize) + { + this.view.style.width = (this.width / this.game.resolution) + 'px'; + this.view.style.height = (this.height / this.game.resolution) + 'px'; + } + + if (this.smoothProperty) + { + this.context[this.smoothProperty] = (this.scaleMode === Phaser.scaleModes.LINEAR); + } + + }, + + /** + * Renders the Phaser.Stage to the canvas view, then iterates through its children. + * + * @method render + * @param stage {Phaser.Stage} + */ + render: function (stage) + { + this.context.setTransform(1, 0, 0, 1, 0, 0); + this.context.globalAlpha = 1; + this.context.globalCompositeOperation = 'source-over'; + + this.currentBlendMode = 0; + this.currentScaleMode = 0; + + // Add Pre-render hook + + // this.renderSession.currentBlendMode = 0; + // this.renderSession.shakeX = this.game.camera._shake.x; + // this.renderSession.shakeY = this.game.camera._shake.y; + + // Is this needed any longer? + /* + if (navigator.isCocoonJS && this.view.screencanvas) + { + this.context.fillStyle = "black"; + this.context.clear(); + } + */ + + if (this.clearBeforeRender) + { + if (this.transparent) + { + this.context.clearRect(0, 0, this.width, this.height); + } + else if (stage._bgColor) + { + this.context.fillStyle = stage._bgColor.rgba; + this.context.fillRect(0, 0, this.width , this.height); + } + } + + stage.render(this, stage); + + // Add Post-render hook + + }, + + /** + * This method adds it to the current stack of masks. + * + * @method pushMask + * @param maskData {Object} the maskData that will be pushed + * @param renderSession {Object} The renderSession whose context will be used for this mask manager. + */ + pushMask: function (maskData) + { + this.context.save(); + + var cacheAlpha = maskData.alpha; + var transform = maskData.worldTransform; + + var resolution = this.game.resolution; + + this.context.setTransform( + transform.a * resolution, + transform.b * resolution, + transform.c * resolution, + transform.d * resolution, + transform.tx * resolution, + transform.ty * resolution + ); + + // PIXI.CanvasGraphics.renderGraphicsMask(maskData, context); + + this.context.clip(); + + maskData.worldAlpha = cacheAlpha; + + }, + + popMask: function () + { + this.context.restore(); + }, + + /** + * Removes everything from the renderer and optionally removes the Canvas DOM element. + * + * @method destroy + * @param [removeView=true] {boolean} Removes the Canvas element from the DOM. + */ + destroy: function () + { + // CanvasPool + + this.view = null; + this.context = null; + this.maskManager = null; + + } + +}; + diff --git a/src/renderer/canvas/gameobjects/Container.js b/src/renderer/canvas/gameobjects/Container.js new file mode 100644 index 000000000..03f5210d3 --- /dev/null +++ b/src/renderer/canvas/gameobjects/Container.js @@ -0,0 +1,49 @@ +/** +* Renders the object using the Canvas renderer +* +* @method _renderCanvas +* @param renderSession {RenderSession} +* @private +*/ +Phaser.Renderer.Canvas.GameObjects.Container = { + + render: function (renderer, source) + { + if (source.visible === false || source.alpha === 0) + { + return; + } + + // if (this._cacheAsBitmap) + // { + // this._renderCachedSprite(renderSession); + // return; + // } + + if (source._mask) + { + renderer.pushMask(source._mask); + } + + for (var i = 0; i < source.children.length; i++) + { + var child = source.children[i]; + + child.render(renderer, child); + } + + if (this._mask) + { + renderer.popMask(); + } + + }, + + renderCache: function (renderer, source) + { + // Do something + + return source; + } + +}; diff --git a/src/renderer/canvas/gameobjects/Sprite.js b/src/renderer/canvas/gameobjects/Sprite.js index 4544bf15f..166df6f2f 100644 --- a/src/renderer/canvas/gameobjects/Sprite.js +++ b/src/renderer/canvas/gameobjects/Sprite.js @@ -6,138 +6,145 @@ * @param {Matrix} [matrix] - Optional matrix. If provided the Display Object will be rendered using this matrix, otherwise it will use its worldTransform. * @private */ -Phaser.CanvasRenderer.GameObjects.Sprite = function (src, renderSession, matrix) { +Phaser.Renderer.Canvas.GameObjects.Sprite = { - // If the sprite is not visible or the alpha is 0 then no need to render this element - if (!src.visible || src.alpha === 0 || !src.renderable || src.texture.crop.width <= 0 || src.texture.crop.height <= 0) + render: function (renderer, source, matrix) { - return; - } - - var wt = src.worldTransform; - - // If they provided an alternative rendering matrix then use it - if (matrix) - { - wt = matrix; - } - - if (src.blendMode !== renderSession.currentBlendMode) - { - renderSession.currentBlendMode = src.blendMode; - renderSession.context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode]; - } - - if (src._mask) - { - renderSession.maskManager.pushMask(src._mask, renderSession); - } - - // Ignore null sources - if (!src.texture.valid) - { - // Update the children and leave - for (var i = 0; i < src.children.length; i++) + // If the sprite is not visible or the alpha is 0 then no need to render this element + if (!source.visible || source.alpha === 0 || !source.renderable) { - src.children[i]._renderCanvas(renderSession); + return; } - if (src._mask) + // Add back in: || src.texture.crop.width <= 0 || src.texture.crop.height <= 0 + + // If they provided an alternative rendering matrix then use it + var wt = (matrix) ? matrix : source.worldTransform; + + if (source.blendMode !== renderer.currentBlendMode) { - renderSession.maskManager.popMask(renderSession); + renderer.currentBlendMode = source.blendMode; + renderer.context.globalCompositeOperation = Phaser.blendModesCanvas[renderer.currentBlendMode]; } - return; - } + // Check if the texture can be rendered - var resolution = src.texture.baseTexture.resolution / renderSession.resolution; - - renderSession.context.globalAlpha = src.worldAlpha; - - // If smoothingEnabled is supported and we need to change the smoothing property for src texture - if (renderSession.smoothProperty && renderSession.scaleMode !== src.texture.baseTexture.scaleMode) - { - renderSession.scaleMode = src.texture.baseTexture.scaleMode; - renderSession.context[renderSession.smoothProperty] = (renderSession.scaleMode === PIXI.scaleModes.LINEAR); - } - - // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions - var dx = (src.texture.trim) ? src.texture.trim.x - src.anchor.x * src.texture.trim.width : src.anchor.x * -src.texture.frame.width; - var dy = (src.texture.trim) ? src.texture.trim.y - src.anchor.y * src.texture.trim.height : src.anchor.y * -src.texture.frame.height; - - var tx = (wt.tx * renderSession.resolution) + renderSession.shakeX; - var ty = (wt.ty * renderSession.resolution) + renderSession.shakeY; - - var cw = src.texture.crop.width; - var ch = src.texture.crop.height; - - if (src.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 (renderSession.roundPixels) - { - renderSession.context.setTransform(wt.a, wt.b, wt.c, wt.d, tx | 0, ty | 0); - dx |= 0; - dy |= 0; - } - else - { - renderSession.context.setTransform(wt.a, wt.b, wt.c, wt.d, tx, ty); - } - - dx /= resolution; - dy /= resolution; - - if (src.tint !== 0xFFFFFF) - { - if (src.texture.requiresReTint || src.cachedTint !== src.tint) + if (source._mask) { - src.tintedTexture = PIXI.CanvasTinter.getTintedTexture(src, src.tint); - - src.cachedTint = src.tint; - src.texture.requiresReTint = false; + renderer.pushMask(source._mask); } - renderSession.context.drawImage(src.tintedTexture, 0, 0, cw, ch, dx, dy, cw / resolution, ch / resolution); - } - else - { - var cx = src.texture.crop.x; - var cy = src.texture.crop.y; + // Ignore null sources + /* + if (!src.texture.valid) + { + // Update the children and leave + for (var i = 0; i < src.children.length; i++) + { + src.children[i]._renderCanvas(renderSession); + } - renderSession.context.drawImage(src.texture.baseTexture.source, cx, cy, cw, ch, dx, dy, cw / resolution, ch / resolution); - } + if (src._mask) + { + renderSession.maskManager.popMask(renderSession); + } - for (var i = 0; i < src.children.length; i++) - { - src.children[i]._renderCanvas(renderSession); - } + return; + } + */ + + var resolution = source.texture.baseTexture.resolution / renderer.game.resolution; + + renderer.context.globalAlpha = source.worldAlpha; + + // If smoothingEnabled is supported and we need to change the smoothing property for src texture + if (renderer.smoothProperty && renderer.currentScaleMode !== source.texture.baseTexture.scaleMode) + { + renderer.currentScaleMode = source.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 = (source.texture.trim) ? source.texture.trim.x - source.anchor.x * source.texture.trim.width : source.anchor.x * -source.texture.frame.width; + var dy = (source.texture.trim) ? source.texture.trim.y - source.anchor.y * source.texture.trim.height : source.anchor.y * -source.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 = source.texture.crop.width; + var ch = source.texture.crop.height; + + if (source.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 (source.tint !== 0xFFFFFF) + { + if (source.texture.requiresReTint || source.cachedTint !== source.tint) + { + source.tintedTexture = PIXI.CanvasTinter.getTintedTexture(source, source.tint); + + source.cachedTint = source.tint; + source.texture.requiresReTint = false; + } + + renderer.context.drawImage(source.tintedTexture, 0, 0, cw, ch, dx, dy, cw / resolution, ch / resolution); + } + else + { + var cx = source.texture.crop.x; + var cy = source.texture.crop.y; + + renderer.context.drawImage(source.texture.baseTexture.source, cx, cy, cw, ch, dx, dy, cw / resolution, ch / resolution); + } + + for (var i = 0; i < source.children.length; i++) + { + var child = source.children[i]; + + child.render(renderer, child); + } + + if (source._mask) + { + renderer.popMask(); + } - if (src._mask) - { - renderSession.maskManager.popMask(renderSession); } }; diff --git a/src/textures/Frame.js b/src/textures/Frame.js index ba3e8745a..540ec6328 100644 --- a/src/textures/Frame.js +++ b/src/textures/Frame.js @@ -100,6 +100,9 @@ Phaser.TextureFrame = function (texture, name, sourceIndex, x, y, width, height) */ this.requiresReTint = false; + // Over-rides the Renderer setting? 0 = use Renderer Setting, 1 = No rounding, 2 = Round + this.autoRound = 0; + /** * The un-modified source frame, trim and UV data. * diff --git a/src/textures/Texture.js b/src/textures/Texture.js index a2e83e337..a565dfd1c 100644 --- a/src/textures/Texture.js +++ b/src/textures/Texture.js @@ -120,33 +120,6 @@ Phaser.Texture.prototype = { } }, - /** - * Removes the base texture from the GPU, useful for managing resources on the GPU. - * A texture is still 100% usable and will simply be re-uploaded if there is a sprite on screen that is using it. - * - * @method unloadFromGPU - */ - unloadFromGPU: function () - { - this.dirty(); - - // delete the webGL textures if any. - for (var i = this._glTextures.length - 1; i >= 0; i--) - { - var glTexture = this._glTextures[i]; - var gl = PIXI.glContexts[i]; - - if (gl && glTexture) - { - gl.deleteTexture(glTexture); - } - } - - this._glTextures.length = 0; - - this.dirty(); - }, - /** * Destroys this base texture * diff --git a/src/textures/TextureManager.js b/src/textures/TextureManager.js index 3ea2043ee..7a1d4ef5b 100644 --- a/src/textures/TextureManager.js +++ b/src/textures/TextureManager.js @@ -185,6 +185,101 @@ Phaser.TextureManager.prototype = { callback.apply(thisArg, args); } + }, + + /** + * TODO: This should move to the WebGL Renderer class. + * + * Removes the base texture from the GPU, useful for managing resources on the GPU. + * A texture is still 100% usable and will simply be re-uploaded if there is a sprite on screen that is using it. + * + * @method unloadFromGPU + */ + unloadFromGPU: function () + { + this.dirty(); + + // delete the webGL textures if any. + for (var i = this._glTextures.length - 1; i >= 0; i--) + { + var glTexture = this._glTextures[i]; + var gl = PIXI.glContexts[i]; + + if (gl && glTexture) + { + gl.deleteTexture(glTexture); + } + } + + this._glTextures.length = 0; + + this.dirty(); + }, + + /** + * TODO: This should move to the WebGL Renderer class. + * + * Updates and Creates a WebGL texture for the renderers context. + * + * @method updateTexture + * @param texture {Texture} the texture to update + * @return {boolean} True if the texture was successfully bound, otherwise false. + */ + loadToGPU: function (texture) + { + if (!texture.hasLoaded) + { + return false; + } + + if (texture.source.compressionAlgorithm) + { + return this.updateCompressedTexture(texture); + } + + var gl = this.gl; + + if (!texture._glTextures[gl.id]) + { + texture._glTextures[gl.id] = gl.createTexture(); + } + + gl.activeTexture(gl.TEXTURE0 + texture.textureIndex); + + gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); + + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); + + 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.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + + if (texture.mipmap && Phaser.Math.isPowerOfTwo(texture.width, texture.height)) + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST); + gl.generateMipmap(gl.TEXTURE_2D); + } + else + { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === PIXI.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); + } + + 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); + } + + texture._dirty[gl.id] = false; + + // return texture._glTextures[gl.id]; + return true; + } };