Skip to content

Instantly share code, notes, and snippets.

@kennygoff
Last active February 3, 2022 04:06
Show Gist options
  • Save kennygoff/0165d77af31399096666f4975f0146fb to your computer and use it in GitHub Desktop.
Save kennygoff/0165d77af31399096666f4975f0146fb to your computer and use it in GitHub Desktop.
package effects;
import openfl.display.BitmapData;
import flixel.util.FlxColor;
import flixel.system.FlxAssets.FlxShader;
/**
* https://gamedevelopment.tutsplus.com/tutorials/how-to-use-a-shader-to-dynamically-swap-a-sprites-colors--cms-25129
* https://github.com/HaxeFlixel/flixel-demos/blob/master/Effects/BlendModeShaders/source/openfl8/effects/ColorSwapEffect.hx
* https://community.openfl.org/t/passing-an-array-as-parameter-to-shader/9932/9
* https://gamedev.stackexchange.com/questions/43294/creating-a-retro-style-palette-swapping-effect-in-opengl
* https://www.khronos.org/opengl/wiki/Common_Mistakes#Paletted_textures
*/
// Can probably replace openfl_TextureCoordv with flixel_texture2D, will retain alpha set by FlxSprite
class PaletteSwapEffect {
/**
* The instance of the actual shader class
*/
public var shader(default, null):PaletteSwapShader;
/**
* Original palette
*/
public var palette(default, set):Array<FlxColor>;
/**
* Swapped palette
*/
public var swapPalette(default, set):Array<FlxColor>;
/**
* Activates/Deactivates the palette swap
*/
public var isPaletteSwapActive(default, set):Bool;
public function new():Void {
shader = new PaletteSwapShader();
shader.isPaletteSwapActive.value = [false];
shader.swapTexture.input = new BitmapData(256, 256, true);
}
function set_palette(colors:Array<FlxColor>):Array<FlxColor> {
palette = colors;
return colors;
}
function set_swapPalette(colors:Array<FlxColor>):Array<FlxColor> {
swapPalette = colors;
var swapTexture = new BitmapData(256, 256, true, 0x00000000);
for (i in 0...palette.length) {
swapTexture.setPixel32(palette[i].red, palette[i].green, colors[i]);
}
shader.swapTexture.input = swapTexture;
if (palette != null) {
shader.isPaletteSwapActive.value = [true];
}
return colors;
}
function set_isPaletteSwapActive(value:Bool):Bool {
isPaletteSwapActive = value;
shader.isPaletteSwapActive.value[0] = value;
return value;
}
public static function loadPalettesFromFile(file:String):Array<Array<FlxColor>> {
var bitmap = BitmapData.fromFile(file);
var palettes = [];
for (paletteIndex in 0...bitmap.height) {
var palette = [];
for (colorIndex in 0...bitmap.width) {
var color:FlxColor = bitmap.getPixel32(colorIndex, paletteIndex);
if (color.alpha != 0.0) {
palette.push(color);
}
}
palettes.push(palette);
}
return palettes;
}
}
class PaletteSwapShader extends FlxShader {
@:glFragmentSource('
#pragma header
uniform sampler2D swapTexture;
uniform bool isPaletteSwapActive;
void main()
{
vec4 pixel = texture2D(bitmap, openfl_TextureCoordv);
if (isPaletteSwapActive) {
vec2 index = vec2(pixel.r, pixel.g);
vec4 swapPixel = texture2D(swapTexture, index);
if(pixel.a != 0.0 && swapPixel.a != 0.0) {
pixel = swapPixel;
}
}
gl_FragColor = pixel;
}')
public function new() {
super();
}
}
/*
Usage on FlxSprite:
var effect = new PaletteSwapEffect();
// PALETTE_FILE is a png with the original palette at x=0, each swap palette at x=1+
var palettes = PaletteSwapEffect.loadPalettesFromFile(PALETTE_FILE);
var paletteIndex = 1;
effect.palette = palettes[0];
effect.swapPalette = palettes[paletteIndex];
effect.isPaletteSwapActive = true;
shader = effect.shader;
*/
@DigiEggz
Copy link

DigiEggz commented Nov 7, 2021

Thanks for sharing this! What's the license info for this class?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment