phaser/src/renderer/webgl/pipelines/BitmapMaskPipeline.js

210 lines
6.6 KiB
JavaScript
Raw Normal View History

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
*/
var Class = require('../../../utils/Class');
2020-08-21 15:04:26 +00:00
var GetFastValue = require('../../../utils/object/GetFastValue');
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-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
*/
var BitmapMaskPipeline = new Class({
Extends: WebGLPipeline,
2020-08-21 15:04:26 +00:00
initialize:
function BitmapMaskPipeline (config)
{
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);
},
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
*
* @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.
*/
bind: function (reset)
2020-08-21 15:04:26 +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-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
*/
beginMask: function (mask, maskedObject, camera)
{
var renderer = this.renderer;
var gl = this.gl;
// The renderable Game Object that is being used for the bitmap mask
var bitmapMask = mask.bitmapMask;
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);
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-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)
{
var gl = this.gl;
2019-04-26 18:13:32 +00:00
var renderer = this.renderer;
// The renderable Game Object that is being used for the bitmap mask
var bitmapMask = mask.bitmapMask;
if (bitmapMask && gl)
{
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);
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);
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
gl.drawArrays(this.topology, 0, 3);
}
}
});
module.exports = BitmapMaskPipeline;