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; } }