2018-02-12 16:01:20 +00:00
|
|
|
/**
|
|
|
|
* @author Richard Davey <rich@photonstorm.com>
|
2018-04-05 08:02:36 +00:00
|
|
|
* @author Felipe Alfonso <@bitnenfer>
|
2020-01-15 12:07:09 +00:00
|
|
|
* @copyright 2020 Photon Storm Ltd.
|
2019-05-10 15:15:04 +00:00
|
|
|
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
2018-02-12 16:01:20 +00:00
|
|
|
*/
|
|
|
|
|
2018-01-25 18:43:19 +00:00
|
|
|
var Class = require('../../../utils/Class');
|
2020-08-21 15:04:26 +00:00
|
|
|
var GetFastValue = require('../../../utils/object/GetFastValue');
|
2018-05-08 22:04:57 +00:00
|
|
|
var ShaderSourceFS = require('../shaders/BitmapMask-frag.js');
|
|
|
|
var ShaderSourceVS = require('../shaders/BitmapMask-vert.js');
|
2018-02-09 19:19:21 +00:00
|
|
|
var WebGLPipeline = require('../WebGLPipeline');
|
2018-01-25 18:43:19 +00:00
|
|
|
|
2018-02-09 19:19:21 +00:00
|
|
|
/**
|
|
|
|
* @classdesc
|
2020-08-21 15:04:26 +00:00
|
|
|
*
|
2020-09-07 15:03:18 +00:00
|
|
|
* The Bitmap Mask Pipeline handles all of the bitmap mask rendering in WebGL for applying
|
|
|
|
* alpha masks to Game Objects. It works by sampling two texture on the fragment shader and
|
|
|
|
* using the fragments alpha to clip the region.
|
2020-08-21 15:04:26 +00:00
|
|
|
*
|
2020-09-07 15:03:18 +00:00
|
|
|
* The fragment shader it uses can be found in `shaders/src/BitmapMask.frag`.
|
|
|
|
* The vertex shader it uses can be found in `shaders/src/BitmapMask.vert`.
|
2020-08-21 15:04:26 +00:00
|
|
|
*
|
2020-09-07 15:03:18 +00:00
|
|
|
* The default shader attributes for this pipeline are:
|
|
|
|
*
|
|
|
|
* `inPosition` (vec2, offset 0)
|
|
|
|
*
|
|
|
|
* The default shader uniforms for this pipeline are:
|
|
|
|
*
|
|
|
|
* `uResolution` (vec2)
|
|
|
|
* `uMainSampler` (sampler2D)
|
|
|
|
* `uMaskSampler` (sampler2D)
|
|
|
|
* `uInvertMaskAlpha` (bool)
|
2018-02-09 19:19:21 +00:00
|
|
|
*
|
|
|
|
* @class BitmapMaskPipeline
|
|
|
|
* @extends Phaser.Renderer.WebGL.WebGLPipeline
|
2018-10-10 09:49:13 +00:00
|
|
|
* @memberof Phaser.Renderer.WebGL.Pipelines
|
2018-02-09 19:19:21 +00:00
|
|
|
* @constructor
|
|
|
|
* @since 3.0.0
|
|
|
|
*
|
2020-08-21 15:04:26 +00:00
|
|
|
* @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
|
2018-02-09 19:19:21 +00:00
|
|
|
*/
|
2018-01-25 18:43:19 +00:00
|
|
|
var BitmapMaskPipeline = new Class({
|
|
|
|
|
|
|
|
Extends: WebGLPipeline,
|
2020-08-21 15:04:26 +00:00
|
|
|
|
2018-01-25 18:43:19 +00:00
|
|
|
initialize:
|
|
|
|
|
2018-03-05 14:29:48 +00:00
|
|
|
function BitmapMaskPipeline (config)
|
2018-01-25 18:43:19 +00:00
|
|
|
{
|
2020-08-21 15:04:26 +00:00
|
|
|
config.fragShader = GetFastValue(config, 'fragShader', ShaderSourceFS),
|
|
|
|
config.vertShader = GetFastValue(config, 'vertShader', ShaderSourceVS),
|
|
|
|
config.vertexSize = GetFastValue(config, 'vertexSize', 8),
|
|
|
|
config.vertexCapacity = GetFastValue(config, 'vertexCapacity', 3),
|
|
|
|
config.vertices = GetFastValue(config, 'vertices', new Float32Array([ -1, 1, -1, -7, 7, 1 ]).buffer),
|
|
|
|
config.attributes = GetFastValue(config, 'attributes', [
|
|
|
|
{
|
|
|
|
name: 'inPosition',
|
|
|
|
size: 2,
|
|
|
|
type: config.game.renderer.gl.FLOAT,
|
|
|
|
normalized: false,
|
|
|
|
offset: 0,
|
|
|
|
enabled: false,
|
|
|
|
location: -1
|
|
|
|
}
|
|
|
|
]);
|
|
|
|
|
|
|
|
WebGLPipeline.call(this, config);
|
2018-01-25 18:43:19 +00:00
|
|
|
},
|
2020-08-21 15:04:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called every time the pipeline is bound by the renderer.
|
|
|
|
* Sets the shader program, vertex buffer and other resources.
|
|
|
|
* Should only be called when changing pipeline.
|
|
|
|
*
|
2020-08-21 15:14:59 +00:00
|
|
|
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#bind
|
2020-08-21 15:04:26 +00:00
|
|
|
* @since 3.50.0
|
|
|
|
*
|
2020-08-25 12:24:56 +00:00
|
|
|
* @param {boolean} [reset=false] - Should the pipeline be fully re-bound after a renderer pipeline clear?
|
|
|
|
*
|
2020-08-21 15:04:26 +00:00
|
|
|
* @return {this} This WebGLPipeline instance.
|
|
|
|
*/
|
2020-08-25 12:24:56 +00:00
|
|
|
bind: function (reset)
|
2020-08-21 15:04:26 +00:00
|
|
|
{
|
2020-08-25 12:24:56 +00:00
|
|
|
if (reset === undefined) { reset = false; }
|
|
|
|
|
|
|
|
WebGLPipeline.prototype.bind.call(this, reset);
|
2020-08-21 15:04:26 +00:00
|
|
|
|
|
|
|
var renderer = this.renderer;
|
|
|
|
var program = this.program;
|
|
|
|
|
|
|
|
renderer.setFloat2(program, 'uResolution', this.width, this.height);
|
|
|
|
renderer.setInt1(program, 'uMainSampler', 0);
|
|
|
|
renderer.setInt1(program, 'uMaskSampler', 1);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
2018-01-25 18:43:19 +00:00
|
|
|
|
2018-02-09 19:19:21 +00:00
|
|
|
/**
|
2018-04-24 16:53:10 +00:00
|
|
|
* Binds necessary resources and renders the mask to a separated framebuffer.
|
|
|
|
* The framebuffer for the masked object is also bound for further use.
|
2018-02-09 19:19:21 +00:00
|
|
|
*
|
2018-04-18 11:13:49 +00:00
|
|
|
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#beginMask
|
2018-02-09 19:19:21 +00:00
|
|
|
* @since 3.0.0
|
|
|
|
*
|
2018-04-24 16:53:10 +00:00
|
|
|
* @param {Phaser.GameObjects.GameObject} mask - GameObject used as mask.
|
|
|
|
* @param {Phaser.GameObjects.GameObject} maskedObject - GameObject masked by the mask GameObject.
|
2020-02-04 17:30:27 +00:00
|
|
|
* @param {Phaser.Cameras.Scene2D.Camera} camera - The camera rendering the current mask.
|
2018-02-09 19:19:21 +00:00
|
|
|
*/
|
2018-01-25 18:43:19 +00:00
|
|
|
beginMask: function (mask, maskedObject, camera)
|
|
|
|
{
|
|
|
|
var renderer = this.renderer;
|
|
|
|
var gl = this.gl;
|
2018-08-31 13:39:38 +00:00
|
|
|
|
|
|
|
// The renderable Game Object that is being used for the bitmap mask
|
|
|
|
var bitmapMask = mask.bitmapMask;
|
2018-01-25 18:43:19 +00:00
|
|
|
|
|
|
|
if (bitmapMask && gl)
|
|
|
|
{
|
2019-04-26 18:13:32 +00:00
|
|
|
renderer.flush();
|
2019-04-12 17:36:47 +00:00
|
|
|
|
2019-04-26 18:13:32 +00:00
|
|
|
mask.prevFramebuffer = renderer.currentFramebuffer;
|
2019-04-12 17:36:47 +00:00
|
|
|
|
2019-04-26 18:13:32 +00:00
|
|
|
renderer.setFramebuffer(mask.mainFramebuffer);
|
2018-08-31 13:39:38 +00:00
|
|
|
|
2019-04-29 13:29:13 +00:00
|
|
|
gl.disable(gl.STENCIL_TEST);
|
|
|
|
|
2019-04-26 18:13:32 +00:00
|
|
|
gl.clearColor(0, 0, 0, 0);
|
2019-04-29 13:29:13 +00:00
|
|
|
|
2019-04-26 18:13:32 +00:00
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
|
2019-04-29 13:45:54 +00:00
|
|
|
if (renderer.currentCameraMask.mask !== mask)
|
2019-04-26 18:13:32 +00:00
|
|
|
{
|
2019-04-29 13:45:54 +00:00
|
|
|
renderer.currentMask.mask = mask;
|
|
|
|
renderer.currentMask.camera = camera;
|
2019-04-12 17:36:47 +00:00
|
|
|
}
|
2018-01-25 18:43:19 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-02-09 19:19:21 +00:00
|
|
|
/**
|
2020-08-21 15:04:26 +00:00
|
|
|
* The masked game objects framebuffer is unbound and its texture
|
|
|
|
* is bound together with the mask texture and the mask shader and
|
2018-04-24 16:53:10 +00:00
|
|
|
* a draw call with a single quad is processed. Here is where the
|
2020-08-21 15:04:26 +00:00
|
|
|
* masking effect is applied.
|
2018-02-09 19:19:21 +00:00
|
|
|
*
|
2018-04-18 11:13:49 +00:00
|
|
|
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#endMask
|
2018-02-09 19:19:21 +00:00
|
|
|
* @since 3.0.0
|
|
|
|
*
|
2018-04-24 16:53:10 +00:00
|
|
|
* @param {Phaser.GameObjects.GameObject} mask - GameObject used as a mask.
|
2018-02-09 19:19:21 +00:00
|
|
|
*/
|
2019-04-26 18:13:32 +00:00
|
|
|
endMask: function (mask, camera)
|
2018-01-25 18:43:19 +00:00
|
|
|
{
|
|
|
|
var gl = this.gl;
|
2019-04-26 18:13:32 +00:00
|
|
|
var renderer = this.renderer;
|
2018-01-25 18:43:19 +00:00
|
|
|
|
2018-08-31 13:39:38 +00:00
|
|
|
// The renderable Game Object that is being used for the bitmap mask
|
|
|
|
var bitmapMask = mask.bitmapMask;
|
|
|
|
|
|
|
|
if (bitmapMask && gl)
|
2018-01-25 18:43:19 +00:00
|
|
|
{
|
2019-04-26 18:13:32 +00:00
|
|
|
renderer.flush();
|
|
|
|
|
|
|
|
// First we draw the mask to the mask fb
|
|
|
|
renderer.setFramebuffer(mask.maskFramebuffer);
|
|
|
|
|
|
|
|
gl.clearColor(0, 0, 0, 0);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
|
2019-05-01 10:12:31 +00:00
|
|
|
renderer.setBlendMode(0, true);
|
|
|
|
|
2019-04-26 18:13:32 +00:00
|
|
|
bitmapMask.renderWebGL(renderer, bitmapMask, 0, camera);
|
|
|
|
|
|
|
|
renderer.flush();
|
|
|
|
|
|
|
|
renderer.setFramebuffer(mask.prevFramebuffer);
|
|
|
|
|
2019-04-29 13:29:13 +00:00
|
|
|
// Is there a stencil further up the stack?
|
|
|
|
var prev = renderer.getCurrentStencilMask();
|
|
|
|
|
|
|
|
if (prev)
|
|
|
|
{
|
|
|
|
gl.enable(gl.STENCIL_TEST);
|
|
|
|
|
|
|
|
prev.mask.applyStencil(renderer, prev.camera, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-29 13:45:54 +00:00
|
|
|
renderer.currentMask.mask = null;
|
2019-04-29 13:29:13 +00:00
|
|
|
}
|
2019-04-12 17:36:47 +00:00
|
|
|
|
2019-04-26 18:13:32 +00:00
|
|
|
// Bind bitmap mask pipeline and draw
|
2020-09-09 12:21:38 +00:00
|
|
|
renderer.pipelines.set(this);
|
2019-05-01 10:12:31 +00:00
|
|
|
|
|
|
|
gl.activeTexture(gl.TEXTURE1);
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, mask.maskTexture);
|
|
|
|
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, mask.mainTexture);
|
|
|
|
|
|
|
|
gl.uniform1i(gl.getUniformLocation(this.program, 'uInvertMaskAlpha'), mask.invertAlpha);
|
2018-02-23 17:09:27 +00:00
|
|
|
|
2019-05-01 01:10:38 +00:00
|
|
|
// Finally, draw a triangle filling the whole screen
|
2018-01-25 18:43:19 +00:00
|
|
|
gl.drawArrays(this.topology, 0, 3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = BitmapMaskPipeline;
|