diff --git a/src/gameobjects/components/FX.js b/src/gameobjects/components/FX.js index c8bff6986..8507ff744 100644 --- a/src/gameobjects/components/FX.js +++ b/src/gameobjects/components/FX.js @@ -183,6 +183,15 @@ var FX = { return fx; }, + addShineFX: function () + { + var fx = new Effects.Shine(this); + + this.fx.push(fx); + + return fx; + }, + addBloom: function (r, g, b) { } diff --git a/src/gameobjects/fx/Shadow.js b/src/gameobjects/fx/Shadow.js index ad51b3962..e7a50fe19 100644 --- a/src/gameobjects/fx/Shadow.js +++ b/src/gameobjects/fx/Shadow.js @@ -33,7 +33,7 @@ var Shadow = new Class({ this.y = 0; this.decay = 0.1; this.power = 1.0; - this._color = [ 0, 0, 0, 1 ]; + this.glcolor = [ 0, 0, 0, 1 ]; this.samples = 6; // max 12, min 1 this.intensity = 1; }, @@ -49,14 +49,14 @@ var Shadow = new Class({ get: function () { - var color = this._color; + var color = this.glcolor; return (((color[0] * 255) << 16) + ((color[1] * 255) << 8) + (color[2] * 255 | 0)); }, set: function (value) { - var color = this._color; + var color = this.glcolor; color[0] = ((value >> 16) & 0xFF) / 255; color[1] = ((value >> 8) & 0xFF) / 255; diff --git a/src/gameobjects/fx/Shine.js b/src/gameobjects/fx/Shine.js new file mode 100644 index 000000000..597b01d4b --- /dev/null +++ b/src/gameobjects/fx/Shine.js @@ -0,0 +1,40 @@ +/** + * @author Richard Davey + * @copyright 2013-2023 Photon Storm Ltd. + * @license {@link https://opensource.org/licenses/MIT|MIT License} + */ + +var BaseFX = require('./BaseFX'); +var Class = require('../../utils/Class'); +var FX_CONST = require('./const'); + +/** + * @classdesc + * + * @class Shine + * @extends Phaser.GameObjects.FX.BaseFX + * @memberof Phaser.GameObjects.FX + * @constructor + * @since 3.60.0 + * + * @param {Phaser.GameObjects.GameObject} gameObject - A reference to the Game Object that has this fx. + */ +var Shine = new Class({ + + Extends: BaseFX, + + initialize: + + function Shine (gameObject) + { + BaseFX.call(this, FX_CONST.SHINE, gameObject); + + this.speed = 0.5; + this.lineWidth = 0.5; + this.gradient = 3; + this.reveal = false; + } + +}); + +module.exports = Shine; diff --git a/src/gameobjects/fx/const.js b/src/gameobjects/fx/const.js index 5cb96fb78..af398845e 100644 --- a/src/gameobjects/fx/const.js +++ b/src/gameobjects/fx/const.js @@ -14,7 +14,7 @@ var FX_CONST = { * @const * @since 3.60.0 */ - GLOW: 4, + GLOW: 0, /** * The Shadow FX. @@ -24,7 +24,7 @@ var FX_CONST = { * @const * @since 3.60.0 */ - SHADOW: 5, + SHADOW: 1, /** * The Pixelate FX. @@ -34,7 +34,7 @@ var FX_CONST = { * @const * @since 3.60.0 */ - PIXELATE: 6, + PIXELATE: 2, /** * The Vignette FX. @@ -44,7 +44,17 @@ var FX_CONST = { * @const * @since 3.60.0 */ - VIGNETTE: 7 + VIGNETTE: 3, + + /** + * The Shine FX. + * + * @name Phaser.GameObjects.FX.SHINE + * @type {number} + * @const + * @since 3.60.0 + */ + SHINE: 4 }; diff --git a/src/gameobjects/fx/index.js b/src/gameobjects/fx/index.js index 575795a71..6ed7ba4f0 100644 --- a/src/gameobjects/fx/index.js +++ b/src/gameobjects/fx/index.js @@ -14,6 +14,7 @@ module.exports = { Glow: require('./Glow'), Pixelate: require('./Pixelate'), Shadow: require('./Shadow'), + Shine: require('./Shine'), Vignette: require('./Vignette') }; diff --git a/src/renderer/webgl/PipelineManager.js b/src/renderer/webgl/PipelineManager.js index eb8c12c80..649229518 100644 --- a/src/renderer/webgl/PipelineManager.js +++ b/src/renderer/webgl/PipelineManager.js @@ -22,7 +22,13 @@ var PointLightPipeline = require('./pipelines/PointLightPipeline'); var RopePipeline = require('./pipelines/RopePipeline'); var SinglePipeline = require('./pipelines/SinglePipeline'); var UtilityPipeline = require('./pipelines/UtilityPipeline'); + +// FX Pipelines var GlowFXPipeline = require('./pipelines/fx/GlowFXPipeline'); +var ShadowFXPipeline = require('./pipelines/fx/ShadowFXPipeline'); +var PixelateFXPipeline = require('./pipelines/fx/PixelateFXPipeline'); +var VignetteFXPipeline = require('./pipelines/fx/VignetteFXPipeline'); +var ShineFXPipeline = require('./pipelines/fx/ShineFXPipeline'); /** * @classdesc @@ -107,7 +113,11 @@ var PipelineManager = new Class({ * @since 3.50.0 */ this.postPipelineClasses = new CustomMap([ - [ 'GlowFX', GlowFXPipeline ] + [ 'GlowFX', GlowFXPipeline ], + [ 'ShadowFX', ShadowFXPipeline ], + [ 'PixelateFX', PixelateFXPipeline ], + [ 'VignetteFX', VignetteFXPipeline ], + [ 'ShineFX', ShineFXPipeline ] ]); /** diff --git a/src/renderer/webgl/pipelines/FXPipeline.js b/src/renderer/webgl/pipelines/FXPipeline.js index e1b814a90..224609bde 100644 --- a/src/renderer/webgl/pipelines/FXPipeline.js +++ b/src/renderer/webgl/pipelines/FXPipeline.js @@ -12,7 +12,12 @@ var PreFXPipeline = require('./PreFXPipeline'); var ShadowFrag = require('../shaders/FXShadow-frag.js'); var SingleQuadVS = require('../shaders/Single-vert.js'); var VignetteFrag = require('../shaders/FXVignette-frag.js'); +var ShineFrag = require('../shaders/FXShine-frag.js'); var GlowFXPipeline = require('./fx/GlowFXPipeline'); +var ShadowFXPipeline = require('./fx/ShadowFXPipeline'); +var PixelateFXPipeline = require('./fx/PixelateFXPipeline'); +var VignetteFXPipeline = require('./fx/VignetteFXPipeline'); +var ShineFXPipeline = require('./fx/ShineFXPipeline'); /** * @classdesc @@ -37,7 +42,8 @@ var FXPipeline = new Class({ { name: 'Glow', fragShader: GlowFrag, vertShader: SingleQuadVS }, { name: 'Shadow', fragShader: ShadowFrag, vertShader: SingleQuadVS }, { name: 'Pixelate', fragShader: PixelateFrag, vertShader: SingleQuadVS }, - { name: 'Vignette', fragShader: VignetteFrag, vertShader: SingleQuadVS } + { name: 'Vignette', fragShader: VignetteFrag, vertShader: SingleQuadVS }, + { name: 'Shine', fragShader: ShineFrag, vertShader: SingleQuadVS } ]; PreFXPipeline.call(this, config); @@ -45,6 +51,18 @@ var FXPipeline = new Class({ var game = this.game; this.glow = new GlowFXPipeline(game); + this.shadow = new ShadowFXPipeline(game); + this.pixelate = new PixelateFXPipeline(game); + this.vignette = new VignetteFXPipeline(game); + this.shine = new ShineFXPipeline(game); + + this.fxHandlers = []; + + this.fxHandlers[FX_CONST.GLOW] = this.onGlow; + this.fxHandlers[FX_CONST.SHADOW] = this.onShadow; + this.fxHandlers[FX_CONST.PIXELATE] = this.onPixelate; + this.fxHandlers[FX_CONST.VIGNETTE] = this.onVignette; + this.fxHandlers[FX_CONST.SHINE] = this.onShine; this.source; this.target; @@ -61,6 +79,7 @@ var FXPipeline = new Class({ var height = target1.height; var sprite = this.tempSprite; + var handlers = this.fxHandlers; if (sprite && sprite.fx) { @@ -72,26 +91,7 @@ var FXPipeline = new Class({ if (config.active) { - // TODO - We can remove all of this by having an array - // that maps the CONSTs to the onGlow, onShadow etc methods - switch (config.type) - { - case FX_CONST.GLOW: - this.onGlow(config, width, height); - break; - - case FX_CONST.SHADOW: - this.onShadow(config, width, height); - break; - - case FX_CONST.PIXELATE: - this.onPixelate(config, width, height); - break; - - case FX_CONST.VIGNETTE: - this.onVignette(config, width, height); - break; - } + handlers[config.type].call(this, config, width, height); } } } @@ -112,7 +112,7 @@ var FXPipeline = new Class({ onGlow: function (config, width, height) { - var shader = this.shaders[FX_CONST.GLOW]; + var shader = this.shaders[4 + FX_CONST.GLOW]; this.setShader(shader); @@ -123,56 +123,46 @@ var FXPipeline = new Class({ onShadow: function (config) { - var source = this.source; - var target = this.target; + var shader = this.shaders[4 + FX_CONST.SHADOW]; - this.setShader(this.shaders[FX_CONST.SHADOW]); + this.setShader(shader); - this.set1i('samples', config.samples); - this.set1f('intensity', config.intensity); - this.set1f('decay', config.decay); - this.set1f('power', config.power / config.samples); - this.set2f('lightPosition', config.x, config.y); - this.set4fv('color', config._color); + this.shadow.onPreRender(config, shader); - this.copy(source, target); - - this.source = target; - this.target = source; + this.runDraw(); }, - onPixelate: function (config) + onPixelate: function (config, width, height) { - var source = this.source; - var target = this.target; + var shader = this.shaders[4 + FX_CONST.PIXELATE]; - this.setShader(this.shaders[FX_CONST.PIXELATE]); + this.setShader(shader); - this.set1f('amount', config.amount); - this.set2f('resolution', source.width, source.height); + this.pixelate.onPreRender(config, shader, width, height); - this.copy(source, target); - - this.source = target; - this.target = source; + this.runDraw(); }, onVignette: function (config) { - var source = this.source; - var target = this.target; + var shader = this.shaders[4 + FX_CONST.VIGNETTE]; - // console.log(source, target); - // debugger; + this.setShader(shader); - this.setShader(this.shaders[FX_CONST.VIGNETTE]); + this.vignette.onPreRender(config, shader); - this.set1f('strength', config.strength); + this.runDraw(); + }, - this.copy(source, target); + onShine: function (config, width, height) + { + var shader = this.shaders[4 + FX_CONST.SHINE]; - this.source = target; - this.target = source; + this.setShader(shader); + + this.shine.onPreRender(config, shader, width, height); + + this.runDraw(); }, // onBloom: function (target1, target2, target3) diff --git a/src/renderer/webgl/pipelines/fx/PixelateFXPipeline.js b/src/renderer/webgl/pipelines/fx/PixelateFXPipeline.js new file mode 100644 index 000000000..a2b11df38 --- /dev/null +++ b/src/renderer/webgl/pipelines/fx/PixelateFXPipeline.js @@ -0,0 +1,50 @@ +/** + * @author Richard Davey + * @copyright 2013-2023 Photon Storm Ltd. + * @license {@link https://opensource.org/licenses/MIT|MIT License} + */ + +var Class = require('../../../../utils/Class'); +var GetFastValue = require('../../../../utils/object/GetFastValue'); +var PixelateFrag = require('../../shaders/FXPixelate-frag.js'); +var PostFXPipeline = require('../PostFXPipeline'); + +var PixelateFXPipeline = new Class({ + + Extends: PostFXPipeline, + + initialize: + + function PixelateFXPipeline (game) + { + PostFXPipeline.call(this, { + game: game, + fragShader: PixelateFrag + }); + + this.amount = 1; + }, + + onPreRender: function (config, shader, width, height) + { + // eslint-disable-next-line consistent-this + if (config === undefined) { config = this; } + + this.set1f('amount', GetFastValue(config, 'amount'), shader); + + if (width && height) + { + this.set2f('resolution', width, height, shader); + } + }, + + onDraw: function (target) + { + this.set2f('resolution', target.width, target.height); + + this.bindAndDraw(target); + } + +}); + +module.exports = PixelateFXPipeline; diff --git a/src/renderer/webgl/pipelines/fx/ShadowFXPipeline.js b/src/renderer/webgl/pipelines/fx/ShadowFXPipeline.js new file mode 100644 index 000000000..bbba73d3e --- /dev/null +++ b/src/renderer/webgl/pipelines/fx/ShadowFXPipeline.js @@ -0,0 +1,51 @@ +/** + * @author Richard Davey + * @copyright 2013-2023 Photon Storm Ltd. + * @license {@link https://opensource.org/licenses/MIT|MIT License} + */ + +var Class = require('../../../../utils/Class'); +var GetFastValue = require('../../../../utils/object/GetFastValue'); +var ShadowFrag = require('../../shaders/FXShadow-frag.js'); +var PostFXPipeline = require('../PostFXPipeline'); + +var ShadowFXPipeline = new Class({ + + Extends: PostFXPipeline, + + initialize: + + function ShadowFXPipeline (game) + { + PostFXPipeline.call(this, { + game: game, + fragShader: ShadowFrag + }); + + this.x = 0; + this.y = 1; + this.decay = 0.1; + this.power = 1.0; + this.glcolor = [ 0, 0, 0, 1 ]; + this.samples = 6; + this.intensity = 1; + }, + + onPreRender: function (config, shader) + { + // eslint-disable-next-line consistent-this + if (config === undefined) { config = this; } + + var samples = GetFastValue(config, 'samples'); + + this.set1i('samples', samples, shader); + this.set1f('intensity', GetFastValue(config, 'intensity'), shader); + this.set1f('decay', GetFastValue(config, 'decay'), shader); + this.set1f('power', (GetFastValue(config, 'power') / samples), shader); + this.set2f('lightPosition', GetFastValue(config, 'x'), GetFastValue(config, 'y'), shader); + this.set4fv('color', GetFastValue(config, 'glcolor'), shader); + } + +}); + +module.exports = ShadowFXPipeline; diff --git a/src/renderer/webgl/pipelines/fx/ShineFXPipeline.js b/src/renderer/webgl/pipelines/fx/ShineFXPipeline.js new file mode 100644 index 000000000..c068e1d51 --- /dev/null +++ b/src/renderer/webgl/pipelines/fx/ShineFXPipeline.js @@ -0,0 +1,58 @@ +/** + * @author Richard Davey + * @copyright 2013-2023 Photon Storm Ltd. + * @license {@link https://opensource.org/licenses/MIT|MIT License} + */ + +var Class = require('../../../../utils/Class'); +var GetFastValue = require('../../../../utils/object/GetFastValue'); +var ShineFrag = require('../../shaders/FXShine-frag.js'); +var PostFXPipeline = require('../PostFXPipeline'); + +var ShineFXPipeline = new Class({ + + Extends: PostFXPipeline, + + initialize: + + function ShineFXPipeline (game) + { + PostFXPipeline.call(this, { + game: game, + fragShader: ShineFrag + }); + + this.speed = 0.5; + this.lineWidth = 0.5; + this.gradient = 3; + this.reveal = false; + }, + + onPreRender: function (config, shader, width, height) + { + // eslint-disable-next-line consistent-this + if (config === undefined) { config = this; } + + this.setTime('time', shader); + + this.set1f('speed', GetFastValue(config, 'speed'), shader); + this.set1f('lineWidth', GetFastValue(config, 'lineWidth'), shader); + this.set1f('gradient', GetFastValue(config, 'gradient'), shader); + this.setBoolean('reveal', GetFastValue(config, 'reveal'), shader); + + if (width && height) + { + this.set2f('resolution', width, height, shader); + } + }, + + onDraw: function (target) + { + this.set2f('resolution', target.width, target.height); + + this.bindAndDraw(target); + } + +}); + +module.exports = ShineFXPipeline; diff --git a/src/renderer/webgl/pipelines/fx/VignetteFXPipeline.js b/src/renderer/webgl/pipelines/fx/VignetteFXPipeline.js new file mode 100644 index 000000000..41a50e640 --- /dev/null +++ b/src/renderer/webgl/pipelines/fx/VignetteFXPipeline.js @@ -0,0 +1,38 @@ +/** + * @author Richard Davey + * @copyright 2013-2023 Photon Storm Ltd. + * @license {@link https://opensource.org/licenses/MIT|MIT License} + */ + +var Class = require('../../../../utils/Class'); +var GetFastValue = require('../../../../utils/object/GetFastValue'); +var VignetteFrag = require('../../shaders/FXVignette-frag.js'); +var PostFXPipeline = require('../PostFXPipeline'); + +var VignetteFXPipeline = new Class({ + + Extends: PostFXPipeline, + + initialize: + + function VignetteFXPipeline (game) + { + PostFXPipeline.call(this, { + game: game, + fragShader: VignetteFrag + }); + + this.strength = 1; + }, + + onPreRender: function (config, shader) + { + // eslint-disable-next-line consistent-this + if (config === undefined) { config = this; } + + this.set1f('strength', GetFastValue(config, 'strength'), shader); + } + +}); + +module.exports = VignetteFXPipeline; diff --git a/src/renderer/webgl/shaders/FXShine-frag.js b/src/renderer/webgl/shaders/FXShine-frag.js new file mode 100644 index 000000000..9a192a5bb --- /dev/null +++ b/src/renderer/webgl/shaders/FXShine-frag.js @@ -0,0 +1,39 @@ +module.exports = [ + '#define SHADER_NAME SHINE_FS', + '', + 'precision mediump float;', + '', + 'uniform sampler2D uMainSampler;', + 'uniform vec2 resolution;', + 'uniform bool reveal;', + 'uniform float speed;', + 'uniform float time;', + 'uniform float lineWidth;', + 'uniform float gradient;', + '', + 'varying vec2 outTexCoord;', + '', + 'void main ()', + '{', + ' vec2 uv = gl_FragCoord.xy / resolution.xy;', + '', + ' vec4 tex = texture2D(uMainSampler, outTexCoord);', + '', + ' vec4 col1 = vec4(0.3, 0.0, 0.0, 1.0);', + ' vec4 col2 = vec4(0.85, 0.85, 0.85, 1.0);', + '', + ' uv.x = uv.x - mod(time * speed, 2.0) + 0.5;', + ' float y = uv.x * gradient;', + '', + ' float s = smoothstep(y - lineWidth, y, uv.y) - smoothstep(y, y + lineWidth, uv.y);', + '', + ' gl_FragColor = (((s * col1) + (s * col2)) * tex);', + '', + ' if (!reveal)', + ' {', + ' // Apply the shine effect', + ' gl_FragColor += tex;', + ' }', + '}', + '' +].join('\n'); diff --git a/src/renderer/webgl/shaders/src/FXShine.frag b/src/renderer/webgl/shaders/src/FXShine.frag new file mode 100644 index 000000000..7d0a2e95e --- /dev/null +++ b/src/renderer/webgl/shaders/src/FXShine.frag @@ -0,0 +1,36 @@ +#define SHADER_NAME SHINE_FS + +precision mediump float; + +uniform sampler2D uMainSampler; +uniform vec2 resolution; +uniform bool reveal; +uniform float speed; +uniform float time; +uniform float lineWidth; +uniform float gradient; + +varying vec2 outTexCoord; + +void main () +{ + vec2 uv = gl_FragCoord.xy / resolution.xy; + + vec4 tex = texture2D(uMainSampler, outTexCoord); + + vec4 col1 = vec4(0.3, 0.0, 0.0, 1.0); + vec4 col2 = vec4(0.85, 0.85, 0.85, 1.0); + + uv.x = uv.x - mod(time * speed, 2.0) + 0.5; + float y = uv.x * gradient; + + float s = smoothstep(y - lineWidth, y, uv.y) - smoothstep(y, y + lineWidth, uv.y); + + gl_FragColor = (((s * col1) + (s * col2)) * tex); + + if (!reveal) + { + // Apply the shine effect + gl_FragColor += tex; + } +}