Files
CodenameEngine/source/funkin/shaders/CustomShader.hx
T
2022-11-02 13:52:29 +01:00

125 lines
4.7 KiB
Lua

package funkin.shaders;
import haxe.Exception;
import openfl.display.ShaderParameter;
import openfl.display.BitmapData;
import openfl.display.ShaderInput;
import openfl.Assets;
import hscript.IHScriptCustomBehaviour;
/**
* Class for custom shaders.
*
* To create one, create a `shaders` folder in your assets/mod folder, then add a file named `my-shader.frag` or/and `my-shader.vert`.
*
* Non-existent shaders will only load the default one, and throw a warning in the console.
*
* To access the shader's uniform variables, use `shader.variable`
*/
class CustomShader extends FunkinShader implements IHScriptCustomBehaviour {
private static var __instanceFields = Type.getInstanceFields(CustomShader);
/**
* Creates a new custom shader
* @param name Name of the frag and vert files.
* @param glslVersion GLSL version to use. Defaults to `120`.
*/
public function new(name:String, glslVersion:String = "120") {
var fragShaderPath = Paths.fragShader(name);
var vertShaderPath = Paths.vertShader(name);
var fragCode = Assets.exists(fragShaderPath) ? Assets.getText(fragShaderPath) : null;
var vertCode = Assets.exists(vertShaderPath) ? Assets.getText(vertShaderPath) : null;
if (fragCode != null && vertCode != null) {
// TODO: logging!!
}
super(fragCode, vertCode, glslVersion);
}
public function hget(v:String):Dynamic {
if (__instanceFields.contains(v) || __instanceFields.contains('get_${v}')) {
return Reflect.getProperty(this, v);
}
if (!Reflect.hasField(data, v)) return null;
var field = Reflect.field(data, v);
var cl = Std.string(Type.getClass(field));
// cant do "field is ShaderInput" for some reason
if (cl.startsWith("openfl.display.ShaderInput")) {
var si = cast(field, ShaderInput<Dynamic>);
return si.input;
} else if (field is ShaderParameter) {
var sp = cast(field, ShaderParameter<Dynamic>);
@:privateAccess
return (sp.__length > 1) ? sp.value : sp.value[0];
}
return field;
}
public function hset(v:String, val:Dynamic):Dynamic {
if (__instanceFields.contains(v) || __instanceFields.contains('set_${v}')) {
Reflect.setProperty(this, v, val);
return val;
}
if (!Reflect.hasField(data, v)) {
Reflect.setField(data, v, val);
return val;
} else {
var field = Reflect.field(data, v);
var cl = Std.string(Type.getClass(field));
// cant do "field is ShaderInput" for some reason
if (cl.startsWith("openfl.display.ShaderInput")) {
// shader input!!
if (!(val is BitmapData)) {
throw new ShaderTypeException(v, Type.getClass(val), BitmapData);
return null;
}
field.input = cast val;
} else if (cl.startsWith("openfl.display.ShaderParameter")) {
@:privateAccess
if (field.__length <= 1) {
// that means we wait for a single number, instead of an array
@:privateAccess
if (field.__isInt && !(val is Int)) {
throw new ShaderTypeException(v, Type.getClass(val), 'Int');
return null;
} else
@:privateAccess
if (field.__isBool && !(val is Bool)) {
throw new ShaderTypeException(v, Type.getClass(val), 'Bool');
return null;
} else
@:privateAccess
if (field.__isFloat && !(val is Float)) {
throw new ShaderTypeException(v, Type.getClass(val), 'Float');
return null;
}
return field.value = [val];
} else {
if (!(val is Array)) {
throw new ShaderTypeException(v, Type.getClass(val), Array);
return null;
}
return field.value = val;
}
}
}
return val;
}
}
class ShaderTypeException extends Exception {
var has:Class<Dynamic>;
var want:Class<Dynamic>;
var name:String;
public function new(name:String, has:Class<Dynamic>, want:Dynamic) {
this.has = has;
this.want = want;
this.name = name;
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
}
}