Add shader for sprite tone

This commit is contained in:
Flashfyre 2023-06-02 18:33:51 -04:00
parent 3fc830f401
commit bf2eca2851
5 changed files with 105 additions and 6 deletions

View File

@ -22,6 +22,7 @@ import AbilityBar from './ui/ability-bar';
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, applyAbAttrs, initAbilities } from './data/ability'; import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, applyAbAttrs, initAbilities } from './data/ability';
import Battle from './battle'; import Battle from './battle';
import { GameMode } from './game-mode'; import { GameMode } from './game-mode';
import SpritePipeline from './pipelines/sprite';
const enableAuto = true; const enableAuto = true;
const quickStart = false; const quickStart = false;
@ -87,7 +88,7 @@ export default class BattleScene extends Phaser.Scene {
public uiContainer: Phaser.GameObjects.Container; public uiContainer: Phaser.GameObjects.Container;
public ui: UI; public ui: UI;
//public spritePipeline: SpritePipeline; public spritePipeline: SpritePipeline;
private bgm: Phaser.Sound.BaseSound; private bgm: Phaser.Sound.BaseSound;
private bgmResumeTimer: Phaser.Time.TimerEvent; private bgmResumeTimer: Phaser.Time.TimerEvent;
@ -295,7 +296,8 @@ export default class BattleScene extends Phaser.Scene {
this.load.setBaseURL(); this.load.setBaseURL();
//this.spritePipeline = (this.renderer as Phaser.Renderer.WebGL.WebGLRenderer).pipelines.get('Sprite') as SpritePipeline; this.spritePipeline = new SpritePipeline(this.game);
(this.renderer as Phaser.Renderer.WebGL.WebGLRenderer).pipelines.add('Sprite', this.spritePipeline);
this.time.delayedCall(20, () => this.launchBattle()); this.time.delayedCall(20, () => this.launchBattle());
} }

View File

