diff --git a/src/gameobjects/graphics/Graphics.js b/src/gameobjects/graphics/Graphics.js index 2a511a494..e1c321e60 100644 --- a/src/gameobjects/graphics/Graphics.js +++ b/src/gameobjects/graphics/Graphics.js @@ -745,9 +745,9 @@ var Graphics = new Class({ { this.renderCanvas(sys.game.renderer, this, 0, Graphics.TargetCamera, ctx); - if (this.gl && texture) + if (sys.game.renderer.gl && texture) { - sys.game.renderer.uploadCanvasToGPU(ctx.canvas, texture.source[0].glTexture, true); + texture.source[0].glTexture = sys.game.renderer.canvasToTexture(ctx.canvas, texture.source[0].glTexture, true, 0); } } diff --git a/src/gameobjects/graphics/GraphicsWebGLRenderer.js b/src/gameobjects/graphics/GraphicsWebGLRenderer.js index 3faf3e94f..225fec14a 100644 --- a/src/gameobjects/graphics/GraphicsWebGLRenderer.js +++ b/src/gameobjects/graphics/GraphicsWebGLRenderer.js @@ -1,373 +1,13 @@ -var Commands = require('./Commands'); var GameObject = require('../GameObject'); -var TransformMatrix = require('../components/TransformMatrix'); -var cos = Math.cos; -var sin = Math.sin; - -var currentMatrix = new TransformMatrix(); -var matrixStack = new Float32Array(6 * 1000); -var matrixStackLength = 0; -var pathArray = []; -var tempMatrix = new TransformMatrix(); - -var Point = function (x, y, width, rgb, alpha) +var GraphicsWebGLRenderer = function (renderer, graphics, interpolationPercentage, camera, forceRenderTarget) { - this.x = x; - this.y = y; - this.width = width; - this.rgb = rgb; - this.alpha = alpha; -}; - -var Path = function (x, y, width, rgb, alpha) -{ - this.points = []; - this.pointsLength = 1; - this.points[0] = new Point(x, y, width, rgb, alpha); -}; - -var GraphicsWebGLRenderer = function (renderer, gameObject, interpolationPercentage, camera, forceRenderTarget) -{ - if (GameObject.RENDER_MASK !== gameObject.renderFlags || (gameObject.cameraFilter > 0 && (gameObject.cameraFilter & camera._id))) + if (GameObject.RENDER_MASK !== graphics.renderFlags || (graphics.cameraFilter > 0 && (graphics.cameraFilter & camera._id))) { return; } - var renderTarget = forceRenderTarget || gameObject.renderTarget; - var shapeBatch = renderer.shapeBatch; - var cameraScrollX = camera.scrollX * gameObject.scrollFactorX; - var cameraScrollY = camera.scrollY * gameObject.scrollFactorY; - var srcX = gameObject.x - cameraScrollX; - var srcY = gameObject.y - cameraScrollY; - var srcScaleX = gameObject.scaleX; - var srcScaleY = gameObject.scaleY; - var srcRotation = -gameObject.rotation; - var commandBuffer = gameObject.commandBuffer; - var lineAlpha = 1.0; - var fillAlpha = 1.0; - var lineColor = 0; - var fillColor = 0; - var lineWidth = 1.0; - var cameraMatrix = camera.matrix.matrix; - var lastPath = null; - var iteration = 0; - var iterStep = 0.01; - var tx = 0; - var ty = 0; - var ta = 0; - var x, y, radius, startAngle, endAngle, anticlockwise; - var path; - var tempMatrixMatrix = tempMatrix.matrix; - var sra, srb, src, srd, sre, srf, cma, cmb, cmc, cmd, cme, cmf; - var mva, mvb, mvc, mvd, mve, mvf; - - tempMatrix.applyITRS(srcX, srcY, srcRotation, srcScaleX, srcScaleY); - - sra = tempMatrixMatrix[0]; - srb = tempMatrixMatrix[1]; - src = tempMatrixMatrix[2]; - srd = tempMatrixMatrix[3]; - sre = tempMatrixMatrix[4]; - srf = tempMatrixMatrix[5]; - - cma = cameraMatrix[0]; - cmb = cameraMatrix[1]; - cmc = cameraMatrix[2]; - cmd = cameraMatrix[3]; - cme = cameraMatrix[4]; - cmf = cameraMatrix[5]; - - mva = sra * cma + srb * cmc; - mvb = sra * cmb + srb * cmd; - mvc = src * cma + srd * cmc; - mvd = src * cmb + srd * cmd; - mve = sre * cma + srf * cmc + cme; - mvf = sre * cmb + srf * cmd + cmf; - - renderer.setRenderer(shapeBatch, null, renderTarget); - - for (var cmdIndex = 0, cmdLength = commandBuffer.length; cmdIndex < cmdLength; ++cmdIndex) - { - cmd = commandBuffer[cmdIndex]; - - switch (cmd) - { - case Commands.ARC: - iteration = 0; - x = commandBuffer[cmdIndex + 1]; - y = commandBuffer[cmdIndex + 2]; - radius = commandBuffer[cmdIndex + 3]; - startAngle = commandBuffer[cmdIndex + 4]; - endAngle = commandBuffer[cmdIndex + 5]; - anticlockwise = commandBuffer[cmdIndex + 6]; - - if (anticlockwise) - { - ta = endAngle; - endAngle = startAngle; - startAngle = -ta; - } - - while (iteration < 1) - { - ta = (endAngle - startAngle) * iteration + startAngle; - tx = x + cos(ta) * radius; - ty = y + sin(ta) * radius; - - if (iteration === 0) - { - lastPath = new Path(tx, ty, lineWidth, lineColor, lineAlpha); - pathArray.push(lastPath); - } - else - { - lastPath.points.push(new Point(tx, ty, lineWidth, lineColor, lineAlpha)); - } - - iteration += iterStep; - } - cmdIndex += 6; - break; - - case Commands.LINE_STYLE: - lineWidth = commandBuffer[cmdIndex + 1]; - lineColor = commandBuffer[cmdIndex + 2]; - lineAlpha = commandBuffer[cmdIndex + 3]; - cmdIndex += 3; - break; - - case Commands.FILL_STYLE: - fillColor = commandBuffer[cmdIndex + 1]; - fillAlpha = commandBuffer[cmdIndex + 2]; - cmdIndex += 2; - break; - - case Commands.BEGIN_PATH: - pathArray.length = 0; - break; - - case Commands.CLOSE_PATH: - if (lastPath !== null && lastPath.points.length > 0) - { - var firstPoint = lastPath.points[0]; - var lastPoint = lastPath.points[lastPath.points.length - 1]; - lastPath.points.push(firstPoint); - lastPath = new Path(lastPoint.x, lastPoint.y, lastPoint.width, lastPoint.rgb, lastPoint.alpha); - pathArray.push(lastPath); - } - break; - - case Commands.FILL_PATH: - for (var pathArrayIndex = 0, pathArrayLength = pathArray.length; - pathArrayIndex < pathArrayLength; - ++pathArrayIndex) - { - shapeBatch.addFillPath( - /* Graphics Game Object Properties */ - srcX, srcY, srcScaleX, srcScaleY, srcRotation, - /* Rectangle properties */ - pathArray[pathArrayIndex].points, - fillColor, - fillAlpha, - /* Transform */ - mva, mvb, mvc, mvd, mve, mvf, - currentMatrix - ); - } - break; - - case Commands.STROKE_PATH: - for (var pathArrayIndex = 0, pathArrayLength = pathArray.length; - pathArrayIndex < pathArrayLength; - ++pathArrayIndex) - { - path = pathArray[pathArrayIndex]; - shapeBatch.addStrokePath( - /* Graphics Game Object Properties */ - srcX, srcY, srcScaleX, srcScaleY, srcRotation, - /* Rectangle properties */ - path.points, - lineWidth, - lineColor, - lineAlpha, - /* Transform */ - mva, mvb, mvc, mvd, mve, mvf, - path === this._lastPath, - currentMatrix - ); - } - break; - - case Commands.FILL_RECT: - shapeBatch.addFillRect( - /* Graphics Game Object Properties */ - srcX, srcY, srcScaleX, srcScaleY, srcRotation, - /* Rectangle properties */ - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2], - commandBuffer[cmdIndex + 3], - commandBuffer[cmdIndex + 4], - fillColor, - fillAlpha, - /* Transform */ - mva, mvb, mvc, mvd, mve, mvf, - currentMatrix - ); - - cmdIndex += 4; - break; - - case Commands.FILL_TRIANGLE: - shapeBatch.addFillTriangle( - /* Graphics Game Object Properties */ - srcX, srcY, srcScaleX, srcScaleY, srcRotation, - /* Triangle properties */ - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2], - commandBuffer[cmdIndex + 3], - commandBuffer[cmdIndex + 4], - commandBuffer[cmdIndex + 5], - commandBuffer[cmdIndex + 6], - fillColor, - fillAlpha, - /* Transform */ - mva, mvb, mvc, mvd, mve, mvf, - currentMatrix - ); - - cmdIndex += 6; - break; - - case Commands.STROKE_TRIANGLE: - shapeBatch.addStrokeTriangle( - /* Graphics Game Object Properties */ - srcX, srcY, srcScaleX, srcScaleY, srcRotation, - /* Triangle properties */ - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2], - commandBuffer[cmdIndex + 3], - commandBuffer[cmdIndex + 4], - commandBuffer[cmdIndex + 5], - commandBuffer[cmdIndex + 6], - lineWidth, - lineColor, - lineAlpha, - /* Transform */ - mva, mvb, mvc, mvd, mve, mvf, - currentMatrix - ); - - cmdIndex += 6; - break; - - case Commands.LINE_TO: - if (lastPath !== null) - { - lastPath.points.push(new Point(commandBuffer[cmdIndex + 1], commandBuffer[cmdIndex + 2], lineWidth, lineColor, lineAlpha)); - } - else - { - lastPath = new Path(commandBuffer[cmdIndex + 1], commandBuffer[cmdIndex + 2], lineWidth, lineColor, lineAlpha); - pathArray.push(lastPath); - } - cmdIndex += 2; - break; - - case Commands.MOVE_TO: - lastPath = new Path(commandBuffer[cmdIndex + 1], commandBuffer[cmdIndex + 2], lineWidth, lineColor, lineAlpha); - pathArray.push(lastPath); - cmdIndex += 2; - break; - - case Commands.LINE_FX_TO: - if (lastPath !== null) - { - lastPath.points.push(new Point( - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2], - commandBuffer[cmdIndex + 3], - commandBuffer[cmdIndex + 4], - commandBuffer[cmdIndex + 5] - )); - } - else - { - lastPath = new Path( - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2], - commandBuffer[cmdIndex + 3], - commandBuffer[cmdIndex + 4], - commandBuffer[cmdIndex + 5] - ); - pathArray.push(lastPath); - } - cmdIndex += 5; - break; - - case Commands.MOVE_FX_TO: - lastPath = new Path( - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2], - commandBuffer[cmdIndex + 3], - commandBuffer[cmdIndex + 4], - commandBuffer[cmdIndex + 5] - ); - pathArray.push(lastPath); - cmdIndex += 5; - break; - - case Commands.SAVE: - matrixStack[matrixStackLength + 0] = currentMatrix.matrix[0]; - matrixStack[matrixStackLength + 1] = currentMatrix.matrix[1]; - matrixStack[matrixStackLength + 2] = currentMatrix.matrix[2]; - matrixStack[matrixStackLength + 3] = currentMatrix.matrix[3]; - matrixStack[matrixStackLength + 4] = currentMatrix.matrix[4]; - matrixStack[matrixStackLength + 5] = currentMatrix.matrix[5]; - matrixStackLength += 6; - break; - - case Commands.RESTORE: - matrixStackLength -= 6; - currentMatrix.matrix[0] = matrixStack[matrixStackLength + 0]; - currentMatrix.matrix[1] = matrixStack[matrixStackLength + 1]; - currentMatrix.matrix[2] = matrixStack[matrixStackLength + 2]; - currentMatrix.matrix[3] = matrixStack[matrixStackLength + 3]; - currentMatrix.matrix[4] = matrixStack[matrixStackLength + 4]; - currentMatrix.matrix[5] = matrixStack[matrixStackLength + 5]; - break; - - case Commands.TRANSLATE: - currentMatrix.translate( - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2] - ); - cmdIndex += 2; - break; - - case Commands.SCALE: - currentMatrix.scale( - commandBuffer[cmdIndex + 1], - commandBuffer[cmdIndex + 2] - ); - cmdIndex += 2; - break; - - case Commands.ROTATE: - currentMatrix.rotate( - -commandBuffer[cmdIndex + 1] - ); - cmdIndex += 1; - break; - - default: - console.error('Phaser: Invalid Graphics Command ID ' + cmd); - break; - } - } - - currentMatrix.loadIdentity(); - pathArray.length = 0; + renderer.pipelines.FlatTintPipeline.batchGraphics(this, camera); }; module.exports = GraphicsWebGLRenderer; diff --git a/src/gameobjects/index.js b/src/gameobjects/index.js index c34f9fba2..e17dbb3f5 100644 --- a/src/gameobjects/index.js +++ b/src/gameobjects/index.js @@ -16,7 +16,7 @@ var GameObjects = { //Container: require('./container/Container'), //DynamicBitmapText: require('./bitmaptext/dynamic/DynamicBitmapText'), //DynamicTilemapLayer: require('./tilemap/dynamiclayer/DynamicTilemapLayer'), - //Graphics: require('./graphics/Graphics.js'), + Graphics: require('./graphics/Graphics.js'), //Group: require('./group/Group'), Image: require('./image/Image'), //Particles: require('./particles/ParticleEmitterManager'), @@ -37,7 +37,7 @@ var GameObjects = { Blitter: require('./blitter/BlitterFactory'), //Container: require('./container/ContainerFactory'), //DynamicBitmapText: require('./bitmaptext/dynamic/DynamicBitmapTextFactory'), - //Graphics: require('./graphics/GraphicsFactory'), + Graphics: require('./graphics/GraphicsFactory'), //Group: require('./group/GroupFactory'), Image: require('./image/ImageFactory'), //Particles: require('./particles/ParticleManagerFactory'), @@ -55,7 +55,7 @@ var GameObjects = { Blitter: require('./blitter/BlitterCreator'), //Container: require('./container/ContainerCreator'), //DynamicBitmapText: require('./bitmaptext/dynamic/DynamicBitmapTextCreator'), - //Graphics: require('./graphics/GraphicsCreator'), + Graphics: require('./graphics/GraphicsCreator'), //Group: require('./group/GroupCreator'), Image: require('./image/ImageCreator'), //Particles: require('./particles/ParticleManagerCreator'), @@ -77,12 +77,10 @@ if (WEBGL_RENDERER) GameObjects.Mesh = require('./mesh/Mesh'); GameObjects.Quad = require('./quad/Quad'); - //GameObjects.Factories.EffectLayer = require('./effectlayer/EffectLayerFactory'); //GameObjects.Factories.LightLayer = require('./lightlayer/LightLayerFactory'); GameObjects.Factories.Mesh = require('./mesh/MeshFactory'); GameObjects.Factories.Quad = require('./quad/QuadFactory'); - //GameObjects.Creators.EffectLayer = require('./effectlayer/EffectLayerCreator'); //GameObjects.Creators.LightLayer = require('./lightlayer/LightLayerCreator'); GameObjects.Creators.Mesh = require('./mesh/MeshCreator'); GameObjects.Creators.Quad = require('./quad/QuadCreator'); diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index fe4d3d9ae..40686583a 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -632,7 +632,7 @@ var WebGLRenderer = new Class({ } else { - this.setTexture2D(dstTexture); + this.setTexture2D(dstTexture, 0); if (!shouldReallocate) { @@ -645,7 +645,7 @@ var WebGLRenderer = new Class({ dstTexture.height = srcCanvas.height; } - this.setTexture2D(null); + this.setTexture2D(null, 0); } return dstTexture; diff --git a/src/renderer/webgl/pipelines/FlatTintPipeline.js b/src/renderer/webgl/pipelines/FlatTintPipeline.js index 2a3fc6f4e..842e0c56f 100644 --- a/src/renderer/webgl/pipelines/FlatTintPipeline.js +++ b/src/renderer/webgl/pipelines/FlatTintPipeline.js @@ -4,6 +4,28 @@ var Utils = require('../Utils'); var Earcut = require('../../../geom/polygon/Earcut'); var ShaderSourceVS = require('../shaders/FlatTint.vert'); var ShaderSourceFS = require('../shaders/FlatTint.frag'); +var Commands = require('../../../gameobjects/graphics/Commands'); + +var Point = function (x, y, width, rgb, alpha) +{ + this.x = x; + this.y = y; + this.width = width; + this.rgb = rgb; + this.alpha = alpha; +}; + +var Path = function (x, y, width, rgb, alpha) +{ + this.points = []; + this.pointsLength = 1; + this.points[0] = new Point(x, y, width, rgb, alpha); +}; + +var currentMatrix = new Float32Array([1, 0, 0, 1, 0, 0]); +var matrixStack = new Float32Array(6 * 1000); +var matrixStackLength = 0; +var pathArray = []; var FlatTintPipeline = new Class({ @@ -75,6 +97,7 @@ var FlatTintPipeline = new Class({ {x: 0, y: 0, width: 0, rgb: 0xFFFFFF, alpha: 1.0}, {x: 0, y: 0, width: 0, rgb: 0xFFFFFF, alpha: 1.0} ]; + this.polygonCache = []; }, resize: function (width, height, resolution) @@ -91,23 +114,25 @@ var FlatTintPipeline = new Class({ }, batchFillRect: function (srcX, srcY, srcScaleX, srcScaleY, srcRotation, x, y, width, height, fillColor, fillAlpha, a1, b1, c1, d1, e1, f1, currentMatrix) - { + { + this.renderer.setPipeline(this); + if (this.vertexCount + 6 > this.vertexCapacity) { this.flush(); } - var vertexBufferF32 = this.vertexViewF32; - var vertexBufferU32 = this.vertexViewU32; + var vertexViewF32 = this.vertexViewF32; + var vertexViewU32 = this.vertexViewU32; var vertexOffset = this.vertexCount * this.vertexComponentCount; var xw = x + width; var yh = y + height; - var a0 = currentMatrix.matrix[0]; - var b0 = currentMatrix.matrix[1]; - var c0 = currentMatrix.matrix[2]; - var d0 = currentMatrix.matrix[3]; - var e0 = currentMatrix.matrix[4]; - var f0 = currentMatrix.matrix[5]; + var a0 = currentMatrix[0]; + var b0 = currentMatrix[1]; + var c0 = currentMatrix[2]; + var d0 = currentMatrix[3]; + var e0 = currentMatrix[4]; + var f0 = currentMatrix[5]; var a = a1 * a0 + b1 * c0; var b = a1 * b0 + b1 * d0; var c = c1 * a0 + d1 * c0; @@ -124,44 +149,46 @@ var FlatTintPipeline = new Class({ var ty3 = xw * b + y * d + f; var tint = Utils.getTintAppendFloatAlpha(fillColor, fillAlpha); - vertexBufferF32[vertexOffset + 0] = tx0; - vertexBufferF32[vertexOffset + 1] = ty0; - vertexBufferU32[vertexOffset + 2] = tint; - vertexBufferF32[vertexOffset + 3] = tx1; - vertexBufferF32[vertexOffset + 4] = ty1; - vertexBufferU32[vertexOffset + 5] = tint; - vertexBufferF32[vertexOffset + 6] = tx2; - vertexBufferF32[vertexOffset + 7] = ty2; - vertexBufferU32[vertexOffset + 8] = tint; - vertexBufferF32[vertexOffset + 9] = tx0; - vertexBufferF32[vertexOffset + 10] = ty0; - vertexBufferU32[vertexOffset + 11] = tint; - vertexBufferF32[vertexOffset + 12] = tx2; - vertexBufferF32[vertexOffset + 13] = ty2; - vertexBufferU32[vertexOffset + 14] = tint; - vertexBufferF32[vertexOffset + 15] = tx3; - vertexBufferF32[vertexOffset + 16] = ty3; - vertexBufferU32[vertexOffset + 17] = tint; + vertexViewF32[vertexOffset + 0] = tx0; + vertexViewF32[vertexOffset + 1] = ty0; + vertexViewU32[vertexOffset + 2] = tint; + vertexViewF32[vertexOffset + 3] = tx1; + vertexViewF32[vertexOffset + 4] = ty1; + vertexViewU32[vertexOffset + 5] = tint; + vertexViewF32[vertexOffset + 6] = tx2; + vertexViewF32[vertexOffset + 7] = ty2; + vertexViewU32[vertexOffset + 8] = tint; + vertexViewF32[vertexOffset + 9] = tx0; + vertexViewF32[vertexOffset + 10] = ty0; + vertexViewU32[vertexOffset + 11] = tint; + vertexViewF32[vertexOffset + 12] = tx2; + vertexViewF32[vertexOffset + 13] = ty2; + vertexViewU32[vertexOffset + 14] = tint; + vertexViewF32[vertexOffset + 15] = tx3; + vertexViewF32[vertexOffset + 16] = ty3; + vertexViewU32[vertexOffset + 17] = tint; this.vertexCount += 6; }, batchFillTriangle: function (srcX, srcY, srcScaleX, srcScaleY, srcRotation, x0, y0, x1, y1, x2, y2, fillColor, fillAlpha, a1, b1, c1, d1, e1, f1, currentMatrix) { + this.renderer.setPipeline(this); + if (this.vertexCount + 3 > this.vertexCapacity) { this.flush(); } - var vertexBufferF32 = this.vertexViewF32; - var vertexBufferU32 = this.vertexViewU32; + var vertexViewF32 = this.vertexViewF32; + var vertexViewU32 = this.vertexViewU32; var vertexOffset = this.vertexCount * this.vertexComponentCount; - var a0 = currentMatrix.matrix[0]; - var b0 = currentMatrix.matrix[1]; - var c0 = currentMatrix.matrix[2]; - var d0 = currentMatrix.matrix[3]; - var e0 = currentMatrix.matrix[4]; - var f0 = currentMatrix.matrix[5]; + var a0 = currentMatrix[0]; + var b0 = currentMatrix[1]; + var c0 = currentMatrix[2]; + var d0 = currentMatrix[3]; + var e0 = currentMatrix[4]; + var f0 = currentMatrix[5]; var a = a1 * a0 + b1 * c0; var b = a1 * b0 + b1 * d0; var c = c1 * a0 + d1 * c0; @@ -176,21 +203,22 @@ var FlatTintPipeline = new Class({ var ty2 = x2 * b + y2 * d + f; var tint = Utils.getTintAppendFloatAlpha(fillColor, fillAlpha); - vertexBufferF32[vertexOffset + 0] = tx0; - vertexBufferF32[vertexOffset + 1] = ty0; - vertexBufferU32[vertexOffset + 2] = tint; - vertexBufferF32[vertexOffset + 3] = tx1; - vertexBufferF32[vertexOffset + 4] = ty1; - vertexBufferU32[vertexOffset + 5] = tint; - vertexBufferF32[vertexOffset + 6] = tx2; - vertexBufferF32[vertexOffset + 7] = ty2; - vertexBufferU32[vertexOffset + 8] = tint; + vertexViewF32[vertexOffset + 0] = tx0; + vertexViewF32[vertexOffset + 1] = ty0; + vertexViewU32[vertexOffset + 2] = tint; + vertexViewF32[vertexOffset + 3] = tx1; + vertexViewF32[vertexOffset + 4] = ty1; + vertexViewU32[vertexOffset + 5] = tint; + vertexViewF32[vertexOffset + 6] = tx2; + vertexViewF32[vertexOffset + 7] = ty2; + vertexViewU32[vertexOffset + 8] = tint; this.vertexCount += 3; }, batchStrokeTriangle: function (srcX, srcY, srcScaleX, srcScaleY, srcRotation, x0, y0, x1, y1, x2, y2, lineWidth, lineColor, lineAlpha, a, b, c, d, e, f, currentMatrix) { + var tempTriangle = this.tempTriangle; tempTriangle[0].x = x0; @@ -214,7 +242,7 @@ var FlatTintPipeline = new Class({ tempTriangle[3].rgb = lineColor; tempTriangle[3].alpha = lineAlpha; - this.addStrokePath( + this.batchStrokePath( srcX, srcY, srcScaleX, srcScaleY, srcRotation, tempTriangle, lineWidth, lineColor, lineAlpha, a, b, c, d, e, f, @@ -225,16 +253,576 @@ var FlatTintPipeline = new Class({ batchFillPath: function (srcX, srcY, srcScaleX, srcScaleY, srcRotation, path, fillColor, fillAlpha, a1, b1, c1, d1, e1, f1, currentMatrix) { + this.renderer.setPipeline(this); + var length = path.length; + var polygonCache = this.polygonCache; + var polygonIndexArray; + var point; + var v0, v1, v2; + var vertexViewF32 = this.vertexViewF32; + var vertexViewU32 = this.vertexViewU32; + var vertexOffset = 0; + var x0, y0, x1, y1, x2, y2; + var tx0, ty0, tx1, ty1, tx2, ty2; + var a0 = currentMatrix[0]; + var b0 = currentMatrix[1]; + var c0 = currentMatrix[2]; + var d0 = currentMatrix[3]; + var e0 = currentMatrix[4]; + var f0 = currentMatrix[5]; + var a = a1 * a0 + b1 * c0; + var b = a1 * b0 + b1 * d0; + var c = c1 * a0 + d1 * c0; + var d = c1 * b0 + d1 * d0; + var e = e1 * a0 + f1 * c0 + e0; + var f = e1 * b0 + f1 * d0 + f0; + var tint = Utils.getTintAppendFloatAlpha(fillColor, fillAlpha); + + for (var pathIndex = 0; pathIndex < length; ++pathIndex) + { + point = path[pathIndex]; + polygonCache.push(point.x, point.y); + } + + polygonIndexArray = Earcut(polygonCache); + length = polygonIndexArray.length; + + for (var index = 0; index < length; index += 3) + { + v0 = polygonIndexArray[index + 0] * 2; + v1 = polygonIndexArray[index + 1] * 2; + v2 = polygonIndexArray[index + 2] * 2; + + if (this.vertexCount + 3 > this.vertexCapacity) + { + this.flush(); + } + + vertexOffset = this.vertexCount * this.vertexComponentCount; + + x0 = polygonCache[v0 + 0]; + y0 = polygonCache[v0 + 1]; + x1 = polygonCache[v1 + 0]; + y1 = polygonCache[v1 + 1]; + x2 = polygonCache[v2 + 0]; + y2 = polygonCache[v2 + 1]; + + tx0 = x0 * a + y0 * c + e; + ty0 = x0 * b + y0 * d + f; + tx1 = x1 * a + y1 * c + e; + ty1 = x1 * b + y1 * d + f; + tx2 = x2 * a + y2 * c + e; + ty2 = x2 * b + y2 * d + f; + + vertexViewF32[vertexOffset + 0] = tx0; + vertexViewF32[vertexOffset + 1] = ty0; + vertexViewU32[vertexOffset + 2] = tint; + vertexViewF32[vertexOffset + 3] = tx1; + vertexViewF32[vertexOffset + 4] = ty1; + vertexViewU32[vertexOffset + 5] = tint; + vertexViewF32[vertexOffset + 6] = tx2; + vertexViewF32[vertexOffset + 7] = ty2; + vertexViewU32[vertexOffset + 8] = tint; + + this.vertexCount += 3; + } + + polygonCache.length = 0; }, batchStrokePath: function (srcX, srcY, srcScaleX, srcScaleY, srcRotation, path, lineWidth, lineColor, lineAlpha, a, b, c, d, e, f, isLastPath, currentMatrix) { + this.renderer.setPipeline(this); + + var point0, point1; + var pathLength = path.length; + var polylines = this.polygonCache; + var last, curr; + var vertexViewF32 = this.vertexViewF32; + var vertexViewU32 = this.vertexViewU32; + var vertexOffset; + var line; + var getTint = Utils.getTintAppendFloatAlpha; + + for (var pathIndex = 0; pathIndex + 1 < pathLength; pathIndex += 1) + { + point0 = path[pathIndex]; + point1 = path[pathIndex + 1]; + + line = this.batchLine( + srcX, srcY, srcScaleX, srcScaleY, srcRotation, + point0.x, point0.y, + point1.x, point1.y, + point0.width / 2, point1.width / 2, + point0.rgb, point1.rgb, lineAlpha, + a, b, c, d, e, f, + currentMatrix + ); + + polylines.push(line); + } + + /* Render joints */ + for (var index = 1, polylinesLength = polylines.length; index < polylinesLength; ++index) + { + if (this.vertexCount + 6 > this.vertexCapacity) + { + this.flush(); + } + + last = polylines[index - 1] || polylines[polylinesLength - 1]; + curr = polylines[index]; + vertexOffset = this.vertexCount * this.vertexComponentCount; + + vertexViewF32[vertexOffset + 0] = last[3 * 2 + 0]; + vertexViewF32[vertexOffset + 1] = last[3 * 2 + 1]; + vertexViewU32[vertexOffset + 2] = getTint(last[3 * 2 + 2], lineAlpha); + vertexViewF32[vertexOffset + 3] = last[3 * 0 + 0]; + vertexViewF32[vertexOffset + 4] = last[3 * 0 + 1]; + vertexViewU32[vertexOffset + 5] = getTint(last[3 * 0 + 2], lineAlpha); + vertexViewF32[vertexOffset + 6] = curr[3 * 3 + 0]; + vertexViewF32[vertexOffset + 7] = curr[3 * 3 + 1]; + vertexViewU32[vertexOffset + 8] = getTint(curr[3 * 3 + 2], lineAlpha); + vertexViewF32[vertexOffset + 9] = last[3 * 0 + 0]; + vertexViewF32[vertexOffset + 10] = last[3 * 0 + 1]; + vertexViewU32[vertexOffset + 11] = getTint(last[3 * 0 + 2], lineAlpha); + vertexViewF32[vertexOffset + 12] = last[3 * 2 + 0]; + vertexViewF32[vertexOffset + 13] = last[3 * 2 + 1]; + vertexViewU32[vertexOffset + 14] = getTint(last[3 * 2 + 2], lineAlpha); + vertexViewF32[vertexOffset + 15] = curr[3 * 1 + 0]; + vertexViewF32[vertexOffset + 16] = curr[3 * 1 + 1]; + vertexViewU32[vertexOffset + 17] = getTint(curr[3 * 1 + 2], lineAlpha); + + this.vertexCount += 6; + } + + polylines.length = 0; }, batchLine: function (srcX, srcY, srcScaleX, srcScaleY, srcRotation, ax, ay, bx, by, aLineWidth, bLineWidth, aLineColor, bLineColor, lineAlpha, a1, b1, c1, d1, e1, f1, currentMatrix) { + this.renderer.setPipeline(this); + + if (this.vertexCount + 6 > this.vertexCapacity) + { + this.flush(); + } + + var a0 = currentMatrix[0]; + var b0 = currentMatrix[1]; + var c0 = currentMatrix[2]; + var d0 = currentMatrix[3]; + var e0 = currentMatrix[4]; + var f0 = currentMatrix[5]; + var a = a1 * a0 + b1 * c0; + var b = a1 * b0 + b1 * d0; + var c = c1 * a0 + d1 * c0; + var d = c1 * b0 + d1 * d0; + var e = e1 * a0 + f1 * c0 + e0; + var f = e1 * b0 + f1 * d0 + f0; + var vertexViewF32 = this.vertexViewF32; + var vertexViewU32 = this.vertexViewU32; + var dx = bx - ax; + var dy = by - ay; + var len = Math.sqrt(dx * dx + dy * dy); + var al0 = aLineWidth * (by - ay) / len; + var al1 = aLineWidth * (ax - bx) / len; + var bl0 = bLineWidth * (by - ay) / len; + var bl1 = bLineWidth * (ax - bx) / len; + var lx0 = bx - bl0; + var ly0 = by - bl1; + var lx1 = ax - al0; + var ly1 = ay - al1; + var lx2 = bx + bl0; + var ly2 = by + bl1; + var lx3 = ax + al0; + var ly3 = ay + al1; + var x0 = lx0 * a + ly0 * c + e; + var y0 = lx0 * b + ly0 * d + f; + var x1 = lx1 * a + ly1 * c + e; + var y1 = lx1 * b + ly1 * d + f; + var x2 = lx2 * a + ly2 * c + e; + var y2 = lx2 * b + ly2 * d + f; + var x3 = lx3 * a + ly3 * c + e; + var y3 = lx3 * b + ly3 * d + f; + var getTint = Utils.getTintAppendFloatAlpha; + var aTint = getTint(aLineColor, lineAlpha); + var bTint = getTint(bLineColor, lineAlpha); + var vertexOffset = this.vertexCount * this.vertexComponentCount; + + vertexViewF32[vertexOffset + 0] = x0; + vertexViewF32[vertexOffset + 1] = y0; + vertexViewU32[vertexOffset + 2] = bTint; + vertexViewF32[vertexOffset + 3] = x1; + vertexViewF32[vertexOffset + 4] = y1; + vertexViewU32[vertexOffset + 5] = aTint; + vertexViewF32[vertexOffset + 6] = x2; + vertexViewF32[vertexOffset + 7] = y2; + vertexViewU32[vertexOffset + 8] = bTint + vertexViewF32[vertexOffset + 9] = x1; + vertexViewF32[vertexOffset + 10] = y1; + vertexViewU32[vertexOffset + 11] = aTint; + vertexViewF32[vertexOffset + 12] = x3; + vertexViewF32[vertexOffset + 13] = y3; + vertexViewU32[vertexOffset + 14] = aTint; + vertexViewF32[vertexOffset + 15] = x2; + vertexViewF32[vertexOffset + 16] = y2; + vertexViewU32[vertexOffset + 17] = bTint; + + this.vertexCount += 6; + + return [ + x0, y0, bLineColor, + x1, y1, aLineColor, + x2, y2, bLineColor, + x3, y3, aLineColor + ]; + }, + + batchGraphics: function (graphics, camera) + { + this.renderer.setPipeline(this); + + var cameraScrollX = camera.scrollX * graphics.scrollFactorX; + var cameraScrollY = camera.scrollY * graphics.scrollFactorY; + var srcX = graphics.x - cameraScrollX; + var srcY = graphics.y - cameraScrollY; + var srcScaleX = graphics.scaleX; + var srcScaleY = graphics.scaleY; + var srcRotation = -graphics.rotation; + var commands = graphics.commandBuffer; + var lineAlpha = 1.0; + var fillAlpha = 1.0; + var lineColor = 0; + var fillColor = 0; + var lineWidth = 1.0; + var cameraMatrix = camera.matrix.matrix; + var lastPath = null; + var iteration = 0; + var iterStep = 0.01; + var tx = 0; + var ty = 0; + var ta = 0; + var x = 0; + var y = 0; + var radius = 0; + var startAngle = 0; + var endAngle = 0; + var anticlockwise = 0; + var path = null; + var sin = Math.sin; + var cos = Math.cos; + var sr = sin(srcRotation); + var cr = cos(srcRotation); + var sra = cr * srcScaleX; + var srb = -sr * srcScaleX; + var src = sr * srcScaleY; + var srd = cr * srcScaleY; + var sre = srcX; + var srf = srcY; + var cma = cameraMatrix[0]; + var cmb = cameraMatrix[1]; + var cmc = cameraMatrix[2]; + var cmd = cameraMatrix[3]; + var cme = cameraMatrix[4]; + var cmf = cameraMatrix[5]; + var mva = sra * cma + srb * cmc; + var mvb = sra * cmb + srb * cmd; + var mvc = src * cma + srd * cmc; + var mvd = src * cmb + srd * cmd; + var mve = sre * cma + srf * cmc + cme; + var mvf = sre * cmb + srf * cmd + cmf; + + for (var cmdIndex = 0, cmdLength = commands.length; cmdIndex < cmdLength; ++cmdIndex) + { + cmd = commands[cmdIndex]; + + switch (cmd) + { + case Commands.ARC: + iteration = 0; + x = commands[cmdIndex + 1]; + y = commands[cmdIndex + 2]; + radius = commands[cmdIndex + 3]; + startAngle = commands[cmdIndex + 4]; + endAngle = commands[cmdIndex + 5]; + anticlockwise = commands[cmdIndex + 6]; + + if (anticlockwise) + { + ta = endAngle; + endAngle = startAngle; + startAngle = -ta; + } + + while (iteration < 1) + { + ta = (endAngle - startAngle) * iteration + startAngle; + tx = x + cos(ta) * radius; + ty = y + sin(ta) * radius; + + if (iteration === 0) + { + lastPath = new Path(tx, ty, lineWidth, lineColor, lineAlpha); + pathArray.push(lastPath); + } + else + { + lastPath.points.push(new Point(tx, ty, lineWidth, lineColor, lineAlpha)); + } + + iteration += iterStep; + } + cmdIndex += 6; + break; + + case Commands.LINE_STYLE: + lineWidth = commands[cmdIndex + 1]; + lineColor = commands[cmdIndex + 2]; + lineAlpha = commands[cmdIndex + 3]; + cmdIndex += 3; + break; + + case Commands.FILL_STYLE: + fillColor = commands[cmdIndex + 1]; + fillAlpha = commands[cmdIndex + 2]; + cmdIndex += 2; + break; + + case Commands.BEGIN_PATH: + pathArray.length = 0; + break; + + case Commands.CLOSE_PATH: + if (lastPath !== null && lastPath.points.length > 0) + { + var firstPoint = lastPath.points[0]; + var lastPoint = lastPath.points[lastPath.points.length - 1]; + lastPath.points.push(firstPoint); + lastPath = new Path(lastPoint.x, lastPoint.y, lastPoint.width, lastPoint.rgb, lastPoint.alpha); + pathArray.push(lastPath); + } + break; + + case Commands.FILL_PATH: + for (var pathArrayIndex = 0, pathArrayLength = pathArray.length; + pathArrayIndex < pathArrayLength; + ++pathArrayIndex) + { + this.batchFillPath( + /* Graphics Game Object Properties */ + srcX, srcY, srcScaleX, srcScaleY, srcRotation, + /* Rectangle properties */ + pathArray[pathArrayIndex].points, + fillColor, + fillAlpha, + /* Transform */ + mva, mvb, mvc, mvd, mve, mvf, + currentMatrix + ); + } + break; + + case Commands.STROKE_PATH: + for (var pathArrayIndex = 0, pathArrayLength = pathArray.length; + pathArrayIndex < pathArrayLength; + ++pathArrayIndex) + { + path = pathArray[pathArrayIndex]; + this.batchStrokePath( + /* Graphics Game Object Properties */ + srcX, srcY, srcScaleX, srcScaleY, srcRotation, + /* Rectangle properties */ + path.points, + lineWidth, + lineColor, + lineAlpha, + /* Transform */ + mva, mvb, mvc, mvd, mve, mvf, + path === this._lastPath, + currentMatrix + ); + } + break; + + case Commands.FILL_RECT: + this.batchFillRect( + /* Graphics Game Object Properties */ + srcX, srcY, srcScaleX, srcScaleY, srcRotation, + /* Rectangle properties */ + commands[cmdIndex + 1], + commands[cmdIndex + 2], + commands[cmdIndex + 3], + commands[cmdIndex + 4], + fillColor, + fillAlpha, + /* Transform */ + mva, mvb, mvc, mvd, mve, mvf, + currentMatrix + ); + + cmdIndex += 4; + break; + + case Commands.FILL_TRIANGLE: + this.batchFillTriangle( + /* Graphics Game Object Properties */ + srcX, srcY, srcScaleX, srcScaleY, srcRotation, + /* Triangle properties */ + commands[cmdIndex + 1], + commands[cmdIndex + 2], + commands[cmdIndex + 3], + commands[cmdIndex + 4], + commands[cmdIndex + 5], + commands[cmdIndex + 6], + fillColor, + fillAlpha, + /* Transform */ + mva, mvb, mvc, mvd, mve, mvf, + currentMatrix + ); + + cmdIndex += 6; + break; + + case Commands.STROKE_TRIANGLE: + this.batchStrokeTriangle( + /* Graphics Game Object Properties */ + srcX, srcY, srcScaleX, srcScaleY, srcRotation, + /* Triangle properties */ + commands[cmdIndex + 1], + commands[cmdIndex + 2], + commands[cmdIndex + 3], + commands[cmdIndex + 4], + commands[cmdIndex + 5], + commands[cmdIndex + 6], + lineWidth, + lineColor, + lineAlpha, + /* Transform */ + mva, mvb, mvc, mvd, mve, mvf, + currentMatrix + ); + + cmdIndex += 6; + break; + + case Commands.LINE_TO: + if (lastPath !== null) + { + lastPath.points.push(new Point(commands[cmdIndex + 1], commands[cmdIndex + 2], lineWidth, lineColor, lineAlpha)); + } + else + { + lastPath = new Path(commands[cmdIndex + 1], commands[cmdIndex + 2], lineWidth, lineColor, lineAlpha); + pathArray.push(lastPath); + } + cmdIndex += 2; + break; + + case Commands.MOVE_TO: + lastPath = new Path(commands[cmdIndex + 1], commands[cmdIndex + 2], lineWidth, lineColor, lineAlpha); + pathArray.push(lastPath); + cmdIndex += 2; + break; + + case Commands.LINE_FX_TO: + if (lastPath !== null) + { + lastPath.points.push(new Point( + commands[cmdIndex + 1], + commands[cmdIndex + 2], + commands[cmdIndex + 3], + commands[cmdIndex + 4], + commands[cmdIndex + 5] + )); + } + else + { + lastPath = new Path( + commands[cmdIndex + 1], + commands[cmdIndex + 2], + commands[cmdIndex + 3], + commands[cmdIndex + 4], + commands[cmdIndex + 5] + ); + pathArray.push(lastPath); + } + cmdIndex += 5; + break; + + case Commands.MOVE_FX_TO: + lastPath = new Path( + commands[cmdIndex + 1], + commands[cmdIndex + 2], + commands[cmdIndex + 3], + commands[cmdIndex + 4], + commands[cmdIndex + 5] + ); + pathArray.push(lastPath); + cmdIndex += 5; + break; + + case Commands.SAVE: + matrixStack[matrixStackLength + 0] = currentMatrix[0]; + matrixStack[matrixStackLength + 1] = currentMatrix[1]; + matrixStack[matrixStackLength + 2] = currentMatrix[2]; + matrixStack[matrixStackLength + 3] = currentMatrix[3]; + matrixStack[matrixStackLength + 4] = currentMatrix[4]; + matrixStack[matrixStackLength + 5] = currentMatrix[5]; + matrixStackLength += 6; + break; + + case Commands.RESTORE: + matrixStackLength -= 6; + currentMatrix[0] = matrixStack[matrixStackLength + 0]; + currentMatrix[1] = matrixStack[matrixStackLength + 1]; + currentMatrix[2] = matrixStack[matrixStackLength + 2]; + currentMatrix[3] = matrixStack[matrixStackLength + 3]; + currentMatrix[4] = matrixStack[matrixStackLength + 4]; + currentMatrix[5] = matrixStack[matrixStackLength + 5]; + break; + + case Commands.TRANSLATE: + x = commands[cmdIndex + 1]; + y = commands[cmdIndex + 2]; + currentMatrix[4] = currentMatrix[0] * x + currentMatrix[2] * y + currentMatrix[4]; + currentMatrix[5] = currentMatrix[1] * x + currentMatrix[3] * y + currentMatrix[5]; + cmdIndex += 2; + break; + + case Commands.SCALE: + x = commands[cmdIndex + 1]; + y = commands[cmdIndex + 2]; + currentMatrix[0] *= x; + currentMatrix[1] *= x; + currentMatrix[2] *= y; + currentMatrix[3] *= y; + cmdIndex += 2; + break; + + case Commands.ROTATE: + y = commands[cmdIndex + 1]; + x = sin(y); + y = cos(y); + sra = currentMatrix[0]; + srb = currentMatrix[1]; + src = currentMatrix[2]; + srd = currentMatrix[3]; + currentMatrix[0] = y * sra + x * src; + currentMatrix[1] = y * srb + x * srd; + currentMatrix[2] = -x * sra + y * src; + currentMatrix[3] = -x * srb + y * srd; + cmdIndex += 1; + break; + + default: + console.error('Phaser: Invalid Graphics Command ID ' + cmd); + break; + } + } } diff --git a/src/renderer/webgl/shaders/FlatTint.frag b/src/renderer/webgl/shaders/FlatTint.frag index 103d9a503..892a4ba0f 100644 --- a/src/renderer/webgl/shaders/FlatTint.frag +++ b/src/renderer/webgl/shaders/FlatTint.frag @@ -5,5 +5,5 @@ precision mediump float; varying vec4 outTint; void main() { - gl_FragColor = vec4(outTint.bgr * outTint.a, outTint.a); + gl_FragColor = vec4(outTint.rgb * outTint.a, outTint.a); }