From d8d9aaa9b4c5c9a5b79da9d4833b9d12e1a252a7 Mon Sep 17 00:00:00 2001 From: Rodolphe Suescun Date: Sun, 18 Aug 2019 16:28:50 +0200 Subject: [PATCH] More refactoring and added buffer generator --- addons/material_maker/engine/gen_base.gd | 15 ++--- addons/material_maker/engine/gen_buffer.gd | 27 +++++++- addons/material_maker/engine/gen_material.gd | 3 +- addons/material_maker/engine/gen_shader.gd | 43 ++++++++++--- addons/material_maker/engine/renderer.gd | 5 +- addons/material_maker/nodes/colorize.mmn | 2 +- addons/material_maker/nodes/generic.gd | 66 ++++++++++---------- 7 files changed, 105 insertions(+), 56 deletions(-) diff --git a/addons/material_maker/engine/gen_base.gd b/addons/material_maker/engine/gen_base.gd index 7ff6546..b2be44b 100644 --- a/addons/material_maker/engine/gen_base.gd +++ b/addons/material_maker/engine/gen_base.gd @@ -9,16 +9,7 @@ class OutputPort: func _init(g : MMGenBase, o : int): generator = g output_index = o - """ - func get_shader(): - return generator.get_shader(output_index) - func get_shader_code(uv): - return generator.get_shader_code(uv, output_index) - - func get_globals(): - return generator.get_globals() - """ func to_str(): return generator.name+"("+str(output_index)+")" @@ -81,16 +72,20 @@ func get_globals(): func render(output_index : int, renderer : MMGenRenderer, size : int): var context : MMGenContext = MMGenContext.new(renderer) var source = get_shader_code("UV", output_index, context) + while source is GDScriptFunctionState: + source = yield(source, "completed") if source == null: return false var shader : String = renderer.generate_shader(source) - var status = renderer.render_shader(shader, {}, 1024) + var status = renderer.render_shader(shader, source.textures, size) while status is GDScriptFunctionState: status = yield(status, "completed") return status func get_shader_code(uv : String, output_index : int, context : MMGenContext): var rv = _get_shader_code(uv, output_index, context) + while rv is GDScriptFunctionState: + rv = yield(rv, "completed") if rv != null: if !rv.has("f"): if rv.has("rgb"): diff --git a/addons/material_maker/engine/gen_buffer.gd b/addons/material_maker/engine/gen_buffer.gd index 0ba7296..58bcce8 100644 --- a/addons/material_maker/engine/gen_buffer.gd +++ b/addons/material_maker/engine/gen_buffer.gd @@ -2,6 +2,8 @@ tool extends MMGenBase class_name MMGenBuffer +var texture : ImageTexture = ImageTexture.new() + func _ready(): if !parameters.has("size"): parameters.size = 4 @@ -16,7 +18,28 @@ func get_parameter_defs(): return [ { name="size", type="size", first=4, last=11, default=4 } ] func get_input_defs(): - return [ ] + return [ { name="in", type="rgba" } ] func get_output_defs(): - return [ ] + return [ { rgba="" } ] + +func _get_shader_code(uv : String, output_index : int, context : MMGenContext): + var source = get_source(0) + if source != null: + print(parameters.size) + var status = source.generator.render(source.output_index, context.renderer, pow(2, 4+parameters.size)) + while status is GDScriptFunctionState: + status = yield(status, "completed") + if status: + var image : Image = context.renderer.get_texture().get_data() + texture.create_from_image(image) + texture.flags = 0 + var rv = { defs="" } + var variant_index = context.get_variant(self, uv) + if variant_index == -1: + variant_index = context.get_variant(self, uv) + var texture_name = name+"_tex" + rv.code = "vec4 %s_%d = texture(%s, %s);\n" % [ name, variant_index, texture_name, uv ] + rv.rgba = "%s_%d" % [ name, variant_index ] + rv.textures = { texture_name:texture } + return rv \ No newline at end of file diff --git a/addons/material_maker/engine/gen_material.gd b/addons/material_maker/engine/gen_material.gd index 7e208de..963568e 100644 --- a/addons/material_maker/engine/gen_material.gd +++ b/addons/material_maker/engine/gen_material.gd @@ -39,8 +39,7 @@ func _ready(): func generate_material(renderer : MMGenRenderer): var source = get_source(0) if source != null: - var shader : String = renderer.generate_shader(source) - var status = renderer.render_shader(shader, {}, 512) + var status = source.generator.render(source.output_index, renderer, 512) while status is GDScriptFunctionState: status = yield(status, "completed") print("Render status: "+str(status)) diff --git a/addons/material_maker/engine/gen_shader.gd b/addons/material_maker/engine/gen_shader.gd index 2800908..822d033 100644 --- a/addons/material_maker/engine/gen_shader.gd +++ b/addons/material_maker/engine/gen_shader.gd @@ -3,7 +3,6 @@ extends MMGenBase class_name MMGenShader var shader_model : Dictionary = {} -var generated_variants = [] func get_type(): return "shader" @@ -19,6 +18,18 @@ func get_parameter_defs(): else: return shader_model.parameters +func get_input_defs(): + if shader_model == null or !shader_model.has("inputs"): + return [] + else: + return shader_model.inputs + +func get_output_defs(): + if shader_model == null or !shader_model.has("outputs"): + return [] + else: + return shader_model.outputs + func set_shader_model(data: Dictionary): shader_model = data init_parameters() @@ -43,6 +54,7 @@ func find_keyword_call(string, keyword): func replace_input(string, context, input, type, src, default): var required_defs = "" var required_code = "" + var required_textures = {} while true: var uv = find_keyword_call(string, input) if uv == null: @@ -52,15 +64,17 @@ func replace_input(string, context, input, type, src, default): break var src_code if src == null: - src_code = subst(default, "(%s)" % uv) + src_code = subst(default, context, "(%s)" % uv) else: - print(src.to_str()) src_code = src.generator.get_shader_code(uv, src.output_index, context) + while src_code is GDScriptFunctionState: + src_code = yield(src_code, "completed") src_code.string = src_code[type] required_defs += src_code.defs required_code += src_code.code + required_textures = src_code.textures string = string.replace("$%s(%s)" % [ input, uv ], src_code.string) - return { string=string, defs=required_defs, code=required_code } + return { string=string, defs=required_defs, code=required_code, textures=required_textures } func is_word_letter(l): return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1 @@ -86,6 +100,7 @@ func replace_variable(string, variable, value): func subst(string, context, uv = ""): var required_defs = "" var required_code = "" + var required_textures = {} string = replace_variable(string, "name", name) string = replace_variable(string, "seed", str(get_seed())) if uv != "": @@ -113,20 +128,29 @@ func subst(string, context, uv = ""): var input = shader_model.inputs[i] var source = get_source(i) var result = replace_input(string, context, input.name, input.type, source, input.default) + while result is GDScriptFunctionState: + result = yield(result, "completed") string = result.string required_defs += result.defs required_code += result.code - return { string=string, defs=required_defs, code=required_code } + for t in result.textures.keys(): + required_textures[t] = result.textures[t] + return { string=string, defs=required_defs, code=required_code, textures=required_textures } func _get_shader_code(uv : String, output_index : int, context : MMGenContext): var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ] - var rv = { defs="", code="" } + var rv = { defs="", code="", textures={} } var variant_string = uv+","+str(output_index) if shader_model != null and shader_model.has("outputs") and shader_model.outputs.size() > output_index: var output = shader_model.outputs[output_index] rv.defs = "" if shader_model.has("instance") && !context.has_variant(self): - rv.defs += subst(shader_model.instance, context).string + var subst_output = subst(shader_model.instance, context, uv) + while subst_output is GDScriptFunctionState: + subst_output = yield(subst_output, "completed") + rv.defs += subst_output.string + for t in subst_output.textures.keys(): + rv.textures[t] = subst_output.textures[t] for p in shader_model.parameters: if p.type == "gradient": var g = parameters[p.name] @@ -137,13 +161,16 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext): var variant_index = context.get_variant(self, variant_string) if variant_index == -1: variant_index = context.get_variant(self, variant_string) - generated_variants.append(variant_string) for t in output_info: if output.has(t.field): var subst_output = subst(output[t.field], context, uv) + while subst_output is GDScriptFunctionState: + subst_output = yield(subst_output, "completed") rv.defs += subst_output.defs rv.code += subst_output.code rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, output_index, variant_index, t.field, subst_output.string ] + for t in subst_output.textures.keys(): + rv.textures[t] = subst_output.textures[t] for t in output_info: if output.has(t.field): rv[t.field] = "%s_%d_%d_%s" % [ name, output_index, variant_index, t.field ] diff --git a/addons/material_maker/engine/renderer.gd b/addons/material_maker/engine/renderer.gd index 2662bd6..14d7420 100644 --- a/addons/material_maker/engine/renderer.gd +++ b/addons/material_maker/engine/renderer.gd @@ -18,6 +18,9 @@ static func generate_shader(src_code): file.open("res://addons/material_maker/common.shader", File.READ) code += file.get_as_text() code += "\n" + if src_code.has("textures"): + for t in src_code.textures.keys(): + code += "uniform sampler2D "+t+";\n" if src_code.has("globals"): for g in src_code.globals: code += g @@ -84,7 +87,7 @@ func render_shader(shader, textures, render_size): shader_material.shader.code = shader if textures != null: for k in textures.keys(): - shader_material.set_shader_param(k+"_tex", textures[k]) + shader_material.set_shader_param(k, textures[k]) render_target_update_mode = Viewport.UPDATE_ONCE update_worlds() yield(get_tree(), "idle_frame") diff --git a/addons/material_maker/nodes/colorize.mmn b/addons/material_maker/nodes/colorize.mmn index f2fd928..f1dcfc3 100644 --- a/addons/material_maker/nodes/colorize.mmn +++ b/addons/material_maker/nodes/colorize.mmn @@ -1 +1 @@ -{"global":"","inputs":[{"default":"0.0","label":"Input","name":"input","type":"f"}],"instance":"","name":"Colorize","outputs":[{"rgba":"$gradient($input($uv))"}],"parameters":[{"default":{"points":[{"a":1,"b":0,"g":0,"pos":0,"r":0},{"a":1,"b":1,"g":1,"pos":1,"r":1}],"type":"Gradient"},"label":"","name":"gradient","type":"gradient"}]} \ No newline at end of file +{"global":"","inputs":[{"default":"$uv.x","label":"Input","name":"input","type":"f"}],"instance":"","name":"Colorize","outputs":[{"rgba":"$gradient($input($uv))"}],"parameters":[{"default":{"points":[{"a":1,"b":0,"g":0,"pos":0,"r":0},{"a":1,"b":1,"g":1,"pos":1,"r":1}],"type":"Gradient"},"label":"","name":"gradient","type":"gradient"}]} \ No newline at end of file diff --git a/addons/material_maker/nodes/generic.gd b/addons/material_maker/nodes/generic.gd index cc5efd4..f515c8e 100644 --- a/addons/material_maker/nodes/generic.gd +++ b/addons/material_maker/nodes/generic.gd @@ -86,13 +86,11 @@ func update_node(data): if data.has("instance") and data.instance.find("$(seed)"): uses_seed = true # Parameters - print("Parameters") controls = [] var sizer = null for p in generator.get_parameter_defs(): if !p.has("name") or !p.has("type"): continue - print(p.name) var control = null if p.type == "float": if p.has("widget") and p.widget == "spinbox": @@ -141,35 +139,39 @@ func update_node(data): control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL sizer.add_child(control) initialize_properties() - if data.has("inputs") and typeof(data.inputs) == TYPE_ARRAY: - for i in range(data.inputs.size()): - var input = data.inputs[i] - var enable_left = false - var color_left = Color(0.5, 0.5, 0.5) - if typeof(input) == TYPE_DICTIONARY: - if input.type == "rgb": - enable_left = true - color_left = Color(0.5, 0.5, 1.0) - elif input.type == "rgba": - enable_left = true - color_left = Color(0.0, 0.5, 0.0, 0.5) - else: - enable_left = true - set_slot(i, enable_left, 0, color_left, false, 0, Color()) - if data.has("outputs") and typeof(data.outputs) == TYPE_ARRAY: - for i in range(data.outputs.size()): - var output = data.outputs[i] - var enable_right = false - var color_right = Color(0.5, 0.5, 0.5) - if typeof(output) == TYPE_DICTIONARY: - if output.has("rgb"): - enable_right = true - color_right = Color(0.5, 0.5, 1.0) - elif output.has("rgba"): - enable_right = true - color_right = Color(0.0, 0.5, 0.0, 0.5) - elif output.has("f"): - enable_right = true - set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right) + # Inputs + var inputs = generator.get_input_defs() + for i in range(inputs.size()): + var input = inputs[i] + print(input) + var enable_left = false + var color_left = Color(0.5, 0.5, 0.5) + if typeof(input) == TYPE_DICTIONARY: + if input.type == "rgb": + enable_left = true + color_left = Color(0.5, 0.5, 1.0) + elif input.type == "rgba": + enable_left = true + color_left = Color(0.0, 0.5, 0.0, 0.5) + else: + enable_left = true + set_slot(i, enable_left, 0, color_left, false, 0, Color()) + # Outputs + var outputs = generator.get_output_defs() + for i in range(outputs.size()): + var output = outputs[i] + print(output) + var enable_right = false + var color_right = Color(0.5, 0.5, 0.5) + if typeof(output) == TYPE_DICTIONARY: + if output.has("rgb"): + enable_right = true + color_right = Color(0.5, 0.5, 1.0) + elif output.has("rgba"): + enable_right = true + color_right = Color(0.0, 0.5, 0.0, 0.5) + elif output.has("f"): + enable_right = true + set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right) if custom_node_buttons != null: move_child(custom_node_buttons, get_child_count()-1)