@ -666,6 +666,7 @@ export abstract class BattleAnim {
const spriteSource = isUser ? userSprite : targetSprite; const spriteSource = isUser ? userSprite : targetSprite;
let sprite: Phaser.GameObjects.Sprite; let sprite: Phaser.GameObjects.Sprite;
sprite = scene.add.sprite(0, 0, spriteSource.texture, spriteSource.frame.name); sprite = scene.add.sprite(0, 0, spriteSource.texture, spriteSource.frame.name);
sprite.setPipeline(scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ] });
spriteSource.on('animationupdate', (_anim, frame) => sprite.setFrame(frame.textureFrame)); spriteSource.on('animationupdate', (_anim, frame) => sprite.setFrame(frame.textureFrame));
scene.field.add(sprite); scene.field.add(sprite);
sprites.push(sprite); sprites.push(sprite);
@ -682,6 +683,7 @@ export abstract class BattleAnim {
pokemonSprite.setData('locked', frame.locked); pokemonSprite.setData('locked', frame.locked);
pokemonSprite.setAlpha(frame.opacity / 255); pokemonSprite.setAlpha(frame.opacity / 255);
pokemonSprite.pipelineData['tone'] = frame.tone;
pokemonSprite.setVisible(frame.visible && (isUser ? user.visible : target.visible)); pokemonSprite.setVisible(frame.visible && (isUser ? user.visible : target.visible));
pokemonSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE); pokemonSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE);
} else { } else {
@ -778,10 +780,12 @@ export abstract class BattleAnim {
userSprite.setPosition(0, 0); userSprite.setPosition(0, 0);
userSprite.setScale(1); userSprite.setScale(1);
userSprite.setAlpha(1); userSprite.setAlpha(1);
userSprite.pipelineData['tone'] = [ 0.0, 0.0, 0.0, 0.0 ];
userSprite.setAngle(0); userSprite.setAngle(0);
targetSprite.setPosition(0, 0); targetSprite.setPosition(0, 0);
targetSprite.setScale(1); targetSprite.setScale(1);
targetSprite.setAlpha(1); targetSprite.setAlpha(1);
targetSprite.pipelineData['tone'] = [ 0.0, 0.0, 0.0, 0.0 ];
targetSprite.setAngle(0); targetSprite.setAngle(0);
userSprite.setVisible(true); userSprite.setVisible(true);
targetSprite.setVisible(true); targetSprite.setVisible(true);

View File

@ -1,6 +1,6 @@
import Phaser from 'phaser'; import Phaser from 'phaser';
import BattleScene from './battle-scene'; import BattleScene from './battle-scene';
//import SpritePipeline from './pipelines/sprite'; import SpritePipeline from './pipelines/sprite';
const config: Phaser.Types.Core.GameConfig = { const config: Phaser.Types.Core.GameConfig = {
type: Phaser.WEBGL, type: Phaser.WEBGL,
@ -11,7 +11,6 @@ const config: Phaser.Types.Core.GameConfig = {
mode: Phaser.Scale.FIT mode: Phaser.Scale.FIT
}, },
pixelArt: true, pixelArt: true,
//pipeline: { 'Sprite': SpritePipeline },
scene: [ BattleScene ] scene: [ BattleScene ]
}; };

94
src/pipelines/sprite.ts Normal file
View File

@ -0,0 +1,94 @@
const spriteFragShader = `
#define SHADER_NAME PHASER_MULTI_FS
#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 vec4 tone;
const vec3 lumaF = vec3(.299, .587, .114);
void main ()
{
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 gray */
float luma = dot(color.rgb, lumaF);
color.rgb = mix(color.rgb, vec3(luma), tone.w);
/* Apply tone */
color.rgb += tone.rgb * (color.a / 255.0);
gl_FragColor = color;
}
`;
export default class SpritePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline
{
private _tone: number[];
constructor(game: Phaser.Game) {
super({
game: game,
name: 'sprite',
fragShader: spriteFragShader
});
this._tone = [ 0, 0, 0, 0 ];
}
onPreRender(): void {
this.set4f('tone', this._tone[0], this._tone[1], this._tone[2], this._tone[3]);
}
onBind(gameObject: Phaser.GameObjects.GameObject): void {
super.onBind();
const data = (gameObject as Phaser.GameObjects.Sprite).pipelineData;
const tone = data['tone'] as number[];
this.set4f('tone', tone[0], tone[1], tone[2], tone[3]);
}
onBatch(gameObject: Phaser.GameObjects.GameObject): void {
if (gameObject) {
this.flush();
}
}
get tone(): number[] {
return this._tone;
}
set tone(value: number[]) {
this._tone = value;
}
}

View File

@ -26,6 +26,7 @@ import { Biome } from './data/biome';
import { Abilities, Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, abilities, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from './data/ability'; import { Abilities, Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, abilities, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from './data/ability';
import PokemonData from './system/pokemon-data'; import PokemonData from './system/pokemon-data';
import { BattlerIndex } from './battle'; import { BattlerIndex } from './battle';
import SpritePipeline from './pipelines/sprite';
export enum FieldPosition { export enum FieldPosition {
CENTER, CENTER,
@ -144,8 +145,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!species.isObtainable()) if (!species.isObtainable())
this.shiny = false; this.shiny = false;
//this.setPipeline(this.scene).spritePipeline);
this.calculateStats(); this.calculateStats();
this.fieldPosition = FieldPosition.CENTER; this.fieldPosition = FieldPosition.CENTER;
@ -157,6 +156,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const getSprite = () => { const getSprite = () => {
const ret = this.scene.add.sprite(0, 0, `pkmn__${this.isPlayer() ? 'back__' : ''}sub`); const ret = this.scene.add.sprite(0, 0, `pkmn__${this.isPlayer() ? 'back__' : ''}sub`);
ret.setOrigin(0.5, 1); ret.setOrigin(0.5, 1);
ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ] });
return ret; return ret;
}; };