From 47b1d755a786b86e10f42efe91f24061371c2781 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Wed, 3 Jul 2019 11:11:25 +0100 Subject: [PATCH] Fixed a bug in the WebGL and Canvas Renderers where a Sprite with a `flipX` or `flipY` value set would render the offset frames slightly out of place, causing the animation to appear jittery. Also, the sprite would be out of place by its origin. Fix #4636 #3813 --- CHANGELOG.md | 1 + src/renderer/canvas/CanvasRenderer.js | 40 +++++++++++++------ .../webgl/pipelines/TextureTintPipeline.js | 38 ++++++++++-------- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de5474f22..87c33e516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ * The `Arc / Circle` Game Object wasn't rendering centered correctly in WebGL due to an issue in a previous size related commit, it would be half a radius off. Fix #4620 (thanks @CipSoft-Components @rexrainbow) * Destroying a Scene in HEADLESS mode would throw an error as it tried to access the gl renderer in the Camera class. Fix #4467 (thanks @AndreaBoeAbrahamsen @samme) * `Tilemap.createFromObjects` would ignore the `scene` argument passed in to the method. It's now used (thanks @samme) +* Fixed a bug in the WebGL and Canvas Renderers where a Sprite with a `flipX` or `flipY` value set would render the offset frames slightly out of place, causing the animation to appear jittery. Also, the sprite would be out of place by its origin. Fix #4636 #3813 (thanks @jronn @B3L7) ### Examples, Documentation and TypeScript diff --git a/src/renderer/canvas/CanvasRenderer.js b/src/renderer/canvas/CanvasRenderer.js index aaf4be318..280573b47 100644 --- a/src/renderer/canvas/CanvasRenderer.js +++ b/src/renderer/canvas/CanvasRenderer.js @@ -659,12 +659,12 @@ var CanvasRenderer = new Class({ var frameHeight = frame.cutHeight; var res = frame.source.resolution; - var x = -sprite.displayOriginX + frame.x; - var y = -sprite.displayOriginY + frame.y; + var displayOriginX = sprite.displayOriginX; + var displayOriginY = sprite.displayOriginY; + + var x = -displayOriginX + frame.x; + var y = -displayOriginY + frame.y; - var fx = (sprite.flipX) ? -1 : 1; - var fy = (sprite.flipY) ? -1 : 1; - if (sprite.isCropped) { var crop = sprite._crop; @@ -680,10 +680,10 @@ var CanvasRenderer = new Class({ frameX = crop.cx; frameY = crop.cy; - x = -sprite.displayOriginX + crop.x; - y = -sprite.displayOriginY + crop.y; + x = -displayOriginX + crop.x; + y = -displayOriginY + crop.y; - if (fx === -1) + if (sprite.flipX) { if (x >= 0) { @@ -695,7 +695,7 @@ var CanvasRenderer = new Class({ } } - if (fy === -1) + if (sprite.flipY) { if (y >= 0) { @@ -708,7 +708,25 @@ var CanvasRenderer = new Class({ } } - spriteMatrix.applyITRS(sprite.x, sprite.y, sprite.rotation, sprite.scaleX, sprite.scaleY); + var flipX = 1; + var flipY = 1; + + if (sprite.flipX) + { + x += (-frame.realWidth + (displayOriginX * 2)); + + flipX = -1; + } + + // Auto-invert the flipY if this is coming from a GLTexture + if (sprite.flipY) + { + y += (-frame.realHeight + (displayOriginY * 2)); + + flipY = -1; + } + + spriteMatrix.applyITRS(sprite.x, sprite.y, sprite.rotation, sprite.scaleX * flipX, sprite.scaleY * flipY); camMatrix.copyFrom(camera.matrix); @@ -737,8 +755,6 @@ var CanvasRenderer = new Class({ calcMatrix.setToContext(ctx); - ctx.scale(fx, fy); - ctx.globalCompositeOperation = this.blendModes[sprite.blendMode]; ctx.globalAlpha = alpha; diff --git a/src/renderer/webgl/pipelines/TextureTintPipeline.js b/src/renderer/webgl/pipelines/TextureTintPipeline.js index e6c8f7767..8e847495b 100644 --- a/src/renderer/webgl/pipelines/TextureTintPipeline.js +++ b/src/renderer/webgl/pipelines/TextureTintPipeline.js @@ -534,8 +534,11 @@ var TextureTintPipeline = new Class({ var frameWidth = frame.cutWidth; var frameHeight = frame.cutHeight; - var x = -sprite.displayOriginX + frameX; - var y = -sprite.displayOriginY + frameY; + var displayOriginX = sprite.displayOriginX; + var displayOriginY = sprite.displayOriginY; + + var x = -displayOriginX + frameX; + var y = -displayOriginY + frameY; if (sprite.isCropped) { @@ -557,29 +560,29 @@ var TextureTintPipeline = new Class({ frameX = crop.x; frameY = crop.y; - x = -sprite.displayOriginX + frameX; - y = -sprite.displayOriginY + frameY; + x = -displayOriginX + frameX; + y = -displayOriginY + frameY; } + var flipX = 1; + var flipY = 1; + if (sprite.flipX) { - x += frameWidth; - frameWidth *= -1; + x += (-frame.realWidth + (displayOriginX * 2)); + + flipX = -1; } - // Invert the flipY if this is coming from a GLTexture - var flipY = sprite.flipY ^ ((frame.source.isGLTexture && !texture.flipY) ? 1 : 0); - - if (flipY) + // Auto-invert the flipY if this is coming from a GLTexture + if (sprite.flipY || (frame.source.isGLTexture && !texture.flipY)) { - y += frameHeight; - frameHeight *= -1; + y += (-frame.realHeight + (displayOriginY * 2)); + + flipY = -1; } - var xw = x + frameWidth; - var yh = y + frameHeight; - - spriteMatrix.applyITRS(sprite.x, sprite.y, sprite.rotation, sprite.scaleX, sprite.scaleY); + spriteMatrix.applyITRS(sprite.x, sprite.y, sprite.rotation, sprite.scaleX * flipX, sprite.scaleY * flipY); camMatrix.copyFrom(camera.matrix); @@ -604,6 +607,9 @@ var TextureTintPipeline = new Class({ camMatrix.multiply(spriteMatrix, calcMatrix); } + var xw = x + frameWidth; + var yh = y + frameHeight; + var tx0 = calcMatrix.getX(x, y); var ty0 = calcMatrix.getY(x, y);