mirror of
https://github.com/photonstorm/phaser
synced 2024-12-25 12:33:38 +00:00
210 lines
6.6 KiB
JavaScript
210 lines
6.6 KiB
JavaScript
/**
|
|
* @author Richard Davey <rich@photonstorm.com>
|
|
* @author Felipe Alfonso <@bitnenfer>
|
|
* @copyright 2020 Photon Storm Ltd.
|
|
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
|
*/
|
|
|
|
var Class = require('../../../utils/Class');
|
|
var GetFastValue = require('../../../utils/object/GetFastValue');
|
|
var ShaderSourceFS = require('../shaders/BitmapMask-frag.js');
|
|
var ShaderSourceVS = require('../shaders/BitmapMask-vert.js');
|
|
var WebGLPipeline = require('../WebGLPipeline');
|
|
|
|
/**
|
|
* @classdesc
|
|
*
|
|
* 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.
|
|
*
|
|
* 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`.
|
|
*
|
|
* 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)
|
|
*
|
|
* @class BitmapMaskPipeline
|
|
* @extends Phaser.Renderer.WebGL.WebGLPipeline
|
|
* @memberof Phaser.Renderer.WebGL.Pipelines
|
|
* @constructor
|
|
* @since 3.0.0
|
|
*
|
|
* @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
|
|
*/
|
|
var BitmapMaskPipeline = new Class({
|
|
|
|
Extends: WebGLPipeline,
|
|
|
|
initialize:
|
|
|
|
function BitmapMaskPipeline (config)
|
|
{
|
|
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
|
|
}
|
|
]);
|
|
config.uniforms = GetFastValue(config, 'uniforms', [
|
|
'uResolution',
|
|
'uMainSampler',
|
|
'uMaskSampler',
|
|
'uInvertMaskAlpha'
|
|
]);
|
|
|
|
WebGLPipeline.call(this, config);
|
|
},
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#bind
|
|
* @since 3.50.0
|
|
*
|
|
* @param {boolean} [reset=false] - Should the pipeline be fully re-bound after a renderer pipeline clear?
|
|
*
|
|
* @return {this} This WebGLPipeline instance.
|
|
*/
|
|
bind: function (reset)
|
|
{
|
|
if (reset === undefined) { reset = false; }
|
|
|
|
WebGLPipeline.prototype.bind.call(this, reset);
|
|
|
|
this.set2f('uResolution', this.width, this.height);
|
|
this.set1i('uMainSampler', 0);
|
|
this.set1i('uMaskSampler', 1);
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Binds necessary resources and renders the mask to a separated framebuffer.
|
|
* The framebuffer for the masked object is also bound for further use.
|
|
*
|
|
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#beginMask
|
|
* @since 3.0.0
|
|
*
|
|
* @param {Phaser.GameObjects.GameObject} mask - GameObject used as mask.
|
|
* @param {Phaser.GameObjects.GameObject} maskedObject - GameObject masked by the mask GameObject.
|
|
* @param {Phaser.Cameras.Scene2D.Camera} camera - The camera rendering the current mask.
|
|
*/
|
|
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)
|
|
{
|
|
renderer.flush();
|
|
|
|
mask.prevFramebuffer = renderer.currentFramebuffer;
|
|
|
|
renderer.setFramebuffer(mask.mainFramebuffer);
|
|
|
|
gl.disable(gl.STENCIL_TEST);
|
|
gl.clearColor(0, 0, 0, 0);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
if (renderer.currentCameraMask.mask !== mask)
|
|
{
|
|
renderer.currentMask.mask = mask;
|
|
renderer.currentMask.camera = camera;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* The masked game objects framebuffer is unbound and its texture
|
|
* 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.
|
|
*
|
|
* @method Phaser.Renderer.WebGL.Pipelines.BitmapMaskPipeline#endMask
|
|
* @since 3.0.0
|
|
*
|
|
* @param {Phaser.GameObjects.GameObject} mask - GameObject used as a mask.
|
|
*/
|
|
endMask: function (mask, camera)
|
|
{
|
|
var gl = this.gl;
|
|
var renderer = this.renderer;
|
|
|
|
// The renderable Game Object that is being used for the bitmap mask
|
|
var bitmapMask = mask.bitmapMask;
|
|
|
|
if (bitmapMask && gl)
|
|
{
|
|
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);
|
|
|
|
bitmapMask.renderWebGL(renderer, bitmapMask, camera);
|
|
|
|
renderer.flush();
|
|
|
|
renderer.setFramebuffer(mask.prevFramebuffer);
|
|
|
|
// 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
|
|
{
|
|
renderer.currentMask.mask = null;
|
|
}
|
|
|
|
// Bind bitmap mask pipeline and draw
|
|
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);
|
|
|
|
this.set1i('uInvertMaskAlpha', mask.invertAlpha);
|
|
|
|
// Finally, draw a triangle filling the whole screen
|
|
gl.drawArrays(this.topology, 0, 3);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
module.exports = BitmapMaskPipeline;
|