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

258 lines
8 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');
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
2018-04-24 16:53:10 +00:00
* BitmapMaskPipeline handles all bitmap masking rendering in WebGL. It works by using
* sampling two texture on the fragment shader and using the fragment's alpha to clip the region.
* The config properties are:
* - game: Current game instance.
* - renderer: Current WebGL renderer.
* - topology: This indicates how the primitives are rendered. The default value is GL_TRIANGLES.
* Here is the full list of rendering primitives (https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants).
* - vertShader: Source for vertex shader as a string.
* - fragShader: Source for fragment shader as a string.
* - vertexCapacity: The amount of vertices that shall be allocated
* - vertexSize: The size of a single vertex in bytes.
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
*
2018-04-24 16:53:10 +00:00
* @param {object} config - Used for overriding shader an pipeline properties if extending this pipeline.
2018-02-09 19:19:21 +00:00
*/
var BitmapMaskPipeline = new Class({
Extends: WebGLPipeline,
initialize:
function BitmapMaskPipeline (config)
{
WebGLPipeline.call(this, {
game: config.game,
renderer: config.renderer,
gl: config.renderer.gl,
topology: (config.topology ? config.topology : config.renderer.gl.TRIANGLES),
vertShader: (config.vertShader ? config.vertShader : ShaderSourceVS),
fragShader: (config.fragShader ? config.fragShader : ShaderSourceFS),
vertexCapacity: (config.vertexCapacity ? config.vertexCapacity : 3),
vertexSize: (config.vertexSize ? config.vertexSize :
Float32Array.BYTES_PER_ELEMENT * 2),
vertices: new Float32Array([
-1, +1, -1, -7, +7, +1
]).buffer,
attributes: [
{
name: 'inPosition',
size: 2,
type: config.renderer.gl.FLOAT,
normalized: false,
offset: 0
}
]
});
2018-02-09 19:19:21 +00:00
/**
2018-04-24 16:53:10 +00:00
* Float32 view of the array buffer containing the pipeline's vertices.
2018-02-09 19:19:21 +00:00
*
2018-04-18 11:13:49 +00:00
* @name Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#vertexViewF32
2018-02-09 19:19:21 +00:00
* @type {Float32Array}
* @since 3.0.0
*/
this.vertexViewF32 = new Float32Array(this.vertexData);
2018-02-09 19:19:21 +00:00
/**
2018-04-24 16:53:10 +00:00
* Size of the batch.
2018-02-09 19:19:21 +00:00
*
2018-04-18 11:13:49 +00:00
* @name Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#maxQuads
2018-02-09 19:19:21 +00:00
* @type {number}
* @default 1
* @since 3.0.0
*/
this.maxQuads = 1;
2018-02-09 19:19:21 +00:00
/**
2018-04-24 16:53:10 +00:00
* Dirty flag to check if resolution properties need to be updated on the
* masking shader.
2018-02-09 19:19:21 +00:00
*
2018-04-18 11:13:49 +00:00
* @name Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#resolutionDirty
2018-02-09 19:19:21 +00:00
* @type {boolean}
* @default true
* @since 3.0.0
*/
this.resolutionDirty = true;
},
2018-02-09 19:19:21 +00:00
/**
2018-04-24 16:53:10 +00:00
* Called every time the pipeline needs to be used.
* It binds all necessary resources.
2018-02-09 19:19:21 +00:00
*
2018-04-18 11:13:49 +00:00
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#onBind
2018-02-09 19:19:21 +00:00
* @since 3.0.0
*
2018-09-25 10:36:36 +00:00
* @return {this} This WebGLPipeline instance.
2018-02-09 19:19:21 +00:00
*/
onBind: function ()
{
WebGLPipeline.prototype.onBind.call(this);
var renderer = this.renderer;
2018-01-30 03:38:31 +00:00
var program = this.program;
2018-01-30 03:38:31 +00:00
if (this.resolutionDirty)
{
renderer.setFloat2(program, 'uResolution', this.width, this.height);
renderer.setInt1(program, 'uMainSampler', 0);
renderer.setInt1(program, 'uMaskSampler', 1);
this.resolutionDirty = false;
}
return this;
},
2018-02-09 19:19:21 +00:00
/**
* [description]
*
2018-04-18 11:13:49 +00:00
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#resize
2018-02-09 19:19:21 +00:00
* @since 3.0.0
*
* @param {number} width - [description]
* @param {number} height - [description]
* @param {number} resolution - [description]
*
2018-09-25 10:36:36 +00:00
* @return {this} This WebGLPipeline instance.
2018-02-09 19:19:21 +00:00
*/
resize: function (width, height, resolution)
{
WebGLPipeline.prototype.resize.call(this, width, height, resolution);
this.resolutionDirty = true;
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.
2018-02-09 19:19:21 +00:00
* @param {Phaser.Cameras.Scene2D.Camera} camera - [description]
*/
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
/**
2019-04-26 18:13:32 +00:00
* The masked game objects framebuffer is unbound and its texture
2018-04-24 16:53:10 +00:00
* is bound together with the mask texture and the mask shader and
* a draw call with a single quad is processed. Here is where the
* 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
renderer.setPipeline(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;