From 1a65f50a25d62664f34a8a110115b36b666e39da Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 11 Dec 2020 13:40:53 +0000 Subject: [PATCH] Added new `renderDirect` hook which RenderTexture can use. Fix #5431 --- .../src/gameobject/SpineGameObjectRender.js | 5 +- .../gameobject/SpineGameObjectWebGLDirect.js | 131 ++++++++++++++++++ .../rendertexture/RenderTexture.js | 15 +- 3 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 plugins/spine/src/gameobject/SpineGameObjectWebGLDirect.js diff --git a/plugins/spine/src/gameobject/SpineGameObjectRender.js b/plugins/spine/src/gameobject/SpineGameObjectRender.js index f89d408e2..9acc2bc11 100644 --- a/plugins/spine/src/gameobject/SpineGameObjectRender.js +++ b/plugins/spine/src/gameobject/SpineGameObjectRender.js @@ -6,10 +6,12 @@ var renderWebGL = require('../../../../src/utils/NOOP'); var renderCanvas = require('../../../../src/utils/NOOP'); +var renderDirect = require('../../../../src/utils/NOOP'); if (typeof WEBGL_RENDERER) { renderWebGL = require('./SpineGameObjectWebGLRenderer'); + renderDirect = require('./SpineGameObjectWebGLDirect'); } if (typeof CANVAS_RENDERER) @@ -20,6 +22,7 @@ if (typeof CANVAS_RENDERER) module.exports = { renderWebGL: renderWebGL, - renderCanvas: renderCanvas + renderCanvas: renderCanvas, + renderDirect: renderDirect }; diff --git a/plugins/spine/src/gameobject/SpineGameObjectWebGLDirect.js b/plugins/spine/src/gameobject/SpineGameObjectWebGLDirect.js new file mode 100644 index 000000000..07eb2430b --- /dev/null +++ b/plugins/spine/src/gameobject/SpineGameObjectWebGLDirect.js @@ -0,0 +1,131 @@ +/** + * @author Richard Davey + * @copyright 2020 Photon Storm Ltd. + * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} + */ + +var Clamp = require('../../../../src/math/Clamp'); +var CounterClockwise = require('../../../../src/math/angle/CounterClockwise'); +var GetCalcMatrix = require('../../../../src/gameobjects/GetCalcMatrix'); +var RadToDeg = require('../../../../src/math/RadToDeg'); +var Wrap = require('../../../../src/math/Wrap'); + +/** + * Directly renders this Game Object with the WebGL Renderer to the given Camera. + * The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera. + * This method should not be called directly. It is a utility function of the Render module. + * + * @method SpineGameObject#renderDirect + * @since 3.50.0 + * @private + * + * @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - A reference to the current active WebGL renderer. + * @param {SpineGameObject} src - The Game Object being rendered in this call. + * @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object. + * @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested + * @param {SpineContainer} [container] - If this Spine object is in a Spine Container, this is a reference to it. + */ +var SpineGameObjectWebGLDirect = function (renderer, src, camera, parentMatrix, container) +{ + var plugin = src.plugin; + var skeleton = src.skeleton; + var sceneRenderer = plugin.sceneRenderer; + + // flush + clear previous pipeline if this is a new type + renderer.pipelines.clear(); + + sceneRenderer.begin(); + + var scrollFactorX = src.scrollFactorX; + var scrollFactorY = src.scrollFactorY; + var alpha = skeleton.color.a; + + if (container) + { + src.scrollFactorX = container.scrollFactorX; + src.scrollFactorY = container.scrollFactorY; + + skeleton.color.a = Clamp(alpha * container.alpha, 0, 1); + } + + var calcMatrix = GetCalcMatrix(src, camera, parentMatrix).calc; + + var viewportHeight = renderer.height; + + skeleton.x = calcMatrix.tx; + skeleton.y = viewportHeight - calcMatrix.ty; + + skeleton.scaleX = calcMatrix.scaleX; + skeleton.scaleY = calcMatrix.scaleY; + + if (src.scaleX < 0) + { + skeleton.scaleX *= -1; + + // -180 degrees to account for the difference in Spine vs. Phaser rotation when inversely scaled + src.root.rotation = Wrap(RadToDeg(calcMatrix.rotationNormalized) - 180, 0, 360); + } + else + { + // +90 degrees to account for the difference in Spine vs. Phaser rotation + src.root.rotation = Wrap(RadToDeg(CounterClockwise(calcMatrix.rotationNormalized)) + 90, 0, 360); + } + + if (src.scaleY < 0) + { + skeleton.scaleY *= -1; + + if (src.scaleX < 0) + { + src.root.rotation -= (RadToDeg(calcMatrix.rotationNormalized) * 2); + } + else + { + src.root.rotation += (RadToDeg(calcMatrix.rotationNormalized) * 2); + } + } + + /* + if (renderer.currentFramebuffer !== null) + { + skeleton.y = calcMatrix.ty; + skeleton.scaleY *= -1; + } + */ + + skeleton.updateWorldTransform(); + + // Draw the current skeleton + + sceneRenderer.drawSkeleton(skeleton, src.preMultipliedAlpha); + + if (container) + { + src.scrollFactorX = scrollFactorX; + src.scrollFactorY = scrollFactorY; + skeleton.color.a = alpha; + } + + if (plugin.drawDebug || src.drawDebug) + { + // Because if we don't, the bones render positions are completely wrong (*sigh*) + var oldX = skeleton.x; + var oldY = skeleton.y; + + skeleton.x = 0; + skeleton.y = 0; + + sceneRenderer.drawSkeletonDebug(skeleton, src.preMultipliedAlpha); + + skeleton.x = oldX; + skeleton.y = oldY; + } + + // The next object in the display list is not a Spine Game Object or Spine Container, so we end the batch + sceneRenderer.end(); + + // And rebind the previous pipeline + renderer.pipelines.rebind(); +}; + +module.exports = SpineGameObjectWebGLDirect; diff --git a/src/gameobjects/rendertexture/RenderTexture.js b/src/gameobjects/rendertexture/RenderTexture.js index 908562c57..c4d9d8580 100644 --- a/src/gameobjects/rendertexture/RenderTexture.js +++ b/src/gameobjects/rendertexture/RenderTexture.js @@ -597,7 +597,7 @@ var RenderTexture = new Class({ * It can accept any of the following: * * * Any renderable Game Object, such as a Sprite, Text, Graphics or TileSprite. - * * Dynamic and Static Tilemap Layers. + * * Tilemap Layers. * * A Group. The contents of which will be iterated and drawn in turn. * * A Container. The contents of which will be iterated fully, and drawn in turn. * * A Scene's Display List. Pass in `Scene.children` to draw the whole list. @@ -654,7 +654,7 @@ var RenderTexture = new Class({ * It can accept any of the following: * * * Any renderable Game Object, such as a Sprite, Text, Graphics or TileSprite. - * * Dynamic and Static Tilemap Layers. + * * Tilemap Layers. * * A Group. The contents of which will be iterated and drawn in turn. * * A Container. The contents of which will be iterated fully, and drawn in turn. * * A Scene's Display List. Pass in `Scene.children` to draw the whole list. @@ -837,7 +837,7 @@ var RenderTexture = new Class({ * It can accept any of the following: * * * Any renderable Game Object, such as a Sprite, Text, Graphics or TileSprite. - * * Dynamic and Static Tilemap Layers. + * * Tilemap Layers. * * A Group. The contents of which will be iterated and drawn in turn. * * A Container. The contents of which will be iterated fully, and drawn in turn. * * A Scene's Display List. Pass in `Scene.children` to draw the whole list. @@ -1157,7 +1157,14 @@ var RenderTexture = new Class({ gameObject.setPosition(x + this.frame.cutX, y + this.frame.cutY); - gameObject.renderWebGL(this.renderer, gameObject, this.camera); + if (gameObject.renderDirect) + { + gameObject.renderDirect(this.renderer, gameObject, this.camera); + } + else + { + gameObject.renderWebGL(this.renderer, gameObject, this.camera); + } gameObject.setPosition(prevX, prevY); },