Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Beeblerox/7a57799df87e03667cc7070e41603a01 to your computer and use it in GitHub Desktop.
Save Beeblerox/7a57799df87e03667cc7070e41603a01 to your computer and use it in GitHub Desktop.
package;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.filters.ShaderFilter;
import openfl.Lib;
import openfl.events.Event;
import openfl.Assets;
import openfl.display.Sprite;
import openfl.utils.Float32Array;
import openfl.display.Shader;
import openfl.display.ShaderInput;
import openfl.display.ShaderParameter;
import openfl.display.ShaderParameterType;
import openfl.gl.GL;
class Main extends Sprite
{
var filter:ColorMatrixFilter;
var bitmap:Bitmap;
var matrix:Array<Float>;
public function new()
{
super();
bitmap = new Bitmap(Assets.getBitmapData("assets/pirate.png"));
addChild(bitmap);
matrix = [];
matrix = matrix.concat([1, 0, 0, 0, 0]); // red
matrix = matrix.concat([0, 0, 0, 0, 0]); // green
matrix = matrix.concat([0, 0, 0, 0, 0]); // blue
matrix = matrix.concat([0, 0, 0, 1, 0]); // alpha
filter = new ColorMatrixFilter(matrix);
bitmap.filters = [filter];
// need to add second display object or my shader won't update (i'll open issue about it)
var bitmap2:Bitmap = new Bitmap(new BitmapData(1, 1, true, 0));
addChild(bitmap2);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):Void
{
var red:Float = 0.5 * (1 + Math.sin(Lib.getTimer() / 1000));
matrix[0] = red;
filter.matrix = matrix;
}
}
class ColorMatrixFilter extends ShaderFilter
{
public var matrix(default, set):Array<Float>;
private function set_matrix(value:Array<Float>):Array<Float>
{
_uMultipliers[0][0] = value[0];
_uMultipliers[0][1] = value[1];
_uMultipliers[0][2] = value[2];
_uMultipliers[0][3] = value[3];
_uMultipliers[0][4] = value[5];
_uMultipliers[0][5] = value[6];
_uMultipliers[0][6] = value[7];
_uMultipliers[0][7] = value[8];
_uMultipliers[0][8] = value[10];
_uMultipliers[0][9] = value[11];
_uMultipliers[0][10] = value[12];
_uMultipliers[0][11] = value[13];
_uMultipliers[0][12] = value[15];
_uMultipliers[0][13] = value[16];
_uMultipliers[0][14] = value[17];
_uMultipliers[0][15] = value[18];
_uOffsets[0] = value[4] / 255.0;
_uOffsets[1] = value[9] / 255.0;
_uOffsets[2] = value[14] / 255.0;
_uOffsets[3] = value[19] / 255.0;
_colorMatrixShader.data.uMultipliers.value = _uMultipliers;
_colorMatrixShader.data.uOffsets.value = _uOffsets;
return matrix = value;
}
private var _colorMatrixShader:ColorMatrixShader;
private var _uMultipliers:Array<Float32Array> = [];
private var _uOffsets:Array<Float> = [];
public function new(matrix:Array<Float>)
{
super(_colorMatrixShader = new ColorMatrixShader());
_uMultipliers[0] = new Float32Array(16);
this.matrix = matrix;
}
}
class ColorMatrixShader extends FlxShader
{
public function new()
{
glVertexSource =
"
attribute float aAlpha;
attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying float vAlpha;
varying vec2 vTexCoord;
uniform mat4 uMatrix;
void main(void)
{
vAlpha = aAlpha;
vTexCoord = aTexCoord;
gl_Position = uMatrix * aPosition;
}";
glFragmentSource =
"
varying float vAlpha;
varying vec2 vTexCoord;
uniform sampler2D uImage0;
uniform mat4 uMultipliers;
uniform vec4 uOffsets;
void main(void)
{
vec4 color = texture2D(uImage0, vTexCoord);
color = vec4(color.rgb / color.a, color.a);
color = uOffsets + color * uMultipliers;
color = vec4(color.rgb * color.a, color.a * vAlpha);
gl_FragColor = color;
}";
super(glVertexSource, glFragmentSource);
}
}
/**
* ...
* @author Zaphod
*/
class FlxShader extends Shader
{
public function new(vertexSource:String, fragmentSource:String)
{
super();
if (glProgram != null)
{
GL.deleteProgram(this.glProgram); // Delete what super created
this.glProgram = null;
}
this.data = null;
if (Assets.exists(vertexSource))
{
vertexSource = Assets.getText(vertexSource);
}
if (Assets.exists(fragmentSource))
{
fragmentSource = Assets.getText(fragmentSource);
}
// Then reinit all the data.
glVertexSource = vertexSource;
glFragmentSource = fragmentSource;
// And call init again.
__init();
initShaderData();
}
override function __enable():Void
{
super.__enable();
if (glProgram != null)
{
var param:ShaderParameter, value;
var paramValue:Dynamic;
for (field in Reflect.fields(data))
{
value = Reflect.field(data, field);
if (Std.is(value, ShaderParameter))
{
param = cast value;
paramValue = param.value;
if (paramValue == null)
{
continue;
}
switch (param.type)
{
case ShaderParameterType.FLOAT:
gl.uniform1f(param.index, paramValue[0]);
case ShaderParameterType.FLOAT2:
gl.uniform2f(param.index, paramValue[0], paramValue[1]);
case ShaderParameterType.FLOAT3:
gl.uniform3f(param.index, paramValue[0], paramValue[1], paramValue[2]);
case ShaderParameterType.FLOAT4:
gl.uniform4f(param.index, paramValue[0], paramValue[1], paramValue[2], paramValue[3]);
case ShaderParameterType.INT:
gl.uniform1i(param.index, paramValue[0]);
case ShaderParameterType.INT2:
gl.uniform2i(param.index, paramValue[0], paramValue[1]);
case ShaderParameterType.INT3:
gl.uniform3i(param.index, paramValue[0], paramValue[1], paramValue[2]);
case ShaderParameterType.INT4:
gl.uniform4i(param.index, paramValue[0], paramValue[1], paramValue[2], paramValue[3]);
case ShaderParameterType.MATRIX2X2:
gl.uniformMatrix2fv(param.index, false, paramValue[0]);
case ShaderParameterType.MATRIX3X3:
gl.uniformMatrix3fv(param.index, false, paramValue[0]);
case ShaderParameterType.MATRIX4X4:
gl.uniformMatrix4fv(param.index, false, paramValue[0]);
default:
// nothing to do here. just continue the loop.
}
}
}
}
}
private function initShaderData():Void
{
if (glFragmentSource != null && glVertexSource != null)
{
__processGLData(glVertexSource, "attribute");
__processGLData(glVertexSource, "uniform");
__processGLData(glFragmentSource, "uniform");
}
}
override private function __processGLData(source:String, storageType:String):Void
{
var lastMatch = 0, position, regex, name, type;
var input:Dynamic;
var parameter:Dynamic;
if (storageType == "uniform")
{
regex = ~/uniform ([A-Za-z0-9]+) ([A-Za-z0-9]+)/;
}
else
{
regex = ~/attribute ([A-Za-z0-9]+) ([A-Za-z0-9]+)/;
}
while (regex.matchSub(source, lastMatch))
{
type = regex.matched(1);
name = regex.matched(2);
if (StringTools.startsWith(type, "sampler"))
{
input = Reflect.field(data, name);
if (input == null)
{
input = new ShaderInput();
Reflect.setField(data, name, input);
}
if (gl != null)
{
if (storageType == "uniform")
{
input.index = gl.getUniformLocation(glProgram, name);
}
else
{
input.index = gl.getAttribLocation(glProgram, name);
}
}
}
else
{
parameter = Reflect.field(data, name);
if (parameter == null)
{
parameter = new ShaderParameter();
parameter.type = switch(type)
{
case "bool": BOOL;
case "double", "float": FLOAT;
case "int", "uint": INT;
case "bvec2": BOOL2;
case "bvec3": BOOL3;
case "bvec4": BOOL4;
case "ivec2", "uvec2": INT2;
case "ivec3", "uvec3": INT3;
case "ivec4", "uvec4": INT4;
case "vec2", "dvec2": FLOAT2;
case "vec3", "dvec3": FLOAT3;
case "vec4", "dvec4": FLOAT4;
case "mat2", "mat2x2": MATRIX2X2;
case "mat2x3": MATRIX2X3;
case "mat2x4": MATRIX2X4;
case "mat3x2": MATRIX3X2;
case "mat3", "mat3x3": MATRIX3X3;
case "mat3x4": MATRIX3X4;
case "mat4x2": MATRIX4X2;
case "mat4x3": MATRIX4X3;
case "mat4", "mat4x4": MATRIX4X4;
default: null;
}
Reflect.setField(data, name, parameter);
}
if (gl != null)
{
if (storageType == "uniform")
{
parameter.index = gl.getUniformLocation(glProgram, name);
}
else
{
parameter.index = gl.getAttribLocation(glProgram, name);
}
}
}
position = regex.matchedPos();
lastMatch = position.pos + position.len;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment