2023-12-30 02:04:40 +00:00
|
|
|
import BattleScene from "../battle-scene";
|
2024-03-10 02:57:33 +00:00
|
|
|
import { TerrainType, getTerrainColor } from "../data/terrain";
|
2023-12-30 02:04:40 +00:00
|
|
|
import * as Utils from "../utils";
|
|
|
|
|
|
|
|
const spriteFragShader = `
|
|
|
|
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
|
|
|
precision highp float;
|
|
|
|
#else
|
|
|
|
precision mediump float;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uniform sampler2D uMainSampler[%count%];
|
|
|
|
|
|
|
|
varying vec2 outTexCoord;
|
|
|
|
varying float outTexId;
|
|
|
|
varying float outTintEffect;
|
|
|
|
varying vec4 outTint;
|
|
|
|
|
|
|
|
uniform float time;
|
2023-12-30 20:44:20 +00:00
|
|
|
uniform int ignoreTimeTint;
|
2023-12-30 02:04:40 +00:00
|
|
|
uniform int isOutside;
|
|
|
|
uniform vec3 dayTint;
|
|
|
|
uniform vec3 duskTint;
|
|
|
|
uniform vec3 nightTint;
|
2024-03-10 02:57:33 +00:00
|
|
|
uniform vec3 terrainColor;
|
|
|
|
uniform float terrainColorRatio;
|
2023-12-30 02:04:40 +00:00
|
|
|
|
|
|
|
float blendOverlay(float base, float blend) {
|
|
|
|
return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend));
|
|
|
|
}
|
|
|
|
|
|
|
|
vec3 blendOverlay(vec3 base, vec3 blend) {
|
|
|
|
return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b));
|
|
|
|
}
|
|
|
|
|
|
|
|
vec3 blendHardLight(vec3 base, vec3 blend) {
|
|
|
|
return blendOverlay(blend, base);
|
|
|
|
}
|
|
|
|
|
2024-03-10 02:57:33 +00:00
|
|
|
float hue2rgb(float f1, float f2, float hue) {
|
|
|
|
if (hue < 0.0)
|
|
|
|
hue += 1.0;
|
|
|
|
else if (hue > 1.0)
|
|
|
|
hue -= 1.0;
|
|
|
|
float res;
|
|
|
|
if ((6.0 * hue) < 1.0)
|
|
|
|
res = f1 + (f2 - f1) * 6.0 * hue;
|
|
|
|
else if ((2.0 * hue) < 1.0)
|
|
|
|
res = f2;
|
|
|
|
else if ((3.0 * hue) < 2.0)
|
|
|
|
res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
|
|
|
|
else
|
|
|
|
res = f1;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec3 rgb2hsl(vec3 color) {
|
|
|
|
vec3 hsl;
|
|
|
|
|
|
|
|
float fmin = min(min(color.r, color.g), color.b);
|
|
|
|
float fmax = max(max(color.r, color.g), color.b);
|
|
|
|
float delta = fmax - fmin;
|
|
|
|
|
|
|
|
hsl.z = (fmax + fmin) / 2.0;
|
|
|
|
|
|
|
|
if (delta == 0.0) {
|
|
|
|
hsl.x = 0.0;
|
|
|
|
hsl.y = 0.0;
|
|
|
|
} else {
|
|
|
|
if (hsl.z < 0.5)
|
|
|
|
hsl.y = delta / (fmax + fmin);
|
|
|
|
else
|
|
|
|
hsl.y = delta / (2.0 - fmax - fmin);
|
|
|
|
|
|
|
|
float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;
|
|
|
|
float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;
|
|
|
|
float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;
|
|
|
|
|
|
|
|
if (color.r == fmax )
|
|
|
|
hsl.x = deltaB - deltaG;
|
|
|
|
else if (color.g == fmax)
|
|
|
|
hsl.x = (1.0 / 3.0) + deltaR - deltaB;
|
|
|
|
else if (color.b == fmax)
|
|
|
|
hsl.x = (2.0 / 3.0) + deltaG - deltaR;
|
|
|
|
|
|
|
|
if (hsl.x < 0.0)
|
|
|
|
hsl.x += 1.0;
|
|
|
|
else if (hsl.x > 1.0)
|
|
|
|
hsl.x -= 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hsl;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec3 hsl2rgb(vec3 hsl) {
|
|
|
|
vec3 rgb;
|
|
|
|
|
|
|
|
if (hsl.y == 0.0)
|
|
|
|
rgb = vec3(hsl.z);
|
|
|
|
else {
|
|
|
|
float f2;
|
|
|
|
|
|
|
|
if (hsl.z < 0.5)
|
|
|
|
f2 = hsl.z * (1.0 + hsl.y);
|
|
|
|
else
|
|
|
|
f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);
|
|
|
|
|
|
|
|
float f1 = 2.0 * hsl.z - f2;
|
|
|
|
|
|
|
|
rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0));
|
|
|
|
rgb.g = hue2rgb(f1, f2, hsl.x);
|
2024-03-21 17:12:05 +00:00
|
|
|
rgb.b = hue2rgb(f1, f2, hsl.x - (1.0/3.0));
|
2024-03-10 02:57:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rgb;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec3 blendHue(vec3 base, vec3 blend) {
|
|
|
|
vec3 baseHSL = rgb2hsl(base);
|
|
|
|
return hsl2rgb(vec3(rgb2hsl(blend).r, baseHSL.g, baseHSL.b));
|
|
|
|
}
|
|
|
|
|
2024-02-17 05:40:03 +00:00
|
|
|
void main() {
|
2023-12-30 02:04:40 +00:00
|
|
|
vec4 texture;
|
|
|
|
|
|
|
|
%forloop%
|
|
|
|
|
|
|
|
vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);
|
|
|
|
|
|
|
|
// Multiply texture tint
|
|
|
|
vec4 color = texture * texel;
|
|
|
|
|
|
|
|
if (outTintEffect == 1.0) {
|
|
|
|
// Solid color + texture alpha
|
|
|
|
color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a);
|
|
|
|
} else if (outTintEffect == 2.0) {
|
|
|
|
// Solid color, no texture
|
|
|
|
color = texel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply day/night tint */
|
2023-12-30 20:44:20 +00:00
|
|
|
if (color.a > 0.0 && ignoreTimeTint == 0) {
|
2023-12-30 02:04:40 +00:00
|
|
|
vec3 dayNightTint;
|
|
|
|
|
|
|
|
if (time < 0.25) {
|
|
|
|
dayNightTint = dayTint;
|
|
|
|
} else if (isOutside == 0 && time < 0.5) {
|
|
|
|
dayNightTint = mix(dayTint, nightTint, (time - 0.25) / 0.25);
|
|
|
|
} else if (time < 0.375) {
|
|
|
|
dayNightTint = mix(dayTint, duskTint, (time - 0.25) / 0.125);
|
|
|
|
} else if (time < 0.5) {
|
|
|
|
dayNightTint = mix(duskTint, nightTint, (time - 0.375) / 0.125);
|
|
|
|
} else if (time < 0.75) {
|
|
|
|
dayNightTint = nightTint;
|
|
|
|
} else if (isOutside == 0) {
|
|
|
|
dayNightTint = mix(nightTint, dayTint, (time - 0.75) / 0.25);
|
|
|
|
} else if (time < 0.875) {
|
|
|
|
dayNightTint = mix(nightTint, duskTint, (time - 0.75) / 0.125);
|
|
|
|
} else {
|
|
|
|
dayNightTint = mix(duskTint, dayTint, (time - 0.875) / 0.125);
|
|
|
|
}
|
|
|
|
|
|
|
|
color = vec4(blendHardLight(color.rgb, dayNightTint), color.a);
|
|
|
|
}
|
|
|
|
|
2024-03-31 17:00:54 +01:00
|
|
|
if (terrainColorRatio > 0.0 && (1.0 - terrainColorRatio) < outTexCoord.y) {
|
|
|
|
if (color.a > 0.0 && (terrainColor.r > 0.0 || terrainColor.g > 0.0 || terrainColor.b > 0.0)) {
|
2024-03-10 02:57:33 +00:00
|
|
|
color.rgb = mix(color.rgb, blendHue(color.rgb, terrainColor), 1.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-30 02:04:40 +00:00
|
|
|
gl_FragColor = color;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
const spriteVertShader = `
|
|
|
|
precision mediump float;
|
|
|
|
|
|
|
|
uniform mat4 uProjectionMatrix;
|
2024-02-17 05:40:03 +00:00
|
|
|
uniform int uRoundPixels;
|
|
|
|
uniform vec2 uResolution;
|
2023-12-30 02:04:40 +00:00
|
|
|
|
|
|
|
attribute vec2 inPosition;
|
|
|
|
attribute vec2 inTexCoord;
|
|
|
|
attribute float inTexId;
|
|
|
|
attribute float inTintEffect;
|
|
|
|
attribute vec4 inTint;
|
|
|
|
|
|
|
|
varying vec2 outTexCoord;
|
|
|
|
varying float outTexId;
|
2024-02-17 05:40:03 +00:00
|
|
|
varying vec2 outPosition;
|
2023-12-30 02:04:40 +00:00
|
|
|
varying float outTintEffect;
|
|
|
|
varying vec4 outTint;
|
|
|
|
|
2024-02-17 05:40:03 +00:00
|
|
|
void main() {
|
2023-12-30 02:04:40 +00:00
|
|
|
gl_Position = uProjectionMatrix * vec4(inPosition, 1.0, 1.0);
|
2024-02-17 05:40:03 +00:00
|
|
|
if (uRoundPixels == 1)
|
|
|
|
{
|
|
|
|
gl_Position.xy = floor(((gl_Position.xy + 1.0) * 0.5 * uResolution) + 0.5) / uResolution * 2.0 - 1.0;
|
|
|
|
}
|
2023-12-30 02:04:40 +00:00
|
|
|
outTexCoord = inTexCoord;
|
|
|
|
outTexId = inTexId;
|
2024-02-17 05:40:03 +00:00
|
|
|
outPosition = inPosition;
|
2023-12-30 02:04:40 +00:00
|
|
|
outTint = inTint;
|
|
|
|
outTintEffect = inTintEffect;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline {
|
|
|
|
constructor(game: Phaser.Game, config?: Phaser.Types.Renderer.WebGL.WebGLPipelineConfig) {
|
|
|
|
super(config || {
|
|
|
|
game: game,
|
|
|
|
name: 'field-sprite',
|
|
|
|
fragShader: spriteFragShader,
|
|
|
|
vertShader: spriteVertShader
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onPreRender(): void {
|
|
|
|
this.set1f('time', 0);
|
2023-12-30 20:44:20 +00:00
|
|
|
this.set1i('ignoreTimeTint', 0);
|
2024-03-10 02:57:33 +00:00
|
|
|
this.set1f('terrainColorRatio', 0);
|
|
|
|
this.set3fv('terrainColor', [ 0, 0, 0 ]);
|
2023-12-30 02:04:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onBind(gameObject: Phaser.GameObjects.GameObject): void {
|
|
|
|
super.onBind();
|
|
|
|
|
2024-03-31 17:00:54 +01:00
|
|
|
const sprite = gameObject as Phaser.GameObjects.Sprite | Phaser.GameObjects.NineSlice;
|
2023-12-30 02:04:40 +00:00
|
|
|
const scene = sprite.scene as BattleScene;
|
|
|
|
|
2023-12-30 20:44:20 +00:00
|
|
|
const data = sprite.pipelineData;
|
|
|
|
const ignoreTimeTint = data['ignoreTimeTint'] as boolean;
|
2024-03-10 02:57:33 +00:00
|
|
|
const terrainColorRatio = data['terrainColorRatio'] as number || 0;
|
2023-12-30 20:44:20 +00:00
|
|
|
|
2023-12-30 02:04:40 +00:00
|
|
|
let time = scene.currentBattle?.waveIndex
|
2024-03-16 01:59:34 +00:00
|
|
|
? ((scene.currentBattle.waveIndex + scene.waveCycleOffset) % 40) / 40 // ((new Date().getSeconds() * 1000 + new Date().getMilliseconds()) % 10000) / 10000
|
2023-12-30 02:04:40 +00:00
|
|
|
: Utils.getCurrentTime();
|
2023-12-30 20:44:20 +00:00
|
|
|
this.set1f('time', time);
|
|
|
|
this.set1i('ignoreTimeTint', ignoreTimeTint ? 1 : 0);
|
2023-12-30 02:04:40 +00:00
|
|
|
this.set1i('isOutside', scene.arena.isOutside() ? 1 : 0);
|
|
|
|
this.set3fv('dayTint', scene.arena.getDayTint().map(c => c / 255));
|
|
|
|
this.set3fv('duskTint', scene.arena.getDuskTint().map(c => c / 255));
|
|
|
|
this.set3fv('nightTint', scene.arena.getNightTint().map(c => c / 255));
|
2024-03-10 02:57:33 +00:00
|
|
|
this.set3fv('terrainColor', getTerrainColor(scene.arena.terrain?.terrainType || TerrainType.NONE).map(c => c / 255));
|
|
|
|
this.set1f('terrainColorRatio', terrainColorRatio);
|
2023-12-30 02:04:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onBatch(gameObject: Phaser.GameObjects.GameObject): void {
|
|
|
|
if (gameObject)
|
|
|
|
this.flush();
|
|
|
|
}
|
|
|
|
}
|