gamemaker_material/scrMaterial.gml
2026-05-24 14:27:50 +00:00

239 lines
7.6 KiB
Text

enum MaterialUniformType {Float, Vec2, Vec3, Vec4, ColorNoAlpha, Color}
///@param {Asset.GMShader} shader
function Material(shader) constructor {
self.uniforms = {};
self.names = [];
self.shader = shader;
}
///@param {Any} value
///@param {Real} type
function MaterialUniform(value, type) constructor {
self.value = value;
self.type = type;
self.debug_display_info = new MaterialUniformValueDisplayInfo(MaterialUniformValueDisplayType.Slider, 0.0, 1.0);
}
enum MaterialUniformValueDisplayType {
Slider,
ColorNoAlpha,
Color,
}
///@param {real} type
///@param {real} [range_min = 0.0]
///@param {real} [range_max = 1.0]
function MaterialUniformValueDisplayInfo(type, range_min = 0.0, range_max = 1.0) constructor {
self.type = type;
self.range_min = range_min;
self.range_max = range_max;
}
///@param {Struct.Material} mat
function shader_set_from_material(mat) {
shader_set(mat.shader);
material_apply(mat);
}
///@param {Struct.Material} mat
///@param {String} key
///@return {Struct}
function material_get_uniform(mat, key) {
return mat.uniforms[$key];
}
///@param {Struct.Material} material
///@param {String} key
///@param {Real} type
///@param {Real} [range_min = 0.0]
///@param {Real} [range_max = 1.0]
function material_uniform_set_display_info(material, key, type, range_min = 0.0, range_max = 1.0) {
var _u = material.uniforms[$key];
switch (type) {
case MaterialUniformValueDisplayType.ColorNoAlpha:
if (_u.type != MaterialUniformType.ColorNoAlpha) {
printerr($"Cannot change debug display type of uniform '{key}' to ColorNoAlpha because it's type doesn't support it ({_u.type})", ERROR_LOC);
return;
}
break;
case MaterialUniformValueDisplayType.Color:
if (_u.type != MaterialUniformType.Color) {
printerr($"Cannot change debug display type of uniform '{key}' to Color because it's type doesn't support it ({_u.type})", ERROR_LOC);
return;
}
break;
}
material.uniforms[$key].debug_display_info.type = type;
material.uniforms[$key].debug_display_info.range_min = range_min;
material.uniforms[$key].debug_display_info.range_max = range_max;
}
///@param {Struct.Material} mat
///@param {String} key
///@param {Real} val
///@return {Struct}
function material_add_float(mat, key, val) {
if (variable_struct_exists(mat.uniforms, key)) {
printerr($"Material already has uniform '{key}'", ERROR_LOC);
return;
}
var _uniform = new MaterialUniform(new Vec1(val), MaterialUniformType.Float);
array_push(mat.names, key);
variable_struct_set(mat.uniforms, key, _uniform);
return _uniform;
}
///@param {Struct.Material} mat
///@param {String} key
///@param {Real} x
///@param {Real} y
///@return {Struct}
function material_add_vec2(mat, key, x, y) {
if (variable_struct_exists(mat.uniforms, key)) {
printerr($"Material already has uniform '{key}'", ERROR_LOC);
return;
}
var _uniform = new MaterialUniform(new Vec2(x, y), MaterialUniformType.Vec2);
array_push(mat.names, key);
variable_struct_set(mat.uniforms, key, _uniform);
return _uniform;
}
///@param {Struct.Material} mat
///@param {String} key
///@param {Real} x
///@param {Real} y
///@param {Real} z
///@return {Struct}
function material_add_vec3(mat, key, x, y, z) {
if (variable_struct_exists(mat.uniforms, key)) {
printerr($"Material already has uniform '{key}'", ERROR_LOC);
return;
}
var _uniform = new MaterialUniform(new Vec3(x, y, z), MaterialUniformType.Vec3);
array_push(mat.names, key);
variable_struct_set(mat.uniforms, key, _uniform);
return _uniform;
}
///@param {Struct.Material} mat
///@param {String} key
///@param {Real} x
///@param {Real} y
///@param {Real} z
///@param {Real} w
///@return {Struct}
function material_add_vec4(mat, key, x, y, z, w) {
if (variable_struct_exists(mat.uniforms, key)) {
printerr($"Material already has uniform '{key}'", ERROR_LOC);
return;
}
var _uniform = new MaterialUniform(new Vec4(x, y, z, w), MaterialUniformType.Vec4);
array_push(mat.names, key);
variable_struct_set(mat.uniforms, key, _uniform);
return _uniform;
}
///@param {Struct.Material} mat
///@param {String} key
///@param {Constant.Color} color
///@return {Struct}
function material_add_color_rgb(mat, key, color) {
if (variable_struct_exists(mat.uniforms, key)) {
printerr($"Material already has uniform '{key}'", ERROR_LOC);
return;
}
var _uniform = new MaterialUniform(new Vec1(color), MaterialUniformType.ColorNoAlpha);
_uniform.debug_display_info.type = MaterialUniformValueDisplayType.ColorNoAlpha;
array_push(mat.names, key);
variable_struct_set(mat.uniforms, key, _uniform);
return _uniform;
}
///@param {Struct.Material} mat
///@param {String} key
///@param {Constant.Color} color
///@param {Real} alpha
///@return {Struct}
function material_add_color_rgba(mat, key, color, alpha) {
if (variable_struct_exists(mat.uniforms, key)) {
printerr($"Material already has uniform '{key}'", ERROR_LOC);
return;
}
var _uniform = new MaterialUniform(new Vec2(color, alpha), MaterialUniformType.Color);
_uniform.debug_display_info.type = MaterialUniformValueDisplayType.Color;
array_push(mat.names, key);
variable_struct_set(mat.uniforms, key, _uniform);
return _uniform;
}
///@param {Struct.Material} mat
function material_apply(mat) {
var _names = variable_struct_get_names(mat.uniforms);
var _sh = shader_current();
for (var i = 0, n = array_length(_names); i < n; i++) {
var _uniform = variable_struct_get(mat.uniforms, _names[i]);
switch (_uniform.type) {
case MaterialUniformType.Float:
shader_set_uniform_f(shader_get_uniform(_sh, _names[i]), _uniform.value.x);
break;
case MaterialUniformType.Vec2:
shader_set_uniform_f(shader_get_uniform(_sh, _names[i]), _uniform.value.x, _uniform.value.y);
break;
case MaterialUniformType.Vec3:
shader_set_uniform_f(shader_get_uniform(_sh, _names[i]), _uniform.value.x, _uniform.value.y, _uniform.value.z);
break;
case MaterialUniformType.Vec4:
shader_set_uniform_f(shader_get_uniform(_sh, _names[i]), _uniform.value.x, _uniform.value.y, _uniform.value.z, _uniform.value.w);
break;
case MaterialUniformType.ColorNoAlpha:
shader_set_uniform_f(
shader_get_uniform(_sh, _names[i]),
color_get_red(_uniform.value.x) / 255,
color_get_green(_uniform.value.x) / 255,
color_get_blue(_uniform.value.x) / 255);
break;
case MaterialUniformType.Color:
shader_set_uniform_f(
shader_get_uniform(_sh, _names[i]),
color_get_red(_uniform.value.x) / 255,
color_get_green(_uniform.value.x) / 255,
color_get_blue(_uniform.value.x) / 255,
_uniform.value.y);
break;
}
}
}
///@param {Struct.Material} mat
function material_add_to_debug_view(mat, name) {
if (!DEBUG_MODE) {
return;
}
dbg_set_view(global.debug_views.materials.view);
array_push(global.debug_views.materials.sections, dbg_section(name, false));
for (var i = 0, n = array_length(mat.names); i < n; i++) {
_material_uniform_add_to_current_debug_view_section(mat.uniforms[$mat.names[i]], mat.names[i]);
}
}
///@param {Struct.MaterialUniform} uniform
///@param {string} name
function _material_uniform_add_to_current_debug_view_section(uniform, name) {
dbg_text_separator(name);
switch (uniform.debug_display_info.type) {
case MaterialUniformValueDisplayType.Slider:
var _names = struct_get_names(uniform.value);
for (var i = 0, n = array_length(_names); i < n; i++) {
dbg_slider(ref_create(uniform.value, _names[i]), uniform.debug_display_info.range_min, uniform.debug_display_info.range_max);
}
break;
case MaterialUniformValueDisplayType.ColorNoAlpha:
dbg_color(ref_create(uniform.value, "x"), "Color");
break;
case MaterialUniformValueDisplayType.Color:
dbg_color(ref_create(uniform.value, "x"), "Color");
dbg_slider(ref_create(uniform.value, "y"), 0.0, 1.0, "Alpha");
break;
}
}