Initial
This commit is contained in:
25
resources/app/client-esm/canvas/smaa/LICENSE
Normal file
25
resources/app/client-esm/canvas/smaa/LICENSE
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
|
||||
Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
|
||||
Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
|
||||
Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
|
||||
Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
|
||||
|
||||
Copyright (C) 2018 Damien Seguin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
109
resources/app/client-esm/canvas/smaa/blend.mjs
Normal file
109
resources/app/client-esm/canvas/smaa/blend.mjs
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* The neighborhood blending filter for {@link foundry.canvas.SMAAFilter}.
|
||||
*/
|
||||
export default class SMAANeighborhoodBlendingFilter extends PIXI.Filter {
|
||||
constructor() {
|
||||
super(VERTEX_SOURCE, FRAGMENT_SOURCE);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The vertex shader source of {@link SMAANeighborhoodBlendingFilter}.
|
||||
* @type {string}
|
||||
*/
|
||||
const VERTEX_SOURCE = `\
|
||||
#define mad(a, b, c) (a * b + c)
|
||||
|
||||
attribute vec2 aVertexPosition;
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
uniform vec4 inputSize;
|
||||
uniform vec4 inputPixel;
|
||||
uniform vec4 outputFrame;
|
||||
|
||||
#define resolution (inputPixel.xy)
|
||||
#define SMAA_RT_METRICS (inputPixel.zwxy)
|
||||
|
||||
varying vec2 vTexCoord0;
|
||||
varying vec4 vOffset;
|
||||
|
||||
void main() {
|
||||
vTexCoord0 = aVertexPosition * (outputFrame.zw * inputSize.zw);
|
||||
vOffset = mad(SMAA_RT_METRICS.xyxy, vec4(1.0, 0.0, 0.0, 1.0), vTexCoord0.xyxy);
|
||||
|
||||
vec3 position = vec3(aVertexPosition * max(outputFrame.zw, vec2(0.0)) + outputFrame.xy, 1.0);
|
||||
gl_Position = vec4((projectionMatrix * position).xy, 0.0, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The fragment shader source of {@link SMAANeighborhoodBlendingFilter}.
|
||||
* @type {string}
|
||||
*/
|
||||
const FRAGMENT_SOURCE = `\
|
||||
precision highp float;
|
||||
|
||||
#define mad(a, b, c) (a * b + c)
|
||||
|
||||
uniform sampler2D blendTex;
|
||||
uniform sampler2D uSampler; // colorTex
|
||||
uniform vec4 inputPixel;
|
||||
|
||||
#define colorTex uSampler
|
||||
#define resolution (inputPixel.xy)
|
||||
#define SMAA_RT_METRICS (inputPixel.zwxy)
|
||||
|
||||
varying vec2 vTexCoord0;
|
||||
varying vec4 vOffset;
|
||||
|
||||
/**
|
||||
* Conditional move:
|
||||
*/
|
||||
void SMAAMovc(bvec2 cond, inout vec2 variable, vec2 value) {
|
||||
if (cond.x) variable.x = value.x;
|
||||
if (cond.y) variable.y = value.y;
|
||||
}
|
||||
|
||||
void SMAAMovc(bvec4 cond, inout vec4 variable, vec4 value) {
|
||||
SMAAMovc(cond.xy, variable.xy, value.xy);
|
||||
SMAAMovc(cond.zw, variable.zw, value.zw);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 color;
|
||||
|
||||
// Fetch the blending weights for current pixel:
|
||||
vec4 a;
|
||||
a.x = texture2D(blendTex, vOffset.xy).a; // Right
|
||||
a.y = texture2D(blendTex, vOffset.zw).g; // Top
|
||||
a.wz = texture2D(blendTex, vTexCoord0).xz; // Bottom / Left
|
||||
|
||||
// Is there any blending weight with a value greater than 0.0?
|
||||
if (dot(a, vec4(1.0, 1.0, 1.0, 1.0)) <= 1e-5) {
|
||||
color = texture2D(colorTex, vTexCoord0); // LinearSampler
|
||||
} else {
|
||||
bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical)
|
||||
|
||||
// Calculate the blending offsets:
|
||||
vec4 blendingOffset = vec4(0.0, a.y, 0.0, a.w);
|
||||
vec2 blendingWeight = a.yw;
|
||||
SMAAMovc(bvec4(h, h, h, h), blendingOffset, vec4(a.x, 0.0, a.z, 0.0));
|
||||
SMAAMovc(bvec2(h, h), blendingWeight, a.xz);
|
||||
blendingWeight /= dot(blendingWeight, vec2(1.0, 1.0));
|
||||
|
||||
// Calculate the texture coordinates:
|
||||
vec4 blendingCoord = mad(blendingOffset, vec4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), vTexCoord0.xyxy);
|
||||
|
||||
// We exploit bilinear filtering to mix current pixel with the chosen
|
||||
// neighbor:
|
||||
color = blendingWeight.x * texture2D(colorTex, blendingCoord.xy); // LinearSampler
|
||||
color += blendingWeight.y * texture2D(colorTex, blendingCoord.zw); // LinearSampler
|
||||
}
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
`;
|
||||
129
resources/app/client-esm/canvas/smaa/edges.mjs
Normal file
129
resources/app/client-esm/canvas/smaa/edges.mjs
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* The edge detection filter for {@link foundry.canvas.SMAAFilter}.
|
||||
*/
|
||||
export default class SMAAEdgeDetectionFilter extends PIXI.Filter {
|
||||
/**
|
||||
* @param {SMAAFilterConfig} config
|
||||
*/
|
||||
constructor(config) {
|
||||
super(VERTEX_SOURCE, generateFragmentSource(config));
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The vertex shader source of {@link SMAAEdgeDetectionFilter}.
|
||||
* @type {string}
|
||||
*/
|
||||
const VERTEX_SOURCE = `\
|
||||
#define mad(a, b, c) (a * b + c)
|
||||
|
||||
attribute vec2 aVertexPosition;
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
uniform vec4 inputSize;
|
||||
uniform vec4 inputPixel;
|
||||
uniform vec4 outputFrame;
|
||||
|
||||
#define resolution (inputPixel.xy)
|
||||
#define SMAA_RT_METRICS (inputPixel.zwxy)
|
||||
|
||||
varying vec2 vTexCoord0;
|
||||
varying vec4 vOffset[3];
|
||||
|
||||
void main() {
|
||||
vTexCoord0 = aVertexPosition * (outputFrame.zw * inputSize.zw);
|
||||
|
||||
vOffset[0] = mad(SMAA_RT_METRICS.xyxy, vec4(-1.0, 0.0, 0.0, -1.0), vTexCoord0.xyxy);
|
||||
vOffset[1] = mad(SMAA_RT_METRICS.xyxy, vec4( 1.0, 0.0, 0.0, 1.0), vTexCoord0.xyxy);
|
||||
vOffset[2] = mad(SMAA_RT_METRICS.xyxy, vec4(-2.0, 0.0, 0.0, -2.0), vTexCoord0.xyxy);
|
||||
|
||||
vec3 position = vec3(aVertexPosition * max(outputFrame.zw, vec2(0.0)) + outputFrame.xy, 1.0);
|
||||
gl_Position = vec4((projectionMatrix * position).xy, 0.0, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The fragment shader source of {@link SMAAEdgeDetectionFilter}.
|
||||
* @param {SMAAFilterConfig} config
|
||||
* @returns {string}
|
||||
*/
|
||||
function generateFragmentSource(config) {
|
||||
return `\
|
||||
precision highp float;
|
||||
|
||||
/**
|
||||
* Color Edge Detection
|
||||
*
|
||||
* IMPORTANT NOTICE: color edge detection requires gamma-corrected colors, and
|
||||
* thus 'colorTex' should be a non-sRGB texture.
|
||||
*/
|
||||
|
||||
#define SMAA_THRESHOLD ${config.threshold.toFixed(8)}
|
||||
#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR ${config.localContrastAdaptionFactor.toFixed(8)}
|
||||
|
||||
uniform sampler2D uSampler; // colorTex
|
||||
|
||||
#define colorTex uSampler
|
||||
|
||||
varying vec2 vTexCoord0;
|
||||
varying vec4 vOffset[3];
|
||||
|
||||
void main() {
|
||||
// Calculate the threshold:
|
||||
vec2 threshold = vec2(SMAA_THRESHOLD);
|
||||
|
||||
// Calculate color deltas:
|
||||
vec4 delta;
|
||||
vec3 c = texture2D(colorTex, vTexCoord0).rgb;
|
||||
|
||||
vec3 cLeft = texture2D(colorTex, vOffset[0].xy).rgb;
|
||||
vec3 t = abs(c - cLeft);
|
||||
delta.x = max(max(t.r, t.g), t.b);
|
||||
|
||||
vec3 cTop = texture2D(colorTex, vOffset[0].zw).rgb;
|
||||
t = abs(c - cTop);
|
||||
delta.y = max(max(t.r, t.g), t.b);
|
||||
|
||||
// We do the usual threshold:
|
||||
vec2 edges = step(threshold, delta.xy);
|
||||
|
||||
// Then discard if there is no edge:
|
||||
if (dot(edges, vec2(1.0, 1.0)) == 0.0)
|
||||
discard;
|
||||
|
||||
// Calculate right and bottom deltas:
|
||||
vec3 cRight = texture2D(colorTex, vOffset[1].xy).rgb;
|
||||
t = abs(c - cRight);
|
||||
delta.z = max(max(t.r, t.g), t.b);
|
||||
|
||||
vec3 cBottom = texture2D(colorTex, vOffset[1].zw).rgb;
|
||||
t = abs(c - cBottom);
|
||||
delta.w = max(max(t.r, t.g), t.b);
|
||||
|
||||
// Calculate the maximum delta in the direct neighborhood:
|
||||
vec2 maxDelta = max(delta.xy, delta.zw);
|
||||
|
||||
// Calculate left-left and top-top deltas:
|
||||
vec3 cLeftLeft = texture2D(colorTex, vOffset[2].xy).rgb;
|
||||
t = abs(c - cLeftLeft);
|
||||
delta.z = max(max(t.r, t.g), t.b);
|
||||
|
||||
vec3 cTopTop = texture2D(colorTex, vOffset[2].zw).rgb;
|
||||
t = abs(c - cTopTop);
|
||||
delta.w = max(max(t.r, t.g), t.b);
|
||||
|
||||
// Calculate the final maximum delta:
|
||||
maxDelta = max(maxDelta.xy, delta.zw);
|
||||
float finalDelta = max(maxDelta.x, maxDelta.y);
|
||||
|
||||
// Local contrast adaptation:
|
||||
edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
|
||||
|
||||
gl_FragColor = vec4(edges, 0.0, 1.0);
|
||||
}
|
||||
`;
|
||||
}
|
||||
116
resources/app/client-esm/canvas/smaa/smaa.mjs
Normal file
116
resources/app/client-esm/canvas/smaa/smaa.mjs
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
import {default as SMAAEdgeDetectionFilter} from "./edges.mjs";
|
||||
import {default as SMAABlendingWeightCalculationFilter} from "./weights.mjs";
|
||||
import {default as SMAANeighborhoodBlendingFilter} from "./blend.mjs";
|
||||
|
||||
/**
|
||||
* @typedef {object} SMAAFilterConfig
|
||||
* @property {number} threshold Specifies the threshold or sensitivity to edges. Lowering this value you will be able to detect more edges at the expense of performance. Range: [0, 0.5]. 0.1 is a reasonable value, and allows to catch most visible edges. 0.05 is a rather overkill value, that allows to catch 'em all.
|
||||
* @property {number} localContrastAdaptionFactor If there is an neighbor edge that has SMAA_LOCAL_CONTRAST_FACTOR times bigger contrast than current edge, current edge will be discarded.
|
||||
* This allows to eliminate spurious crossing edges, and is based on the fact that, if there is too much contrast in a direction, that will hide perceptually contrast in the other neighbors.
|
||||
* @property {number} maxSearchSteps Specifies the maximum steps performed in the horizontal/vertical pattern searches, at each side of the pixel. In number of pixels, it's actually the double. So the maximum line length perfectly handled by, for example 16, is 64 (by perfectly, we meant that longer lines won't look as good, but still antialiased. Range: [0, 112].
|
||||
* @property {number} maxSearchStepsDiag Specifies the maximum steps performed in the diagonal pattern searches, at each side of the pixel. In this case we jump one pixel at time, instead of two. Range: [0, 20].
|
||||
* @property {number} cornerRounding Specifies how much sharp corners will be rounded. Range: [0, 100].
|
||||
* @property {boolean} disableDiagDetection Is diagonal detection disabled?
|
||||
* @property {boolean} disableCornerDetection Is corner detection disabled?
|
||||
*/
|
||||
|
||||
export default class SMAAFilter extends PIXI.Filter {
|
||||
/**
|
||||
* @param {Partial<SMAAFilterConfig>} [config] The config (defaults: {@link SMAAFilter.PRESETS.DEFAULT})
|
||||
*/
|
||||
constructor({threshold=0.1, localContrastAdaptionFactor=2.0, maxSearchSteps=16, maxSearchStepsDiag=8, cornerRounding=25, disableDiagDetection=false, disableCornerDetection=false}={}) {
|
||||
super();
|
||||
const config = {threshold, localContrastAdaptionFactor, maxSearchSteps, maxSearchStepsDiag, cornerRounding, disableDiagDetection, disableCornerDetection};
|
||||
this.#edgesFilter = new SMAAEdgeDetectionFilter(config);
|
||||
this.#weightsFilter = new SMAABlendingWeightCalculationFilter(config);
|
||||
this.#blendFilter = new SMAANeighborhoodBlendingFilter();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The presets.
|
||||
* @enum {SMAAFilterConfig}
|
||||
*/
|
||||
static get PRESETS() {
|
||||
return SMAAFilter.#PRESETS;
|
||||
}
|
||||
|
||||
static #PRESETS = {
|
||||
LOW: {
|
||||
threshold: 0.15,
|
||||
localContrastAdaptionFactor: 2.0,
|
||||
maxSearchSteps: 4,
|
||||
maxSearchStepsDiag: 0,
|
||||
cornerRounding: 0,
|
||||
disableDiagDetection: true,
|
||||
disableCornerDetection: true
|
||||
},
|
||||
MEDIUM: {
|
||||
threshold: 0.1,
|
||||
localContrastAdaptionFactor: 2.0,
|
||||
maxSearchSteps: 8,
|
||||
maxSearchStepsDiag: 0,
|
||||
cornerRounding: 0,
|
||||
disableDiagDetection: true,
|
||||
disableCornerDetection: true
|
||||
},
|
||||
HIGH: {
|
||||
threshold: 0.1,
|
||||
localContrastAdaptionFactor: 2.0,
|
||||
maxSearchSteps: 16,
|
||||
maxSearchStepsDiag: 8,
|
||||
cornerRounding: 25,
|
||||
disableDiagDetection: false,
|
||||
disableCornerDetection: false
|
||||
},
|
||||
ULTRA: {
|
||||
threshold: 0.05,
|
||||
localContrastAdaptionFactor: 2.0,
|
||||
maxSearchSteps: 32,
|
||||
maxSearchStepsDiag: 16,
|
||||
cornerRounding: 25,
|
||||
disableDiagDetection: false,
|
||||
disableCornerDetection: false
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The edge detection filter.
|
||||
* @type {SMAAEdgeDetectionFilter}
|
||||
*/
|
||||
#edgesFilter;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The blending weight calculation filter.
|
||||
* @type {SMAABlendingWeightCalculationFilter}
|
||||
*/
|
||||
#weightsFilter;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The neighborhood blending filter.
|
||||
* @type {SMAANeighborhoodBlendingFilter}
|
||||
*/
|
||||
#blendFilter;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
apply(filterManager, input, output, clearMode, currentState) {
|
||||
const edgesTex = filterManager.getFilterTexture();
|
||||
const blendTex = filterManager.getFilterTexture();
|
||||
this.#edgesFilter.apply(filterManager, input, edgesTex, PIXI.CLEAR_MODES.CLEAR, currentState);
|
||||
this.#weightsFilter.apply(filterManager, edgesTex, blendTex, PIXI.CLEAR_MODES.CLEAR, currentState);
|
||||
this.#blendFilter.uniforms.blendTex = blendTex;
|
||||
this.#blendFilter.apply(filterManager, input, output, clearMode, currentState);
|
||||
filterManager.returnFilterTexture(edgesTex);
|
||||
filterManager.returnFilterTexture(blendTex);
|
||||
}
|
||||
}
|
||||
560
resources/app/client-esm/canvas/smaa/weights.mjs
Normal file
560
resources/app/client-esm/canvas/smaa/weights.mjs
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user