Initial
This commit is contained in:
369
resources/app/client/pixi/webgl/shaders/samplers/base-sampler.js
Normal file
369
resources/app/client/pixi/webgl/shaders/samplers/base-sampler.js
Normal file
@@ -0,0 +1,369 @@
|
||||
/**
|
||||
* The base sampler shader exposes a simple sprite shader and all the framework to handle:
|
||||
* - Batched shaders and plugin subscription
|
||||
* - Configure method (for special processing done once or punctually)
|
||||
* - Update method (pre-binding, normally done each frame)
|
||||
* All other sampler shaders (batched or not) should extend BaseSamplerShader
|
||||
*/
|
||||
class BaseSamplerShader extends AbstractBaseShader {
|
||||
|
||||
/**
|
||||
* The named batch sampler plugin that is used by this shader, or null if no batching is used.
|
||||
* @type {string|null}
|
||||
*/
|
||||
static classPluginName = "batch";
|
||||
|
||||
/**
|
||||
* Is this shader pausable or not?
|
||||
* @type {boolean}
|
||||
*/
|
||||
static pausable = true;
|
||||
|
||||
/**
|
||||
* The plugin name associated for this instance, if any.
|
||||
* Returns "batch" if the shader is disabled.
|
||||
* @type {string|null}
|
||||
*/
|
||||
get pluginName() {
|
||||
return this.#pluginName;
|
||||
}
|
||||
|
||||
#pluginName = this.constructor.classPluginName;
|
||||
|
||||
/**
|
||||
* Activate or deactivate this sampler. If set to false, the batch rendering is redirected to "batch".
|
||||
* Otherwise, the batch rendering is directed toward the instance pluginName (might be null)
|
||||
* @type {boolean}
|
||||
*/
|
||||
get enabled() {
|
||||
return this.#enabled;
|
||||
}
|
||||
|
||||
set enabled(enabled) {
|
||||
this.#pluginName = enabled ? this.constructor.classPluginName : "batch";
|
||||
this.#enabled = enabled;
|
||||
}
|
||||
|
||||
#enabled = true;
|
||||
|
||||
/**
|
||||
* Pause or Unpause this sampler. If set to true, the shader is disabled. Otherwise, it is enabled.
|
||||
* Contrary to enabled, a shader might decide to refuse a pause, to continue to render animations per example.
|
||||
* @see {enabled}
|
||||
* @type {boolean}
|
||||
*/
|
||||
get paused() {
|
||||
return !this.#enabled;
|
||||
}
|
||||
|
||||
set paused(paused) {
|
||||
if ( !this.constructor.pausable ) return;
|
||||
this.enabled = !paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contrast adjustment
|
||||
* @type {string}
|
||||
*/
|
||||
static CONTRAST = `
|
||||
// Computing contrasted color
|
||||
if ( contrast != 0.0 ) {
|
||||
changedColor = (changedColor - 0.5) * (contrast + 1.0) + 0.5;
|
||||
}`;
|
||||
|
||||
/**
|
||||
* Saturation adjustment
|
||||
* @type {string}
|
||||
*/
|
||||
static SATURATION = `
|
||||
// Computing saturated color
|
||||
if ( saturation != 0.0 ) {
|
||||
vec3 grey = vec3(perceivedBrightness(changedColor));
|
||||
changedColor = mix(grey, changedColor, 1.0 + saturation);
|
||||
}`;
|
||||
|
||||
/**
|
||||
* Exposure adjustment.
|
||||
* @type {string}
|
||||
*/
|
||||
static EXPOSURE = `
|
||||
if ( exposure != 0.0 ) {
|
||||
changedColor *= (1.0 + exposure);
|
||||
}`;
|
||||
|
||||
/**
|
||||
* The adjustments made into fragment shaders.
|
||||
* @type {string}
|
||||
*/
|
||||
static get ADJUSTMENTS() {
|
||||
return `vec3 changedColor = baseColor.rgb;
|
||||
${this.CONTRAST}
|
||||
${this.SATURATION}
|
||||
${this.EXPOSURE}
|
||||
baseColor.rgb = changedColor;`;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static vertexShader = `
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
attribute vec2 aVertexPosition;
|
||||
attribute vec2 aTextureCoord;
|
||||
uniform mat3 projectionMatrix;
|
||||
varying vec2 vUvs;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vUvs = aTextureCoord;
|
||||
}
|
||||
`;
|
||||
|
||||
/** @override */
|
||||
static fragmentShader = `
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
uniform sampler2D sampler;
|
||||
uniform vec4 tintAlpha;
|
||||
varying vec2 vUvs;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(sampler, vUvs) * tintAlpha;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* The batch vertex shader source.
|
||||
* @type {string}
|
||||
*/
|
||||
static batchVertexShader = `
|
||||
#version 300 es
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
in vec2 aVertexPosition;
|
||||
in vec2 aTextureCoord;
|
||||
in vec4 aColor;
|
||||
in float aTextureId;
|
||||
uniform mat3 projectionMatrix;
|
||||
uniform mat3 translationMatrix;
|
||||
uniform vec4 tint;
|
||||
out vec2 vTextureCoord;
|
||||
flat out vec4 vColor;
|
||||
flat out float vTextureId;
|
||||
|
||||
void main(void){
|
||||
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vTextureCoord = aTextureCoord;
|
||||
vTextureId = aTextureId;
|
||||
vColor = aColor * tint;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* The batch fragment shader source.
|
||||
* @type {string}
|
||||
*/
|
||||
static batchFragmentShader = `
|
||||
#version 300 es
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
in vec2 vTextureCoord;
|
||||
flat in vec4 vColor;
|
||||
flat in float vTextureId;
|
||||
uniform sampler2D uSamplers[%count%];
|
||||
out vec4 fragColor;
|
||||
|
||||
#define texture2D texture
|
||||
|
||||
void main(void){
|
||||
vec4 color;
|
||||
%forloop%
|
||||
fragColor = color * vColor;
|
||||
}
|
||||
`;
|
||||
|
||||
/** @inheritdoc */
|
||||
static defaultUniforms = {
|
||||
sampler: 0,
|
||||
tintAlpha: [1, 1, 1, 1]
|
||||
};
|
||||
|
||||
/**
|
||||
* Batch geometry associated with this sampler.
|
||||
* @type {typeof PIXI.BatchGeometry|{id: string, size: number, normalized: boolean, type: PIXI.TYPES}[]}
|
||||
*/
|
||||
static batchGeometry = PIXI.BatchGeometry;
|
||||
|
||||
/**
|
||||
* The size of a vertice with all its packed attributes.
|
||||
* @type {number}
|
||||
*/
|
||||
static batchVertexSize = 6;
|
||||
|
||||
/**
|
||||
* Pack interleaved geometry custom function.
|
||||
* @type {Function|undefined}
|
||||
* @protected
|
||||
*/
|
||||
static _packInterleavedGeometry;
|
||||
|
||||
/**
|
||||
* A prerender function happening just before the batch renderer is flushed.
|
||||
* @type {(batchRenderer: BatchRenderer) => void | undefined}
|
||||
* @protected
|
||||
*/
|
||||
static _preRenderBatch;
|
||||
|
||||
/**
|
||||
* A function that returns default uniforms associated with the batched version of this sampler.
|
||||
* @type {object}
|
||||
*/
|
||||
static batchDefaultUniforms = {};
|
||||
|
||||
/**
|
||||
* The number of reserved texture units for this shader that cannot be used by the batch renderer.
|
||||
* @type {number}
|
||||
*/
|
||||
static reservedTextureUnits = 0;
|
||||
|
||||
/**
|
||||
* Initialize the batch geometry with custom properties.
|
||||
*/
|
||||
static initializeBatchGeometry() {}
|
||||
|
||||
/**
|
||||
* The batch renderer to use.
|
||||
* @type {typeof BatchRenderer}
|
||||
*/
|
||||
static batchRendererClass = BatchRenderer;
|
||||
|
||||
/**
|
||||
* The batch generator to use.
|
||||
* @type {typeof BatchShaderGenerator}
|
||||
*/
|
||||
static batchShaderGeneratorClass = BatchShaderGenerator;
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create a batch plugin for this sampler class.
|
||||
* @returns {typeof BatchPlugin} The batch plugin class linked to this sampler class.
|
||||
*/
|
||||
static createPlugin() {
|
||||
const shaderClass = this;
|
||||
const geometryClass = Array.isArray(shaderClass.batchGeometry)
|
||||
? class BatchGeometry extends PIXI.Geometry {
|
||||
constructor(_static=false) {
|
||||
super();
|
||||
this._buffer = new PIXI.Buffer(null, _static, false);
|
||||
this._indexBuffer = new PIXI.Buffer(null, _static, true);
|
||||
for ( const {id, size, normalized, type} of shaderClass.batchGeometry ) {
|
||||
this.addAttribute(id, this._buffer, size, normalized, type);
|
||||
}
|
||||
this.addIndex(this._indexBuffer);
|
||||
}
|
||||
} : shaderClass.batchGeometry;
|
||||
return class BatchPlugin extends shaderClass.batchRendererClass {
|
||||
|
||||
/** @override */
|
||||
static get shaderGeneratorClass() {
|
||||
return shaderClass.batchShaderGeneratorClass;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get defaultVertexSrc() {
|
||||
return shaderClass.batchVertexShader;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get defaultFragmentTemplate() {
|
||||
return shaderClass.batchFragmentShader;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get defaultUniforms() {
|
||||
return shaderClass.batchDefaultUniforms;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* The batch plugin constructor.
|
||||
* @param {PIXI.Renderer} renderer The renderer
|
||||
*/
|
||||
constructor(renderer) {
|
||||
super(renderer);
|
||||
this.geometryClass = geometryClass;
|
||||
this.vertexSize = shaderClass.batchVertexSize;
|
||||
this.reservedTextureUnits = shaderClass.reservedTextureUnits;
|
||||
this._packInterleavedGeometry = shaderClass._packInterleavedGeometry;
|
||||
this._preRenderBatch = shaderClass._preRenderBatch;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
setShaderGenerator(options) {
|
||||
if ( !canvas.performance ) return;
|
||||
super.setShaderGenerator(options);
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
contextChange() {
|
||||
this.shaderGenerator = null;
|
||||
super.contextChange();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* Register the plugin for this sampler.
|
||||
* @param {object} [options] The options
|
||||
* @param {object} [options.force=false] Override the plugin of the same name that is already registered?
|
||||
*/
|
||||
static registerPlugin({force=false}={}) {
|
||||
const pluginName = this.classPluginName;
|
||||
|
||||
// Checking the pluginName
|
||||
if ( !(pluginName && (typeof pluginName === "string") && (pluginName.length > 0)) ) {
|
||||
const msg = `Impossible to create a PIXI plugin for ${this.name}. `
|
||||
+ `The plugin name is invalid: [pluginName=${pluginName}]. `
|
||||
+ "The plugin name must be a string with at least 1 character.";
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
// Checking for existing plugins
|
||||
if ( !force && BatchRenderer.hasPlugin(pluginName) ) {
|
||||
const msg = `Impossible to create a PIXI plugin for ${this.name}. `
|
||||
+ `The plugin name is already associated to a plugin in PIXI.Renderer: [pluginName=${pluginName}].`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
// Initialize custom properties for the batch geometry
|
||||
this.initializeBatchGeometry();
|
||||
|
||||
// Create our custom batch renderer for this geometry
|
||||
const plugin = this.createPlugin();
|
||||
|
||||
// Register this plugin with its batch renderer
|
||||
PIXI.extensions.add({
|
||||
name: pluginName,
|
||||
type: PIXI.ExtensionType.RendererPlugin,
|
||||
ref: plugin
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_preRender(mesh, renderer) {
|
||||
const uniforms = this.uniforms;
|
||||
uniforms.sampler = mesh.texture;
|
||||
uniforms.tintAlpha = mesh._cachedTint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Compute baseline illumination according to darkness level encoded texture.
|
||||
*/
|
||||
class BaselineIlluminationSamplerShader extends BaseSamplerShader {
|
||||
|
||||
/** @override */
|
||||
static classPluginName = null;
|
||||
|
||||
/** @inheritdoc */
|
||||
static fragmentShader = `
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
uniform sampler2D sampler;
|
||||
uniform vec4 tintAlpha;
|
||||
uniform vec3 ambientDarkness;
|
||||
uniform vec3 ambientDaylight;
|
||||
varying vec2 vUvs;
|
||||
|
||||
void main() {
|
||||
float illuminationRed = texture2D(sampler, vUvs).r;
|
||||
vec3 finalColor = mix(ambientDaylight, ambientDarkness, illuminationRed);
|
||||
gl_FragColor = vec4(finalColor, 1.0) * tintAlpha;
|
||||
}`;
|
||||
|
||||
/** @inheritdoc */
|
||||
static defaultUniforms = {
|
||||
tintAlpha: [1, 1, 1, 1],
|
||||
ambientDarkness: [0, 0, 0],
|
||||
ambientDaylight: [1, 1, 1],
|
||||
sampler: null
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
_preRender(mesh, renderer) {
|
||||
super._preRender(mesh, renderer);
|
||||
const c = canvas.colors;
|
||||
const u = this.uniforms;
|
||||
c.ambientDarkness.applyRGB(u.ambientDarkness);
|
||||
c.ambientDaylight.applyRGB(u.ambientDaylight);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* A color adjustment shader.
|
||||
*/
|
||||
class ColorAdjustmentsSamplerShader extends BaseSamplerShader {
|
||||
|
||||
/** @override */
|
||||
static classPluginName = null;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static vertexShader = `
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
attribute vec2 aVertexPosition;
|
||||
attribute vec2 aTextureCoord;
|
||||
uniform mat3 projectionMatrix;
|
||||
uniform vec2 screenDimensions;
|
||||
varying vec2 vUvs;
|
||||
varying vec2 vScreenCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vUvs = aTextureCoord;
|
||||
vScreenCoord = aVertexPosition / screenDimensions;
|
||||
}`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static fragmentShader = `
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
uniform sampler2D sampler;
|
||||
uniform vec4 tintAlpha;
|
||||
uniform vec3 tint;
|
||||
uniform float exposure;
|
||||
uniform float contrast;
|
||||
uniform float saturation;
|
||||
uniform float brightness;
|
||||
uniform sampler2D darknessLevelTexture;
|
||||
uniform bool linkedToDarknessLevel;
|
||||
varying vec2 vUvs;
|
||||
varying vec2 vScreenCoord;
|
||||
|
||||
${this.CONSTANTS}
|
||||
${this.PERCEIVED_BRIGHTNESS}
|
||||
|
||||
void main() {
|
||||
vec4 baseColor = texture2D(sampler, vUvs);
|
||||
|
||||
if ( baseColor.a > 0.0 ) {
|
||||
// Unmultiply rgb with alpha channel
|
||||
baseColor.rgb /= baseColor.a;
|
||||
|
||||
// Copy original color before update
|
||||
vec3 originalColor = baseColor.rgb;
|
||||
|
||||
${this.ADJUSTMENTS}
|
||||
|
||||
if ( linkedToDarknessLevel ) {
|
||||
float darknessLevel = texture2D(darknessLevelTexture, vScreenCoord).r;
|
||||
baseColor.rgb = mix(originalColor, baseColor.rgb, darknessLevel);
|
||||
}
|
||||
|
||||
// Multiply rgb with tint and alpha channel
|
||||
baseColor.rgb *= (tint * baseColor.a);
|
||||
}
|
||||
|
||||
// Output with tint and alpha
|
||||
gl_FragColor = baseColor * tintAlpha;
|
||||
}`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static defaultUniforms = {
|
||||
tintAlpha: [1, 1, 1, 1],
|
||||
tint: [1, 1, 1],
|
||||
contrast: 0,
|
||||
saturation: 0,
|
||||
exposure: 0,
|
||||
sampler: null,
|
||||
linkedToDarknessLevel: false,
|
||||
darknessLevelTexture: null,
|
||||
screenDimensions: [1, 1]
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
get linkedToDarknessLevel() {
|
||||
return this.uniforms.linkedToDarknessLevel;
|
||||
}
|
||||
|
||||
set linkedToDarknessLevel(link) {
|
||||
this.uniforms.linkedToDarknessLevel = link;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
get contrast() {
|
||||
return this.uniforms.contrast;
|
||||
}
|
||||
|
||||
set contrast(contrast) {
|
||||
this.uniforms.contrast = contrast;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
get exposure() {
|
||||
return this.uniforms.exposure;
|
||||
}
|
||||
|
||||
set exposure(exposure) {
|
||||
this.uniforms.exposure = exposure;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
get saturation() {
|
||||
return this.uniforms.saturation;
|
||||
}
|
||||
|
||||
set saturation(saturation) {
|
||||
this.uniforms.saturation = saturation;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* A light amplification shader.
|
||||
*/
|
||||
class AmplificationSamplerShader extends ColorAdjustmentsSamplerShader {
|
||||
|
||||
/** @override */
|
||||
static classPluginName = null;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static vertexShader = `
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
attribute vec2 aVertexPosition;
|
||||
attribute vec2 aTextureCoord;
|
||||
uniform mat3 projectionMatrix;
|
||||
uniform vec2 screenDimensions;
|
||||
varying vec2 vUvs;
|
||||
varying vec2 vScreenCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vUvs = aTextureCoord;
|
||||
vScreenCoord = aVertexPosition / screenDimensions;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static fragmentShader = `
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
uniform sampler2D sampler;
|
||||
uniform vec4 tintAlpha;
|
||||
uniform vec3 tint;
|
||||
uniform float exposure;
|
||||
uniform float contrast;
|
||||
uniform float saturation;
|
||||
uniform float brightness;
|
||||
uniform sampler2D darknessLevelTexture;
|
||||
uniform bool linkedToDarknessLevel;
|
||||
uniform bool enable;
|
||||
varying vec2 vUvs;
|
||||
varying vec2 vScreenCoord;
|
||||
|
||||
${this.CONSTANTS}
|
||||
${this.PERCEIVED_BRIGHTNESS}
|
||||
|
||||
void main() {
|
||||
vec4 baseColor = texture2D(sampler, vUvs);
|
||||
|
||||
if ( enable && baseColor.a > 0.0 ) {
|
||||
// Unmultiply rgb with alpha channel
|
||||
baseColor.rgb /= baseColor.a;
|
||||
|
||||
float lum = perceivedBrightness(baseColor.rgb);
|
||||
vec3 vision = vec3(smoothstep(0.0, 1.0, lum * 1.5)) * tint;
|
||||
float darknessLevel = texture2D(darknessLevelTexture, vScreenCoord).r;
|
||||
baseColor.rgb = vision + (vision * (lum + brightness) * 0.1) + (baseColor.rgb * (1.0 - darknessLevel) * 0.125);
|
||||
|
||||
${this.ADJUSTMENTS}
|
||||
|
||||
// Multiply rgb with alpha channel
|
||||
baseColor.rgb *= baseColor.a;
|
||||
}
|
||||
|
||||
// Output with tint and alpha
|
||||
gl_FragColor = baseColor * tintAlpha;
|
||||
}`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static defaultUniforms = {
|
||||
tintAlpha: [1, 1, 1, 1],
|
||||
tint: [0.38, 0.8, 0.38],
|
||||
brightness: 0,
|
||||
darknessLevelTexture: null,
|
||||
screenDimensions: [1, 1],
|
||||
enable: true
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Brightness controls the luminosity.
|
||||
* @type {number}
|
||||
*/
|
||||
get brightness() {
|
||||
return this.uniforms.brightness;
|
||||
}
|
||||
|
||||
set brightness(brightness) {
|
||||
this.uniforms.brightness = brightness;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Tint color applied to Light Amplification.
|
||||
* @type {number[]} Light Amplification tint (default: [0.48, 1.0, 0.48]).
|
||||
*/
|
||||
get colorTint() {
|
||||
return this.uniforms.colorTint;
|
||||
}
|
||||
|
||||
set colorTint(color) {
|
||||
this.uniforms.colorTint = color;
|
||||
}
|
||||
}
|
||||
421
resources/app/client/pixi/webgl/shaders/samplers/depth.js
Normal file
421
resources/app/client/pixi/webgl/shaders/samplers/depth.js
Normal file
@@ -0,0 +1,421 @@
|
||||
/**
|
||||
* The batch data that is needed by {@link DepthSamplerShader} to render an element with batching.
|
||||
* @typedef {object} DepthBatchData
|
||||
* @property {PIXI.Texture} _texture The texture
|
||||
* @property {Float32Array} vertexData The vertices
|
||||
* @property {Uint16Array|Uint32Array|number[]} indices The indices
|
||||
* @property {Float32Array} uvs The texture UVs
|
||||
* @property {number} elevation The elevation
|
||||
* @property {number} textureAlphaThreshold The texture alpha threshold
|
||||
* @property {number} fadeOcclusion The amount of FADE occlusion
|
||||
* @property {number} radialOcclusion The amount of RADIAL occlusion
|
||||
* @property {number} visionOcclusion The amount of VISION occlusion
|
||||
*/
|
||||
|
||||
/**
|
||||
* The depth sampler shader.
|
||||
*/
|
||||
class DepthSamplerShader extends BaseSamplerShader {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Batched version Rendering */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static classPluginName = "batchDepth";
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static batchGeometry = [
|
||||
{id: "aVertexPosition", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aTextureCoord", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aTextureId", size: 1, normalized: false, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aTextureAlphaThreshold", size: 1, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aDepthElevation", size: 1, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aRestrictionState", size: 1, normalized: false, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aOcclusionData", size: 4, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE}
|
||||
];
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static batchVertexSize = 6;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static reservedTextureUnits = 1; // We need a texture unit for the occlusion texture
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static defaultUniforms = {
|
||||
screenDimensions: [1, 1],
|
||||
sampler: null,
|
||||
occlusionTexture: null,
|
||||
textureAlphaThreshold: 0,
|
||||
depthElevation: 0,
|
||||
occlusionElevation: 0,
|
||||
fadeOcclusion: 0,
|
||||
radialOcclusion: 0,
|
||||
visionOcclusion: 0,
|
||||
restrictsLight: false,
|
||||
restrictsWeather: false
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static batchDefaultUniforms(maxTex) {
|
||||
return {
|
||||
screenDimensions: [1, 1],
|
||||
occlusionTexture: maxTex
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static _preRenderBatch(batchRenderer) {
|
||||
const uniforms = batchRenderer._shader.uniforms;
|
||||
uniforms.screenDimensions = canvas.screenDimensions;
|
||||
batchRenderer.renderer.texture.bind(canvas.masks.occlusion.renderTexture, uniforms.occlusionTexture);
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static _packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) {
|
||||
const {float32View, uint8View} = attributeBuffer;
|
||||
|
||||
// Write indices into buffer
|
||||
const packedVertices = aIndex / this.vertexSize;
|
||||
const indices = element.indices;
|
||||
for ( let i = 0; i < indices.length; i++ ) {
|
||||
indexBuffer[iIndex++] = packedVertices + indices[i];
|
||||
}
|
||||
|
||||
// Prepare attributes
|
||||
const vertexData = element.vertexData;
|
||||
const uvs = element.uvs;
|
||||
const textureId = element._texture.baseTexture._batchLocation;
|
||||
const restrictionState = element.restrictionState;
|
||||
const textureAlphaThreshold = (element.textureAlphaThreshold * 255) | 0;
|
||||
const depthElevation = (canvas.masks.depth.mapElevation(element.elevation) * 255) | 0;
|
||||
const occlusionElevation = (canvas.masks.occlusion.mapElevation(element.elevation) * 255) | 0;
|
||||
const fadeOcclusion = (element.fadeOcclusion * 255) | 0;
|
||||
const radialOcclusion = (element.radialOcclusion * 255) | 0;
|
||||
const visionOcclusion = (element.visionOcclusion * 255) | 0;
|
||||
|
||||
// Write attributes into buffer
|
||||
const vertexSize = this.vertexSize;
|
||||
for ( let i = 0, j = 0; i < vertexData.length; i += 2, j += vertexSize ) {
|
||||
let k = aIndex + j;
|
||||
float32View[k++] = vertexData[i];
|
||||
float32View[k++] = vertexData[i + 1];
|
||||
float32View[k++] = uvs[i];
|
||||
float32View[k++] = uvs[i + 1];
|
||||
k <<= 2;
|
||||
uint8View[k++] = textureId;
|
||||
uint8View[k++] = textureAlphaThreshold;
|
||||
uint8View[k++] = depthElevation;
|
||||
uint8View[k++] = restrictionState;
|
||||
uint8View[k++] = occlusionElevation;
|
||||
uint8View[k++] = fadeOcclusion;
|
||||
uint8View[k++] = radialOcclusion;
|
||||
uint8View[k++] = visionOcclusion;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get batchVertexShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_VERTEX}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
|
||||
in vec2 aVertexPosition;
|
||||
in vec2 aTextureCoord;
|
||||
|
||||
uniform vec2 screenDimensions;
|
||||
|
||||
${this._batchVertexShader}
|
||||
|
||||
in float aTextureId;
|
||||
in float aTextureAlphaThreshold;
|
||||
in float aDepthElevation;
|
||||
in vec4 aOcclusionData;
|
||||
in float aRestrictionState;
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
uniform mat3 translationMatrix;
|
||||
|
||||
out vec2 vTextureCoord;
|
||||
out vec2 vOcclusionCoord;
|
||||
flat out float vTextureId;
|
||||
flat out float vTextureAlphaThreshold;
|
||||
flat out float vDepthElevation;
|
||||
flat out float vOcclusionElevation;
|
||||
flat out float vFadeOcclusion;
|
||||
flat out float vRadialOcclusion;
|
||||
flat out float vVisionOcclusion;
|
||||
flat out uint vRestrictionState;
|
||||
|
||||
void main() {
|
||||
vec2 vertexPosition;
|
||||
vec2 textureCoord;
|
||||
_main(vertexPosition, textureCoord);
|
||||
vec3 tPos = translationMatrix * vec3(vertexPosition, 1.0);
|
||||
gl_Position = vec4((projectionMatrix * tPos).xy, 0.0, 1.0);
|
||||
vTextureCoord = textureCoord;
|
||||
vOcclusionCoord = tPos.xy / screenDimensions;
|
||||
vTextureId = aTextureId;
|
||||
vTextureAlphaThreshold = aTextureAlphaThreshold;
|
||||
vDepthElevation = aDepthElevation;
|
||||
vOcclusionElevation = aOcclusionData.x;
|
||||
vFadeOcclusion = aOcclusionData.y;
|
||||
vRadialOcclusion = aOcclusionData.z;
|
||||
vVisionOcclusion = aOcclusionData.w;
|
||||
vRestrictionState = uint(aRestrictionState);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The batch vertex shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _batchVertexShader = `
|
||||
void _main(out vec2 vertexPosition, out vec2 textureCoord) {
|
||||
vertexPosition = aVertexPosition;
|
||||
textureCoord = aTextureCoord;
|
||||
}
|
||||
`;
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get batchFragmentShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_FRAGMENT}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
|
||||
in vec2 vTextureCoord;
|
||||
flat in float vTextureId;
|
||||
|
||||
uniform sampler2D uSamplers[%count%];
|
||||
|
||||
${DepthSamplerShader.#OPTIONS_CONSTANTS}
|
||||
${this._batchFragmentShader}
|
||||
|
||||
in vec2 vOcclusionCoord;
|
||||
flat in float vTextureAlphaThreshold;
|
||||
flat in float vDepthElevation;
|
||||
flat in float vOcclusionElevation;
|
||||
flat in float vFadeOcclusion;
|
||||
flat in float vRadialOcclusion;
|
||||
flat in float vVisionOcclusion;
|
||||
flat in uint vRestrictionState;
|
||||
|
||||
uniform sampler2D occlusionTexture;
|
||||
|
||||
out vec3 fragColor;
|
||||
|
||||
void main() {
|
||||
float textureAlpha = _main();
|
||||
float textureAlphaThreshold = vTextureAlphaThreshold;
|
||||
float depthElevation = vDepthElevation;
|
||||
float occlusionElevation = vOcclusionElevation;
|
||||
float fadeOcclusion = vFadeOcclusion;
|
||||
float radialOcclusion = vRadialOcclusion;
|
||||
float visionOcclusion = vVisionOcclusion;
|
||||
bool restrictsLight = ((vRestrictionState & RESTRICTS_LIGHT) == RESTRICTS_LIGHT);
|
||||
bool restrictsWeather = ((vRestrictionState & RESTRICTS_WEATHER) == RESTRICTS_WEATHER);
|
||||
${DepthSamplerShader.#FRAGMENT_MAIN}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The batch fragment shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _batchFragmentShader = `
|
||||
float _main() {
|
||||
vec4 color;
|
||||
%forloop%
|
||||
return color.a;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Non-Batched version Rendering */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get vertexShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_VERTEX}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
|
||||
in vec2 aVertexPosition;
|
||||
in vec2 aTextureCoord;
|
||||
|
||||
uniform vec2 screenDimensions;
|
||||
|
||||
${this._vertexShader}
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
|
||||
out vec2 vUvs;
|
||||
out vec2 vOcclusionCoord;
|
||||
|
||||
void main() {
|
||||
vec2 vertexPosition;
|
||||
vec2 textureCoord;
|
||||
_main(vertexPosition, textureCoord);
|
||||
gl_Position = vec4((projectionMatrix * vec3(vertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vUvs = textureCoord;
|
||||
vOcclusionCoord = vertexPosition / screenDimensions;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The vertex shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _vertexShader = `
|
||||
void _main(out vec2 vertexPosition, out vec2 textureCoord) {
|
||||
vertexPosition = aVertexPosition;
|
||||
textureCoord = aTextureCoord;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get fragmentShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_FRAGMENT}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
|
||||
in vec2 vUvs;
|
||||
|
||||
uniform sampler2D sampler;
|
||||
|
||||
${DepthSamplerShader.#OPTIONS_CONSTANTS}
|
||||
${this._fragmentShader}
|
||||
|
||||
in vec2 vOcclusionCoord;
|
||||
|
||||
uniform sampler2D occlusionTexture;
|
||||
uniform float textureAlphaThreshold;
|
||||
uniform float depthElevation;
|
||||
uniform float occlusionElevation;
|
||||
uniform float fadeOcclusion;
|
||||
uniform float radialOcclusion;
|
||||
uniform float visionOcclusion;
|
||||
uniform bool restrictsLight;
|
||||
uniform bool restrictsWeather;
|
||||
|
||||
out vec3 fragColor;
|
||||
|
||||
void main() {
|
||||
float textureAlpha = _main();
|
||||
${DepthSamplerShader.#FRAGMENT_MAIN}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The fragment shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _fragmentShader = `
|
||||
float _main() {
|
||||
return texture(sampler, vUvs).a;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
_preRender(mesh, renderer) {
|
||||
super._preRender(mesh, renderer);
|
||||
const uniforms = this.uniforms;
|
||||
uniforms.screenDimensions = canvas.screenDimensions;
|
||||
uniforms.textureAlphaThreshold = mesh.textureAlphaThreshold;
|
||||
const occlusionMask = canvas.masks.occlusion;
|
||||
uniforms.occlusionTexture = occlusionMask.renderTexture;
|
||||
uniforms.occlusionElevation = occlusionMask.mapElevation(mesh.elevation);
|
||||
uniforms.depthElevation = canvas.masks.depth.mapElevation(mesh.elevation);
|
||||
const occlusionState = mesh._occlusionState;
|
||||
uniforms.fadeOcclusion = occlusionState.fade;
|
||||
uniforms.radialOcclusion = occlusionState.radial;
|
||||
uniforms.visionOcclusion = occlusionState.vision;
|
||||
uniforms.restrictsLight = mesh.restrictsLight;
|
||||
uniforms.restrictsWeather = mesh.restrictsWeather;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The restriction options bit mask constants.
|
||||
* @type {string}
|
||||
*/
|
||||
static #OPTIONS_CONSTANTS = foundry.utils.BitMask.generateShaderBitMaskConstants([
|
||||
"RESTRICTS_LIGHT",
|
||||
"RESTRICTS_WEATHER"
|
||||
]);
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The fragment source.
|
||||
* @type {string}
|
||||
*/
|
||||
static #FRAGMENT_MAIN = `
|
||||
float inverseDepthElevation = 1.0 - depthElevation;
|
||||
fragColor = vec3(inverseDepthElevation, depthElevation, inverseDepthElevation);
|
||||
fragColor *= step(textureAlphaThreshold, textureAlpha);
|
||||
vec3 weight = 1.0 - step(occlusionElevation, texture(occlusionTexture, vOcclusionCoord).rgb);
|
||||
float occlusion = step(0.5, max(max(weight.r * fadeOcclusion, weight.g * radialOcclusion), weight.b * visionOcclusion));
|
||||
fragColor.r *= occlusion;
|
||||
fragColor.g *= 1.0 - occlusion;
|
||||
fragColor.b *= occlusion;
|
||||
if ( !restrictsLight ) {
|
||||
fragColor.r = 0.0;
|
||||
fragColor.g = 0.0;
|
||||
}
|
||||
if ( !restrictsWeather ) {
|
||||
fragColor.b = 0.0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* A simple shader which purpose is to make the original texture red channel the alpha channel,
|
||||
* and still keeping channel informations. Used in cunjunction with the AlphaBlurFilterPass and Fog of War.
|
||||
*/
|
||||
class FogSamplerShader extends BaseSamplerShader {
|
||||
/** @override */
|
||||
static classPluginName = null;
|
||||
|
||||
/** @override */
|
||||
static fragmentShader = `
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
uniform sampler2D sampler;
|
||||
uniform vec4 tintAlpha;
|
||||
varying vec2 vUvs;
|
||||
void main() {
|
||||
vec4 color = texture2D(sampler, vUvs);
|
||||
gl_FragColor = vec4(1.0, color.gb, 1.0) * step(0.15, color.r) * tintAlpha;
|
||||
}`;
|
||||
}
|
||||
395
resources/app/client/pixi/webgl/shaders/samplers/occlusion.js
Normal file
395
resources/app/client/pixi/webgl/shaders/samplers/occlusion.js
Normal file
@@ -0,0 +1,395 @@
|
||||
/**
|
||||
* The batch data that is needed by {@link OccludableSamplerShader} to render an element with batching.
|
||||
* @typedef {object} OccludableBatchData
|
||||
* @property {PIXI.Texture} _texture The texture
|
||||
* @property {Float32Array} vertexData The vertices
|
||||
* @property {Uint16Array|Uint32Array|number[]} indices The indices
|
||||
* @property {Float32Array} uvs The texture UVs
|
||||
* @property {number} worldAlpha The world alpha
|
||||
* @property {number} _tintRGB The tint
|
||||
* @property {number} blendMode The blend mode
|
||||
* @property {number} elevation The elevation
|
||||
* @property {number} unoccludedAlpha The unoccluded alpha
|
||||
* @property {number} occludedAlpha The unoccluded alpha
|
||||
* @property {number} fadeOcclusion The amount of FADE occlusion
|
||||
* @property {number} radialOcclusion The amount of RADIAL occlusion
|
||||
* @property {number} visionOcclusion The amount of VISION occlusion
|
||||
*/
|
||||
|
||||
/**
|
||||
* The occlusion sampler shader.
|
||||
*/
|
||||
class OccludableSamplerShader extends BaseSamplerShader {
|
||||
|
||||
/**
|
||||
* The fragment shader code that applies occlusion.
|
||||
* @type {string}
|
||||
*/
|
||||
static #OCCLUSION = `
|
||||
vec3 occluded = 1.0 - step(occlusionElevation, texture(occlusionTexture, vScreenCoord).rgb);
|
||||
float occlusion = max(occluded.r * fadeOcclusion, max(occluded.g * radialOcclusion, occluded.b * visionOcclusion));
|
||||
fragColor *= mix(unoccludedAlpha, occludedAlpha, occlusion);
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Batched version Rendering */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static classPluginName = "batchOcclusion";
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static batchGeometry = [
|
||||
{id: "aVertexPosition", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aTextureCoord", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aColor", size: 4, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aTextureId", size: 1, normalized: false, type: PIXI.TYPES.UNSIGNED_SHORT},
|
||||
{id: "aOcclusionAlphas", size: 2, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aOcclusionData", size: 4, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE}
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static batchVertexSize = 7;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static reservedTextureUnits = 1; // We need a texture unit for the occlusion texture
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static defaultUniforms = {
|
||||
screenDimensions: [1, 1],
|
||||
sampler: null,
|
||||
tintAlpha: [1, 1, 1, 1],
|
||||
occlusionTexture: null,
|
||||
unoccludedAlpha: 1,
|
||||
occludedAlpha: 0,
|
||||
occlusionElevation: 0,
|
||||
fadeOcclusion: 0,
|
||||
radialOcclusion: 0,
|
||||
visionOcclusion: 0
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static batchDefaultUniforms(maxTex) {
|
||||
return {
|
||||
screenDimensions: [1, 1],
|
||||
occlusionTexture: maxTex
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static _preRenderBatch(batchRenderer) {
|
||||
const occlusionMask = canvas.masks.occlusion;
|
||||
const uniforms = batchRenderer._shader.uniforms;
|
||||
uniforms.screenDimensions = canvas.screenDimensions;
|
||||
batchRenderer.renderer.texture.bind(occlusionMask.renderTexture, uniforms.occlusionTexture);
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static _packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) {
|
||||
const {float32View, uint8View, uint16View, uint32View} = attributeBuffer;
|
||||
|
||||
// Write indices into buffer
|
||||
const packedVertices = aIndex / this.vertexSize;
|
||||
const indices = element.indices;
|
||||
for ( let i = 0; i < indices.length; i++ ) {
|
||||
indexBuffer[iIndex++] = packedVertices + indices[i];
|
||||
}
|
||||
|
||||
// Prepare attributes
|
||||
const vertexData = element.vertexData;
|
||||
const uvs = element.uvs;
|
||||
const baseTexture = element._texture.baseTexture;
|
||||
const alpha = Math.min(element.worldAlpha, 1.0);
|
||||
const argb = PIXI.Color.shared.setValue(element._tintRGB).toPremultiplied(alpha, baseTexture.alphaMode > 0);
|
||||
const textureId = baseTexture._batchLocation;
|
||||
const unoccludedAlpha = (element.unoccludedAlpha * 255) | 0;
|
||||
const occludedAlpha = (element.occludedAlpha * 255) | 0;
|
||||
const occlusionElevation = (canvas.masks.occlusion.mapElevation(element.elevation) * 255) | 0;
|
||||
const fadeOcclusion = (element.fadeOcclusion * 255) | 0;
|
||||
const radialOcclusion = (element.radialOcclusion * 255) | 0;
|
||||
const visionOcclusion = (element.visionOcclusion * 255) | 0;
|
||||
|
||||
// Write attributes into buffer
|
||||
const vertexSize = this.vertexSize;
|
||||
for ( let i = 0, j = 0; i < vertexData.length; i += 2, j += vertexSize ) {
|
||||
let k = aIndex + j;
|
||||
float32View[k++] = vertexData[i];
|
||||
float32View[k++] = vertexData[i + 1];
|
||||
float32View[k++] = uvs[i];
|
||||
float32View[k++] = uvs[i + 1];
|
||||
uint32View[k++] = argb;
|
||||
k <<= 1;
|
||||
uint16View[k++] = textureId;
|
||||
k <<= 1;
|
||||
uint8View[k++] = unoccludedAlpha;
|
||||
uint8View[k++] = occludedAlpha;
|
||||
uint8View[k++] = occlusionElevation;
|
||||
uint8View[k++] = fadeOcclusion;
|
||||
uint8View[k++] = radialOcclusion;
|
||||
uint8View[k++] = visionOcclusion;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get batchVertexShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_VERTEX}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
|
||||
in vec2 aVertexPosition;
|
||||
in vec2 aTextureCoord;
|
||||
in vec4 aColor;
|
||||
|
||||
uniform mat3 translationMatrix;
|
||||
uniform vec4 tint;
|
||||
uniform vec2 screenDimensions;
|
||||
|
||||
${this._batchVertexShader}
|
||||
|
||||
in float aTextureId;
|
||||
in vec2 aOcclusionAlphas;
|
||||
in vec4 aOcclusionData;
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
|
||||
out vec2 vTextureCoord;
|
||||
out vec2 vScreenCoord;
|
||||
flat out vec4 vColor;
|
||||
flat out float vTextureId;
|
||||
flat out float vUnoccludedAlpha;
|
||||
flat out float vOccludedAlpha;
|
||||
flat out float vOcclusionElevation;
|
||||
flat out float vFadeOcclusion;
|
||||
flat out float vRadialOcclusion;
|
||||
flat out float vVisionOcclusion;
|
||||
|
||||
void main() {
|
||||
vec2 vertexPosition;
|
||||
vec2 textureCoord;
|
||||
vec4 color;
|
||||
_main(vertexPosition, textureCoord, color);
|
||||
gl_Position = vec4((projectionMatrix * vec3(vertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vTextureCoord = textureCoord;
|
||||
vScreenCoord = vertexPosition / screenDimensions;
|
||||
vColor = color;
|
||||
vTextureId = aTextureId;
|
||||
vUnoccludedAlpha = aOcclusionAlphas.x;
|
||||
vOccludedAlpha = aOcclusionAlphas.y;
|
||||
vOcclusionElevation = aOcclusionData.x;
|
||||
vFadeOcclusion = aOcclusionData.y;
|
||||
vRadialOcclusion = aOcclusionData.z;
|
||||
vVisionOcclusion = aOcclusionData.w;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The batch vertex shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _batchVertexShader = `
|
||||
void _main(out vec2 vertexPosition, out vec2 textureCoord, out vec4 color) {
|
||||
vertexPosition = (translationMatrix * vec3(aVertexPosition, 1.0)).xy;
|
||||
textureCoord = aTextureCoord;
|
||||
color = aColor * tint;
|
||||
}
|
||||
`;
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get batchFragmentShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_FRAGMENT}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
|
||||
in vec2 vTextureCoord;
|
||||
in vec2 vScreenCoord;
|
||||
flat in vec4 vColor;
|
||||
flat in float vTextureId;
|
||||
|
||||
uniform sampler2D uSamplers[%count%];
|
||||
|
||||
${this._batchFragmentShader}
|
||||
|
||||
flat in float vUnoccludedAlpha;
|
||||
flat in float vOccludedAlpha;
|
||||
flat in float vOcclusionElevation;
|
||||
flat in float vFadeOcclusion;
|
||||
flat in float vRadialOcclusion;
|
||||
flat in float vVisionOcclusion;
|
||||
|
||||
uniform sampler2D occlusionTexture;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = _main();
|
||||
float unoccludedAlpha = vUnoccludedAlpha;
|
||||
float occludedAlpha = vOccludedAlpha;
|
||||
float occlusionElevation = vOcclusionElevation;
|
||||
float fadeOcclusion = vFadeOcclusion;
|
||||
float radialOcclusion = vRadialOcclusion;
|
||||
float visionOcclusion = vVisionOcclusion;
|
||||
${OccludableSamplerShader.#OCCLUSION}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The batch fragment shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _batchFragmentShader = `
|
||||
vec4 _main() {
|
||||
vec4 color;
|
||||
%forloop%
|
||||
return color * vColor;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Non-Batched version Rendering */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get vertexShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_VERTEX}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_VERTEX} float;
|
||||
|
||||
in vec2 aVertexPosition;
|
||||
in vec2 aTextureCoord;
|
||||
|
||||
uniform vec2 screenDimensions;
|
||||
|
||||
${this._vertexShader}
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
|
||||
out vec2 vUvs;
|
||||
out vec2 vScreenCoord;
|
||||
|
||||
void main() {
|
||||
vec2 vertexPosition;
|
||||
vec2 textureCoord;
|
||||
_main(vertexPosition, textureCoord);
|
||||
gl_Position = vec4((projectionMatrix * vec3(vertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vUvs = textureCoord;
|
||||
vScreenCoord = vertexPosition / screenDimensions;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The vertex shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _vertexShader = `
|
||||
void _main(out vec2 vertexPosition, out vec2 textureCoord) {
|
||||
vertexPosition = aVertexPosition;
|
||||
textureCoord = aTextureCoord;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get fragmentShader() {
|
||||
return `
|
||||
#version 300 es
|
||||
|
||||
${this.GLSL1_COMPATIBILITY_FRAGMENT}
|
||||
|
||||
precision ${PIXI.settings.PRECISION_FRAGMENT} float;
|
||||
|
||||
in vec2 vUvs;
|
||||
in vec2 vScreenCoord;
|
||||
|
||||
uniform sampler2D sampler;
|
||||
uniform vec4 tintAlpha;
|
||||
|
||||
${this._fragmentShader}
|
||||
|
||||
uniform sampler2D occlusionTexture;
|
||||
uniform float unoccludedAlpha;
|
||||
uniform float occludedAlpha;
|
||||
uniform float occlusionElevation;
|
||||
uniform float fadeOcclusion;
|
||||
uniform float radialOcclusion;
|
||||
uniform float visionOcclusion;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = _main();
|
||||
${OccludableSamplerShader.#OCCLUSION}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The fragment shader source. Subclasses can override it.
|
||||
* @type {string}
|
||||
* @protected
|
||||
*/
|
||||
static _fragmentShader = `
|
||||
vec4 _main() {
|
||||
return texture(sampler, vUvs) * tintAlpha;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
_preRender(mesh, renderer) {
|
||||
super._preRender(mesh, renderer);
|
||||
const uniforms = this.uniforms;
|
||||
uniforms.screenDimensions = canvas.screenDimensions;
|
||||
const occlusionMask = canvas.masks.occlusion;
|
||||
uniforms.occlusionTexture = occlusionMask.renderTexture;
|
||||
uniforms.occlusionElevation = occlusionMask.mapElevation(mesh.elevation);
|
||||
uniforms.unoccludedAlpha = mesh.unoccludedAlpha;
|
||||
uniforms.occludedAlpha = mesh.occludedAlpha;
|
||||
const occlusionState = mesh._occlusionState;
|
||||
uniforms.fadeOcclusion = occlusionState.fade;
|
||||
uniforms.radialOcclusion = occlusionState.radial;
|
||||
uniforms.visionOcclusion = occlusionState.vision;
|
||||
}
|
||||
}
|
||||
46
resources/app/client/pixi/webgl/shaders/samplers/primary.js
Normal file
46
resources/app/client/pixi/webgl/shaders/samplers/primary.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* The base shader class of {@link PrimarySpriteMesh}.
|
||||
*/
|
||||
class PrimaryBaseSamplerShader extends OccludableSamplerShader {
|
||||
|
||||
/**
|
||||
* The depth shader class associated with this shader.
|
||||
* @type {typeof DepthSamplerShader}
|
||||
*/
|
||||
static depthShaderClass = DepthSamplerShader;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The depth shader associated with this shader.
|
||||
* The depth shader is lazily constructed.
|
||||
* @type {DepthSamplerShader}
|
||||
*/
|
||||
get depthShader() {
|
||||
return this.#depthShader ??= this.#createDepthShader();
|
||||
}
|
||||
|
||||
#depthShader;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create the depth shader and configure it.
|
||||
* @returns {DepthSamplerShader}
|
||||
*/
|
||||
#createDepthShader() {
|
||||
const depthShader = this.constructor.depthShaderClass.create();
|
||||
this._configureDepthShader(depthShader);
|
||||
return depthShader;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* One-time configuration that is called when the depth shader is created.
|
||||
* @param {DepthSamplerShader} depthShader The depth shader
|
||||
* @protected
|
||||
*/
|
||||
_configureDepthShader(depthShader) {}
|
||||
}
|
||||
|
||||
339
resources/app/client/pixi/webgl/shaders/samplers/token-ring.js
Normal file
339
resources/app/client/pixi/webgl/shaders/samplers/token-ring.js
Normal file
@@ -0,0 +1,339 @@
|
||||
/**
|
||||
* The shader definition which powers the TokenRing.
|
||||
*/
|
||||
class TokenRingSamplerShader extends PrimaryBaseSamplerShader {
|
||||
|
||||
/** @override */
|
||||
static classPluginName = "tokenRingBatch";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static pausable = false;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static batchGeometry = [
|
||||
...(super.batchGeometry ?? []),
|
||||
{id: "aRingTextureCoord", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aBackgroundTextureCoord", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aRingColor", size: 4, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aBackgroundColor", size: 4, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE},
|
||||
{id: "aStates", size: 1, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aScaleCorrection", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aRingColorBand", size: 2, normalized: false, type: PIXI.TYPES.FLOAT},
|
||||
{id: "aTextureScaleCorrection", size: 1, normalized: false, type: PIXI.TYPES.FLOAT}
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static batchVertexSize = super.batchVertexSize + 12;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static reservedTextureUnits = super.reservedTextureUnits + 1;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* A null UVs array used for nulled texture position.
|
||||
* @type {Float32Array}
|
||||
*/
|
||||
static nullUvs = new Float32Array([0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static batchDefaultUniforms(maxTex) {
|
||||
return {
|
||||
...super.batchDefaultUniforms(maxTex),
|
||||
tokenRingTexture: maxTex + super.reservedTextureUnits,
|
||||
time: 0
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static _preRenderBatch(batchRenderer) {
|
||||
super._preRenderBatch(batchRenderer);
|
||||
batchRenderer.renderer.texture.bind(CONFIG.Token.ring.ringClass.baseTexture,
|
||||
batchRenderer.uniforms.tokenRingTexture);
|
||||
batchRenderer.uniforms.time = canvas.app.ticker.lastTime / 1000;
|
||||
batchRenderer.uniforms.debugColorBands = CONFIG.Token.ring.debugColorBands;
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static _packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex) {
|
||||
super._packInterleavedGeometry(element, attributeBuffer, indexBuffer, aIndex, iIndex);
|
||||
const {float32View, uint32View} = attributeBuffer;
|
||||
|
||||
// Prepare token ring attributes
|
||||
const vertexData = element.vertexData;
|
||||
const trConfig = CONFIG.Token.ringClass;
|
||||
const object = element.object.object || {};
|
||||
const ringColor = PIXI.Color.shared.setValue(object.ring?.ringColorLittleEndian ?? 0xFFFFFF).toNumber();
|
||||
const bkgColor = PIXI.Color.shared.setValue(object.ring?.bkgColorLittleEndian ?? 0xFFFFFF).toNumber();
|
||||
const ringUvsFloat = object.ring?.ringUVs ?? trConfig.tokenRingSamplerShader.nullUvs;
|
||||
const bkgUvsFloat = object.ring?.bkgUVs ?? trConfig.tokenRingSamplerShader.nullUvs;
|
||||
const states = (object.ring?.effects ?? 0) + 0.5;
|
||||
const scaleCorrectionX = (object.ring?.scaleCorrection ?? 1) * (object.ring?.scaleAdjustmentX ?? 1);
|
||||
const scaleCorrectionY = (object.ring?.scaleCorrection ?? 1) * (object.ring?.scaleAdjustmentY ?? 1);
|
||||
const colorBandRadiusStart = object.ring?.colorBand.startRadius ?? 0;
|
||||
const colorBandRadiusEnd = object.ring?.colorBand.endRadius ?? 0;
|
||||
const textureScaleAdjustment = object.ring?.textureScaleAdjustment ?? 1;
|
||||
|
||||
// Write attributes into buffer
|
||||
const vertexSize = this.vertexSize;
|
||||
const attributeOffset = PrimaryBaseSamplerShader.batchVertexSize;
|
||||
for ( let i = 0, j = attributeOffset; i < vertexData.length; i += 2, j += vertexSize ) {
|
||||
let k = aIndex + j;
|
||||
float32View[k++] = ringUvsFloat[i];
|
||||
float32View[k++] = ringUvsFloat[i + 1];
|
||||
float32View[k++] = bkgUvsFloat[i];
|
||||
float32View[k++] = bkgUvsFloat[i + 1];
|
||||
uint32View[k++] = ringColor;
|
||||
uint32View[k++] = bkgColor;
|
||||
float32View[k++] = states;
|
||||
float32View[k++] = scaleCorrectionX;
|
||||
float32View[k++] = scaleCorrectionY;
|
||||
float32View[k++] = colorBandRadiusStart;
|
||||
float32View[k++] = colorBandRadiusEnd;
|
||||
float32View[k++] = textureScaleAdjustment;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* GLSL Shader Code */
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* The fragment shader header.
|
||||
* @type {string}
|
||||
*/
|
||||
static #FRAG_HEADER = `
|
||||
const uint STATE_RING_PULSE = 0x02U;
|
||||
const uint STATE_RING_GRADIENT = 0x04U;
|
||||
const uint STATE_BKG_WAVE = 0x08U;
|
||||
const uint STATE_INVISIBLE = 0x10U;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
bool hasState(in uint state) {
|
||||
return (vStates & state) == state;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
vec2 rotation(in vec2 uv, in float a) {
|
||||
uv -= 0.5;
|
||||
float s = sin(a);
|
||||
float c = cos(a);
|
||||
return uv * mat2(c, -s, s, c) + 0.5;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
float normalizedCos(in float val) {
|
||||
return (cos(val) + 1.0) * 0.5;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
float wave(in float dist) {
|
||||
float sinWave = 0.5 * (sin(-time * 4.0 + dist * 100.0) + 1.0);
|
||||
return mix(1.0, 0.55 * sinWave + 0.8, clamp(1.0 - dist, 0.0, 1.0));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
vec4 colorizeTokenRing(in vec4 tokenRing, in float dist) {
|
||||
if ( tokenRing.a > 0.0 ) tokenRing.rgb /= tokenRing.a;
|
||||
vec3 rcol = hasState(STATE_RING_PULSE)
|
||||
? mix(tokenRing.rrr, tokenRing.rrr * 0.35, (cos(time * 2.0) + 1.0) * 0.5)
|
||||
: tokenRing.rrr;
|
||||
vec3 ccol = vRingColor * rcol;
|
||||
vec3 gcol = hasState(STATE_RING_GRADIENT)
|
||||
? mix(ccol, vBackgroundColor * tokenRing.r, smoothstep(0.0, 1.0, dot(rotation(vTextureCoord, time), vec2(0.5))))
|
||||
: ccol;
|
||||
vec3 col = mix(tokenRing.rgb, gcol, step(vRingColorBand.x, dist) - step(vRingColorBand.y, dist));
|
||||
return vec4(col, 1.0) * tokenRing.a;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
vec4 colorizeTokenBackground(in vec4 tokenBackground, in float dist) {
|
||||
if (tokenBackground.a > 0.0) tokenBackground.rgb /= tokenBackground.a;
|
||||
|
||||
float wave = hasState(STATE_BKG_WAVE) ? (0.5 + wave(dist) * 1.5) : 1.0;
|
||||
vec3 bgColor = tokenBackground.rgb;
|
||||
vec3 tintColor = vBackgroundColor.rgb;
|
||||
vec3 resultColor;
|
||||
|
||||
// Overlay blend mode
|
||||
if ( tintColor == vec3(1.0, 1.0, 1.0) ) {
|
||||
// If tint color is pure white, keep the original background color
|
||||
resultColor = bgColor;
|
||||
} else {
|
||||
// Overlay blend mode
|
||||
for ( int i = 0; i < 3; i++ ) {
|
||||
if ( bgColor[i] < 0.5 ) resultColor[i] = 2.0 * bgColor[i] * tintColor[i];
|
||||
else resultColor[i] = 1.0 - 2.0 * (1.0 - bgColor[i]) * (1.0 - tintColor[i]);
|
||||
}
|
||||
}
|
||||
return vec4(resultColor, 1.0) * tokenBackground.a * wave;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
vec4 processTokenColor(in vec4 finalColor) {
|
||||
if ( !hasState(STATE_INVISIBLE) ) return finalColor;
|
||||
|
||||
// Computing halo
|
||||
float lum = perceivedBrightness(finalColor.rgb);
|
||||
vec3 haloColor = vec3(lum) * vec3(0.5, 1.0, 1.0);
|
||||
|
||||
// Construct final image
|
||||
return vec4(haloColor, 1.0) * finalColor.a
|
||||
* (0.55 + normalizedCos(time * 2.0) * 0.25);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
vec4 blend(vec4 src, vec4 dst) {
|
||||
return src + (dst * (1.0 - src.a));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
float getTokenTextureClip() {
|
||||
return step(3.5,
|
||||
step(0.0, vTextureCoord.x) +
|
||||
step(0.0, vTextureCoord.y) +
|
||||
step(vTextureCoord.x, 1.0) +
|
||||
step(vTextureCoord.y, 1.0));
|
||||
}
|
||||
`;
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* Fragment shader body.
|
||||
* @type {string}
|
||||
*/
|
||||
static #FRAG_MAIN = `
|
||||
vec4 color;
|
||||
vec4 result;
|
||||
|
||||
%forloop%
|
||||
|
||||
if ( vStates == 0U ) result = color * vColor;
|
||||
else {
|
||||
// Compute distances
|
||||
vec2 scaledDistVec = (vOrigTextureCoord - 0.5) * 2.0 * vScaleCorrection;
|
||||
|
||||
// Euclidean distance computation
|
||||
float dist = length(scaledDistVec);
|
||||
|
||||
// Rectangular distance computation
|
||||
vec2 absScaledDistVec = abs(scaledDistVec);
|
||||
float rectangularDist = max(absScaledDistVec.x, absScaledDistVec.y);
|
||||
|
||||
// Clip token texture color (necessary when a mesh is padded on x and/or y axis)
|
||||
color *= getTokenTextureClip();
|
||||
|
||||
// Blend token texture, token ring and token background
|
||||
result = blend(
|
||||
processTokenColor(color * (vColor / vColor.a)),
|
||||
blend(
|
||||
colorizeTokenRing(texture(tokenRingTexture, vRingTextureCoord), dist),
|
||||
colorizeTokenBackground(texture(tokenRingTexture, vBackgroundTextureCoord), dist)
|
||||
) * step(rectangularDist, 1.0)
|
||||
) * vColor.a;
|
||||
}
|
||||
`;
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* Fragment shader body for debug code.
|
||||
* @type {string}
|
||||
*/
|
||||
static #FRAG_MAIN_DEBUG = `
|
||||
if ( debugColorBands ) {
|
||||
vec2 scaledDistVec = (vTextureCoord - 0.5) * 2.0 * vScaleCorrection;
|
||||
float dist = length(scaledDistVec);
|
||||
result.rgb += vec3(0.0, 0.5, 0.0) * (step(vRingColorBand.x, dist) - step(vRingColorBand.y, dist));
|
||||
}
|
||||
`;
|
||||
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static _batchVertexShader = `
|
||||
in vec2 aRingTextureCoord;
|
||||
in vec2 aBackgroundTextureCoord;
|
||||
in vec2 aScaleCorrection;
|
||||
in vec2 aRingColorBand;
|
||||
in vec4 aRingColor;
|
||||
in vec4 aBackgroundColor;
|
||||
in float aTextureScaleCorrection;
|
||||
in float aStates;
|
||||
|
||||
out vec2 vRingTextureCoord;
|
||||
out vec2 vBackgroundTextureCoord;
|
||||
out vec2 vOrigTextureCoord;
|
||||
flat out vec2 vRingColorBand;
|
||||
flat out vec3 vRingColor;
|
||||
flat out vec3 vBackgroundColor;
|
||||
flat out vec2 vScaleCorrection;
|
||||
flat out uint vStates;
|
||||
|
||||
void _main(out vec2 vertexPosition, out vec2 textureCoord, out vec4 color) {
|
||||
vRingTextureCoord = aRingTextureCoord;
|
||||
vBackgroundTextureCoord = aBackgroundTextureCoord;
|
||||
vRingColor = aRingColor.rgb;
|
||||
vBackgroundColor = aBackgroundColor.rgb;
|
||||
vStates = uint(aStates);
|
||||
vScaleCorrection = aScaleCorrection;
|
||||
vRingColorBand = aRingColorBand;
|
||||
vOrigTextureCoord = aTextureCoord;
|
||||
vertexPosition = (translationMatrix * vec3(aVertexPosition, 1.0)).xy;
|
||||
textureCoord = (aTextureCoord - 0.5) * aTextureScaleCorrection + 0.5;
|
||||
color = aColor * tint;
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static _batchFragmentShader = `
|
||||
in vec2 vRingTextureCoord;
|
||||
in vec2 vBackgroundTextureCoord;
|
||||
in vec2 vOrigTextureCoord;
|
||||
flat in vec3 vRingColor;
|
||||
flat in vec3 vBackgroundColor;
|
||||
flat in vec2 vScaleCorrection;
|
||||
flat in vec2 vRingColorBand;
|
||||
flat in uint vStates;
|
||||
|
||||
uniform sampler2D tokenRingTexture;
|
||||
uniform float time;
|
||||
uniform bool debugColorBands;
|
||||
|
||||
${this.CONSTANTS}
|
||||
${this.PERCEIVED_BRIGHTNESS}
|
||||
${TokenRingSamplerShader.#FRAG_HEADER}
|
||||
|
||||
vec4 _main() {
|
||||
${TokenRingSamplerShader.#FRAG_MAIN}
|
||||
${TokenRingSamplerShader.#FRAG_MAIN_DEBUG}
|
||||
return result;
|
||||
}
|
||||
`;
|
||||
}
|
||||
Reference in New Issue
Block a user