diff --git a/addons/material_maker/engine/gen_base.gd b/addons/material_maker/engine/gen_base.gd index b7f818f..7ff6546 100644 --- a/addons/material_maker/engine/gen_base.gd +++ b/addons/material_maker/engine/gen_base.gd @@ -9,7 +9,7 @@ class OutputPort: func _init(g : MMGenBase, o : int): generator = g output_index = o - + """ func get_shader(): return generator.get_shader(output_index) @@ -18,19 +18,43 @@ class OutputPort: func get_globals(): return generator.get_globals() - + """ func to_str(): return generator.name+"("+str(output_index)+")" var position : Vector2 = Vector2(0, 0) var parameters = {} +func _ready(): + init_parameters() + +func init_parameters(): + for p in get_parameter_defs(): + print(p) + if !parameters.has(p.name): + if p.has("default"): + parameters[p.name] = MMType.deserialize_value(p.default) + else: + print("No default value for parameter "+p.name) + func get_seed(): return 0 func get_type(): return "generic" +func get_type_name(): + return "Unnamed" + +func get_parameter_defs(): + return [] + +func get_input_defs(): + return [] + +func get_output_defs(): + return [] + func get_source(input_index : int): return get_parent().get_port_source(name, input_index) @@ -39,7 +63,7 @@ func get_input_shader(input_index : int): if source != null: return source.get_shader() -func get_shader(output_index : int, context = MMGenContext.new()): +func get_shader(output_index : int, context): return get_shader_code("UV", output_index, context); # this will need an output index for switch @@ -48,14 +72,25 @@ func get_globals(): for i in range(10): var source = get_source(i) if source != null: - var source_list = source.get_globals() + var source_list = source.generator.get_globals() for g in source_list: if list.find(g) == -1: list.append(g) return list -func get_shader_code(uv, slot = 0, context = MMGenContext.new()): - var rv = _get_shader_code(uv, slot, context) +func render(output_index : int, renderer : MMGenRenderer, size : int): + var context : MMGenContext = MMGenContext.new(renderer) + var source = get_shader_code("UV", output_index, context) + if source == null: + return false + var shader : String = renderer.generate_shader(source) + var status = renderer.render_shader(shader, {}, 1024) + 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) if rv != null: if !rv.has("f"): if rv.has("rgb"): @@ -74,5 +109,5 @@ func get_shader_code(uv, slot = 0, context = MMGenContext.new()): rv.globals = get_globals() return rv -func _get_shader_code(uv : String, output_index : int, context = MMGenContext.new()): +func _get_shader_code(uv : String, output_index : int, context : MMGenContext): return null diff --git a/addons/material_maker/engine/gen_buffer.gd b/addons/material_maker/engine/gen_buffer.gd index 80d36bf..0ba7296 100644 --- a/addons/material_maker/engine/gen_buffer.gd +++ b/addons/material_maker/engine/gen_buffer.gd @@ -1,2 +1,22 @@ +tool extends MMGenBase class_name MMGenBuffer + +func _ready(): + if !parameters.has("size"): + parameters.size = 4 + +func get_type(): + return "buffer" + +func get_type_name(): + return "Buffer" + +func get_parameter_defs(): + return [ { name="size", type="size", first=4, last=11, default=4 } ] + +func get_input_defs(): + return [ ] + +func get_output_defs(): + return [ ] diff --git a/addons/material_maker/engine/gen_context.gd b/addons/material_maker/engine/gen_context.gd index 7555d1a..25e0a75 100644 --- a/addons/material_maker/engine/gen_context.gd +++ b/addons/material_maker/engine/gen_context.gd @@ -1,8 +1,13 @@ +tool extends Object class_name MMGenContext +var renderer : MMGenRenderer var variants : Dictionary = {} +func _init(r : MMGenRenderer): + renderer = r + func has_variant(generator): return variants.has(generator) diff --git a/addons/material_maker/engine/gen_convolution.gd b/addons/material_maker/engine/gen_convolution.gd index acf1e5e..aae09ef 100644 --- a/addons/material_maker/engine/gen_convolution.gd +++ b/addons/material_maker/engine/gen_convolution.gd @@ -1,2 +1,3 @@ +tool extends MMGenBase class_name MMGenConvolution diff --git a/addons/material_maker/engine/gen_graph.gd b/addons/material_maker/engine/gen_graph.gd index 9f3c861..25b78b5 100644 --- a/addons/material_maker/engine/gen_graph.gd +++ b/addons/material_maker/engine/gen_graph.gd @@ -4,10 +4,15 @@ class_name MMGenGraph var connections = [] +func get_type(): + return "graph" + func get_port_source(gen_name: String, input_index: int) -> OutputPort: for c in connections: if c.to == gen_name and c.to_port == input_index: - return OutputPort.new(get_node(c.from), c.from_port) + var src_gen = get_node(c.from) + if src_gen != null: + return OutputPort.new(get_node(c.from), c.from_port) return null func connect_children(from, from_port : int, to, to_port : int): diff --git a/addons/material_maker/engine/gen_material.gd b/addons/material_maker/engine/gen_material.gd index c071ed0..7e208de 100644 --- a/addons/material_maker/engine/gen_material.gd +++ b/addons/material_maker/engine/gen_material.gd @@ -43,6 +43,7 @@ func generate_material(renderer : MMGenRenderer): var status = renderer.render_shader(shader, {}, 512) while status is GDScriptFunctionState: status = yield(status, "completed") + print("Render status: "+str(status)) renderer.get_texture().get_data().save_png("res://test.png") material.albedo_texture = load("res://test.png") return material diff --git a/addons/material_maker/engine/gen_shader.gd b/addons/material_maker/engine/gen_shader.gd index 8441cdb..2800908 100644 --- a/addons/material_maker/engine/gen_shader.gd +++ b/addons/material_maker/engine/gen_shader.gd @@ -2,21 +2,26 @@ tool extends MMGenBase class_name MMGenShader -var model_data = null +var shader_model : Dictionary = {} var generated_variants = [] -func set_model_data(data: Dictionary): - model_data = data - for p in model_data.parameters: - if !parameters.has(p.name) and p.has("default"): - parameters[p.name] = MMType.deserialize_value(p.default) +func get_type(): + return "shader" -func initialize(data: Dictionary): - if data.has("name"): - name = data.name - if data.has("parameters"): - for p in data.parameters.keys(): - parameters[p] = data.parameters[p] +func get_type_name(): + if shader_model.has("name"): + return shader_model.name + return .get_type_name() + +func get_parameter_defs(): + if shader_model == null or !shader_model.has("parameters"): + return [] + else: + return shader_model.parameters + +func set_shader_model(data: Dictionary): + shader_model = data + init_parameters() func find_keyword_call(string, keyword): var search_string = "$%s(" % keyword @@ -49,7 +54,8 @@ func replace_input(string, context, input, type, src, default): if src == null: src_code = subst(default, "(%s)" % uv) else: - src_code = src.get_shader_code(uv) + print(src.to_str()) + src_code = src.generator.get_shader_code(uv, src.output_index, context) src_code.string = src_code[type] required_defs += src_code.defs required_code += src_code.code @@ -84,8 +90,8 @@ func subst(string, context, uv = ""): string = replace_variable(string, "seed", str(get_seed())) if uv != "": string = replace_variable(string, "uv", "("+uv+")") - if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY: - for p in model_data.parameters: + if shader_model.has("parameters") and typeof(shader_model.parameters) == TYPE_ARRAY: + for p in shader_model.parameters: if !p.has("name") or !p.has("type"): continue var value = parameters[p.name] @@ -102,9 +108,9 @@ func subst(string, context, uv = ""): value_string = p.name+"_gradient_fct" if value_string != null: string = replace_variable(string, p.name, value_string) - if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY: - for i in range(model_data.inputs.size()): - var input = model_data.inputs[i] + if shader_model.has("inputs") and typeof(shader_model.inputs) == TYPE_ARRAY: + for i in range(shader_model.inputs.size()): + var input = shader_model.inputs[i] var source = get_source(i) var result = replace_input(string, context, input.name, input.type, source, input.default) string = result.string @@ -112,18 +118,16 @@ func subst(string, context, uv = ""): required_code += result.code return { string=string, defs=required_defs, code=required_code } -func _get_shader_code(uv, slot = 0, context = MMGenContext.new()): - if context == null: - context = {} +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 variant_string = uv+","+str(slot) - if model_data != null and model_data.has("outputs") and model_data.outputs.size() > slot: - var output = model_data.outputs[slot] + 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 model_data.has("instance") && !context.has_variant(self): - rv.defs += subst(model_data.instance, context).string - for p in model_data.parameters: + if shader_model.has("instance") && !context.has_variant(self): + rv.defs += subst(shader_model.instance, context).string + for p in shader_model.parameters: if p.type == "gradient": var g = parameters[p.name] if !(g is MMGradient): @@ -139,14 +143,14 @@ func _get_shader_code(uv, slot = 0, context = MMGenContext.new()): var subst_output = subst(output[t.field], context, uv) rv.defs += subst_output.defs rv.code += subst_output.code - rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, slot, variant_index, t.field, subst_output.string ] + rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, output_index, variant_index, t.field, subst_output.string ] for t in output_info: if output.has(t.field): - rv[t.field] = "%s_%d_%d_%s" % [ name, slot, variant_index, t.field ] + rv[t.field] = "%s_%d_%d_%s" % [ name, output_index, variant_index, t.field ] return rv func get_globals(): var list = .get_globals() - if typeof(model_data) == TYPE_DICTIONARY and model_data.has("global") and list.find(model_data.global) == -1: - list.append(model_data.global) + if typeof(shader_model) == TYPE_DICTIONARY and shader_model.has("global") and list.find(shader_model.global) == -1: + list.append(shader_model.global) return list diff --git a/addons/material_maker/engine/loader.gd b/addons/material_maker/engine/loader.gd index 13a01f6..a225295 100644 --- a/addons/material_maker/engine/loader.gd +++ b/addons/material_maker/engine/loader.gd @@ -32,28 +32,29 @@ func create_gen(data) -> MMGenBase: if data.has("connections") and data.has("nodes"): generator = MMGenGraph.new() add_to_gen_graph(generator, data.nodes, data.connections) - elif data.has("model_data"): + elif data.has("shader_model"): generator = MMGenShader.new() - generator.set_model_data(data.model_data) + generator.set_shader_model(data.shader_model) elif data.has("type"): if data.type == "material": generator = MMGenMaterial.new() + elif data.type == "buffer": + generator = MMGenBuffer.new() else: var file = File.new() if file.open("res://addons/material_maker/library/"+data.type+".mml", File.READ) == OK: - var model_data = parse_json(file.get_as_text()) print("loaded description "+data.type+".mml") - generator = create_gen(model_data) + generator = create_gen(parse_json(file.get_as_text())) file.close() elif file.open("res://addons/material_maker/nodes/"+data.type+".mmn", File.READ) == OK: generator = MMGenShader.new() - var model_data = parse_json(file.get_as_text()) print("loaded description "+data.type+".mmn") - generator.set_model_data(model_data) + generator.set_shader_model(parse_json(file.get_as_text())) file.close() else: print("Cannot find description for "+data.type) - generator.name = data.type + if generator != null: + generator.name = data.type else: print(data) if generator != null: @@ -63,5 +64,6 @@ func create_gen(data) -> MMGenBase: generator.position.x = data.node_position.x generator.position.y = data.node_position.y if data.has("parameters"): - generator.initialize(data) + for p in data.parameters.keys(): + generator.parameters[p] = data.parameters[p] return generator diff --git a/addons/material_maker/engine/renderer.gd b/addons/material_maker/engine/renderer.gd index 966c603..2662bd6 100644 --- a/addons/material_maker/engine/renderer.gd +++ b/addons/material_maker/engine/renderer.gd @@ -68,6 +68,7 @@ func setup_material(shader_material, textures, shader_code): func render_shader(shader, textures, render_size): if rendering: + print("Already rendering...") return false rendering = true if debug_path != null and debug_path != "": diff --git a/addons/material_maker/graph_edit.gd b/addons/material_maker/graph_edit.gd index 484c524..4dc11ef 100644 --- a/addons/material_maker/graph_edit.gd +++ b/addons/material_maker/graph_edit.gd @@ -128,7 +128,7 @@ func get_free_name(type): return node_name i += 1 -func create_nodes(data, position = null): +func create_nodes(data, position : Vector2 = Vector2(0, 0)): if data == null: return if data.has("type"): @@ -136,6 +136,8 @@ func create_nodes(data, position = null): if typeof(data.nodes) == TYPE_ARRAY and typeof(data.connections) == TYPE_ARRAY: var loader = MMGenLoader.new() var new_stuff = loader.add_to_gen_graph(generator, data.nodes, data.connections) + for g in new_stuff.generators: + g.position += position update_graph(new_stuff.generators, new_stuff.connections) func load_file(filename): diff --git a/addons/material_maker/library/base.json b/addons/material_maker/library/base.json index efe2dd9..7e16e24 100644 --- a/addons/material_maker/library/base.json +++ b/addons/material_maker/library/base.json @@ -28,124 +28,156 @@ "tree_item":"Generators/Pattern", "icon":"pattern", "type":"pattern", - "mix":0, - "x_scale":4, - "x_wave":0, - "y_scale":4, - "y_wave":0 + "parameters":{ + "mix":0, + "x_scale":4, + "x_wave":0, + "y_scale":4, + "y_wave":0 + } }, { - "tree_item": "Generators/Pattern/Checkerboard", - "type": "pattern", - "icon": "checkerboard", - "mix": 4, - "x_scale": 4, - "x_wave": 2, - "y_scale": 4, - "y_wave": 2 + "tree_item": "Generators/Pattern/Checkerboard", + "type": "pattern", + "icon": "checkerboard", + "parameters":{ + "mix": 4, + "x_scale": 4, + "x_wave": 2, + "y_scale": 4, + "y_wave": 2 + } }, { "tree_item":"Generators/Bricks", "type":"bricks", "icon":"bricks", - "bevel":0.1, - "columns":3, - "mortar":0.1, - "row_offset":0.5, - "rows":6 + "parameters":{ + "bevel":0.1, + "columns":3, + "mortar":0.1, + "row_offset":0.5, + "rows":6 + } }, { - "tree_item": "Generators/Bricks/Tiles", - "type": "bricks", - "icon": "tiles", - "bevel": 0.05, - "columns": 4, - "mortar": 0.05, - "row_offset": 0, - "rows": 4 + "tree_item": "Generators/Bricks/Tiles", + "type": "bricks", + "icon": "tiles", + "parameters":{ + "bevel": 0.05, + "columns": 4, + "mortar": 0.05, + "row_offset": 0, + "rows": 4 + } + }, + { + "tree_item": "Generators/Bricks/BasketWeave", + "type": "bricks", + "icon": "basketweave", + "parameters":{ + "bevel": 0.05, + "columns": 2, + "mortar": 0.05, + "pattern": 3, + "repeat": 2, + "row_offset": 0, + "rows": 2 + } }, { - "tree_item": "Generators/Bricks/BasketWeave", - "type": "bricks", - "icon": "basketweave", - "bevel": 0.05, - "columns": 2, - "mortar": 0.05, - "pattern": 3, - "repeat": 2, - "row_offset": 0, - "rows": 2 + "tree_item": "Generators/Bricks/HerringBone", + "type": "bricks", + "icon": "herringbone", + "parameters":{ + "bevel": 0.05, + "columns": 2, + "mortar": 0.05, + "pattern": 2, + "repeat": 2, + "row_offset": 0, + "rows": 2 + } }, { - "tree_item": "Generators/Bricks/HerringBone", - "type": "bricks", - "icon": "herringbone", - "bevel": 0.05, - "columns": 2, - "mortar": 0.05, - "pattern": 2, - "repeat": 2, - "row_offset": 0, - "rows": 2 - }, - { - "tree_item": "Generators/Bricks/SpanishBond", - "type": "bricks", - "icon": "spanishbond", - "bevel": 0.05, - "columns": 2, - "mortar": 0.05, - "pattern": 4, - "repeat": 2, - "row_offset": 0, - "rows": 2 + "tree_item": "Generators/Bricks/SpanishBond", + "type": "bricks", + "icon": "spanishbond", + "parameters":{ + "bevel": 0.05, + "columns": 2, + "mortar": 0.05, + "pattern": 4, + "repeat": 2, + "row_offset": 0, + "rows": 2 + } }, { "tree_item":"Generators/Noise", "type":"noise", "icon":"noise", - "size":4, - "density":0.5 + "parameters":{ + "size":4, + "density":0.5 + } }, { "tree_item":"Generators/Perlin Noise", "type":"perlin", "icon":"perlin", - "iterations":3, - "persistence":0.5, - "scale_x":4, - "scale_y":4 + "parameters":{ + "iterations":3, + "persistence":0.5, + "scale_x":4, + "scale_y":4 + } }, { "tree_item":"Generators/Voronoi Noise", "type":"voronoi", "icon":"voronoi", - "intensity":1, - "scale_x":4, - "scale_y":4 + "parameters":{ + "intensity":1, + "scale_x":4, + "scale_y":4 + } + }, + { + "tree_item":"Filters/Buffer", + "type":"buffer" }, { "tree_item":"Filters/AdjustHSV", "type":"adjust_hsv", - "hue":0, - "saturation":1, - "value":1 + "parameters":{ + "hue":0, + "saturation":1, + "value":1 + } }, { "tree_item":"Filters/Colorize", "type":"colorize", - "gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":1,"r":1}] + "parameters":{ + "gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":1,"g":1,"pos":1,"r":1}] + } }, { "tree_item":"Filters/Blend", "type":"blend", - "amount":0.5, - "blend_type":0 + "parameters":{ + "amount":0.5, + "blend_type":0 + } }, { "tree_item":"Filters/Blur", "type":"blur", - "sigma":1.0 + "parameters":{ + "sigma":1.0 + } }, { "tree_item":"Filters/Combine", @@ -158,45 +190,55 @@ { "tree_item":"Filters/Emboss", "type":"emboss", - "direction":0 + "parameters":{ + "direction":0 + } }, { "tree_item":"Filters/Normal map", "type":"normal_map", - "amount":0.5 + "parameters":{ + "amount":0.5 + } }, { "tree_item":"Filters/Transform", "type":"transform", - "rotate":0, - "scale_x":1, - "scale_y":1, - "translate_x":0, - "translate_y":0 + "parameters":{ + "rotate":0, + "scale_x":1, + "scale_y":1, + "translate_x":0, + "translate_y":0 + } }, { "tree_item":"Filters/Warp", "type":"warp", - "amount":0.5 + "parameters":{ + "amount":0.5 + } }, { - "tree_item": "Filters/Colorize/Invert", - "type": "colorize", - "icon": "invert", - "gradient": [ - { - "b": 1, - "g": 1, - "pos": 0, - "r": 1 - }, - { - "b": 0, - "g": 0, - "pos": 1, - "r": 0 - } - ] + "tree_item": "Filters/Colorize/Invert", + "type": "colorize", + "icon": "invert", + "parameters":{ + "gradient": [ + { + "b": 1, + "g": 1, + "pos": 0, + "r": 1 + }, + { + "b": 0, + "g": 0, + "pos": 1, + "r": 0 + } + ] + } }, { "tree_item":"Miscellaneous/Comment", diff --git a/addons/material_maker/main_window.gd b/addons/material_maker/main_window.gd index ffda4e7..138c227 100644 --- a/addons/material_maker/main_window.gd +++ b/addons/material_maker/main_window.gd @@ -311,12 +311,10 @@ func update_preview_2d(node = null): node = n break if node != null: - var source = node.generator.get_shader(0) - if source != null: - var shader : String = renderer.generate_shader(source) - var status = renderer.render_shader(shader, {}, 1024) - while status is GDScriptFunctionState: - status = yield(status, "completed") + var status = node.generator.render(0, renderer, 1024) + while status is GDScriptFunctionState: + status = yield(status, "completed") + if status: var image = renderer.get_texture().get_data() var tex = ImageTexture.new() tex.create_from_image(image) diff --git a/addons/material_maker/node_factory.gd b/addons/material_maker/node_factory.gd index f37f2cf..c8dd4b5 100644 --- a/addons/material_maker/node_factory.gd +++ b/addons/material_maker/node_factory.gd @@ -15,4 +15,6 @@ func create_node(type): var node_type = load("res://addons/material_maker/nodes/"+type+".tscn") if node_type != null: node = node_type.instance() + else: + node = preload("res://addons/material_maker/nodes/generic.tscn").instance() return node diff --git a/addons/material_maker/nodes/bricks.mmn b/addons/material_maker/nodes/bricks.mmn index 7893471..24bee6b 100644 --- a/addons/material_maker/nodes/bricks.mmn +++ b/addons/material_maker/nodes/bricks.mmn @@ -1,7 +1,7 @@ { "name":"Bricks", "parameters":[ - { "name":"pattern", "label":"", "type":"enum", "values":[ + { "name":"pattern", "label":"", "type":"enum", "default":0, "values":[ { "name":"Running bond", "value":"rb" }, { "name":"Running bond (2)", "value":"rb2" }, { "name":"HerringBone", "value":"hb" }, diff --git a/addons/material_maker/nodes/generic.gd b/addons/material_maker/nodes/generic.gd index b86a653..cc5efd4 100644 --- a/addons/material_maker/nodes/generic.gd +++ b/addons/material_maker/nodes/generic.gd @@ -6,16 +6,16 @@ var controls = [] var uses_seed : bool = false -var parameters = {} -var model_data = {} - # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. func set_generator(g): generator = g - update_node(g.model_data) + if g.get("shader_model") != null: + update_node(g.shader_model) + else: + update_node({}) func initialize_properties(): for o in controls: @@ -70,13 +70,9 @@ func _on_gradient_changed(new_gradient, variable): update_shaders() func update_node(data): - print("node_generic.update_node") if typeof(data) != TYPE_DICTIONARY: return - if !data.has("name"): - return # Clean node - parameters = {} var custom_node_buttons = null for c in get_children(): if c.name != "CustomNodeButtons": @@ -85,71 +81,69 @@ func update_node(data): else: custom_node_buttons = c # Rebuild node - title = data.name - model_data = data + title = generator.get_type_name() uses_seed = false - if model_data.has("instance") and model_data.instance.find("$(seed)"): + if data.has("instance") and data.instance.find("$(seed)"): uses_seed = true - if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY: - controls = [] - var sizer = null - for p in model_data.parameters: - if !p.has("name") or !p.has("type"): - continue - var control = null - if p.type == "float": - if p.has("widget") and p.widget == "spinbox": - control = SpinBox.new() - else: - control = HSlider.new() - control.min_value = p.min - control.max_value = p.max - control.step = 0 if !p.has("step") else p.step - if p.has("default"): - control.value = p.default - control.rect_min_size.x = 80 - parameters[p.name] = 0.5*(p.min+p.max) - elif p.type == "size": - control = OptionButton.new() - for i in range(p.first, p.last+1): - var s = pow(2, i) - control.add_item("%dx%d" % [ s, s ]) - control.selected = 0 if !p.has("default") else p.default-p.first - elif p.type == "enum": - control = OptionButton.new() - for i in range(p.values.size()): - var value = p.values[i] - control.add_item(value.name) - control.selected = 0 if !p.has("default") else p.default - elif p.type == "boolean": - control = CheckBox.new() - elif p.type == "color": - control = ColorPickerButton.new() - elif p.type == "gradient": - control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance() - if control != null: - var label = p.name - control.name = label - controls.append(control) - if p.has("label"): - label = p.label - if sizer == null or label != "nonewline": - sizer = HBoxContainer.new() - sizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL - add_child(sizer) - if label != "" && label != "nonewline": - var label_widget = Label.new() - label_widget.text = label - label_widget.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL - sizer.add_child(label_widget) - control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL - sizer.add_child(control) - initialize_properties() - else: - model_data.parameters = [] - if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY: - for i in range(model_data.inputs.size()): - var input = model_data.inputs[i] + # 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": + control = SpinBox.new() + else: + control = HSlider.new() + control.min_value = p.min + control.max_value = p.max + control.step = 0 if !p.has("step") else p.step + if p.has("default"): + control.value = p.default + control.rect_min_size.x = 80 + elif p.type == "size": + control = OptionButton.new() + for i in range(p.first, p.last+1): + var s = pow(2, i) + control.add_item("%dx%d" % [ s, s ]) + control.selected = 0 if !p.has("default") else p.default-p.first + elif p.type == "enum": + control = OptionButton.new() + for i in range(p.values.size()): + var value = p.values[i] + control.add_item(value.name) + control.selected = 0 if !p.has("default") else p.default + elif p.type == "boolean": + control = CheckBox.new() + elif p.type == "color": + control = ColorPickerButton.new() + elif p.type == "gradient": + control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance() + if control != null: + var label = p.name + control.name = label + controls.append(control) + if p.has("label"): + label = p.label + if sizer == null or label != "nonewline": + sizer = HBoxContainer.new() + sizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL + add_child(sizer) + if label != "" && label != "nonewline": + var label_widget = Label.new() + label_widget.text = label + label_widget.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL + sizer.add_child(label_widget) + 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: @@ -162,11 +156,9 @@ func update_node(data): else: enable_left = true set_slot(i, enable_left, 0, color_left, false, 0, Color()) - else: - model_data.inputs = [] - if model_data.has("outputs") and typeof(model_data.outputs) == TYPE_ARRAY: - for i in range(model_data.outputs.size()): - var output = model_data.outputs[i] + 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: @@ -179,7 +171,5 @@ func update_node(data): 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) - else: - model_data.outputs = [] if custom_node_buttons != null: move_child(custom_node_buttons, get_child_count()-1) diff --git a/addons/material_maker/plugin.gd b/addons/material_maker/plugin.gd index 95c143e..467e3ed 100644 --- a/addons/material_maker/plugin.gd +++ b/addons/material_maker/plugin.gd @@ -51,4 +51,7 @@ func generate_material(ptex_filename: String) -> Material: var generator = loader.load_gen(ptex_filename) add_child(generator) var material = generator.get_node("Material") - return material.generate_material(renderer) + var return_value = material.generate_material(renderer) + while return_value is GDScriptFunctionState: + return_value = yield(return_value, "completed") + return return_value diff --git a/addons/material_maker/types/gradient.gd b/addons/material_maker/types/gradient.gd index 894e20e..f776898 100644 --- a/addons/material_maker/types/gradient.gd +++ b/addons/material_maker/types/gradient.gd @@ -8,9 +8,6 @@ class CustomSorter: var points = [ { v=0.0, c=Color(0.0, 0.0, 0.0, 0.0) }, { v=1.0, c=Color(1.0, 1.0, 1.0, 1.0) } ] var sorted = true -func _ready(): - pass - func to_string(): var rv = PoolStringArray() for p in points: @@ -39,17 +36,20 @@ func sort(): func get_color(x): sort() - if x < points[0].v: - return points[0].c - var s = points.size()-1 - for i in range(s): - if x < points[i+1].v: - var p0 = points[i].v - var c0 = points[i].c - var p1 = points[i+1].v - var c1 = points[i+1].c - return c0 + (c1-c0) * (x-p0) / (p1-p0) - return points[s].c + if points.size() >0: + if x < points[0].v: + return points[0].c + var s = points.size()-1 + for i in range(s): + if x < points[i+1].v: + var p0 = points[i].v + var c0 = points[i].c + var p1 = points[i+1].v + var c1 = points[i+1].c + return c0 + (c1-c0) * (x-p0) / (p1-p0) + return points[s].c + else: + return Color(0.0, 0.0, 0.0, 1.0) # get_color_in_shader func gcis(color): @@ -59,19 +59,22 @@ func get_shader(name): sort() var shader shader = "vec4 "+name+"(float x) {\n" - shader += " if (x < %.9f) {\n" % points[0].v - shader += " return "+gcis(points[0].c)+";\n" - var s = points.size()-1 - for i in range(s): - var p0 = points[i].v - var c0 = points[i].c - var p1mp0 = points[i+1].v-p0 - var c1mc0 = points[i+1].c-c0 - if p1mp0 > 0: - shader += " } else if (x < %.9f) {\n" % points[i+1].v - shader += " return %s+x*%s;\n" % [gcis(c0-c1mc0*(p0/p1mp0)), gcis(c1mc0/p1mp0)] - shader += " }\n" - shader += " return "+gcis(points[s].c)+";\n" + if points.size() > 0: + shader += " if (x < %.9f) {\n" % points[0].v + shader += " return "+gcis(points[0].c)+";\n" + var s = points.size()-1 + for i in range(s): + var p0 = points[i].v + var c0 = points[i].c + var p1mp0 = points[i+1].v-p0 + var c1mc0 = points[i+1].c-c0 + if p1mp0 > 0: + shader += " } else if (x < %.9f) {\n" % points[i+1].v + shader += " return %s+x*%s;\n" % [gcis(c0-c1mc0*(p0/p1mp0)), gcis(c1mc0/p1mp0)] + shader += " }\n" + shader += " return "+gcis(points[s].c)+";\n" + else: + shader += " return vec4(0.0, 0.0, 0.0, 1.0);\n" shader += "}\n" return shader @@ -89,7 +92,7 @@ func deserialize(v): for i in v: if !i.has("a"): i.a = 1.0 add_point(i.pos, Color(i.r, i.g, i.b, i.a)) - elif typeof(v) == TYPE_DICTIONARY && v.has("type") && v.type == "Gradient": + elif typeof(v) == TYPE_DICTIONARY and v.has("type") && v.type == "Gradient": for i in v.points: if !i.has("a"): i.a = 1.0 add_point(i.pos, Color(i.r, i.g, i.b, i.a)) diff --git a/test.png b/test.png new file mode 100644 index 0000000..8571f28 Binary files /dev/null and b/test.png differ diff --git a/test.ptex b/test.ptex index 3094556..b6fd2ef 100644 --- a/test.ptex +++ b/test.ptex @@ -1 +1,158 @@ -{"connections":[{"from":"bricks_0","from_port":0,"to":"custom_0","to_port":0},{"from":"custom_0","from_port":0,"to":"adjust_hsv_0","to_port":0},{"from":"adjust_hsv_0","from_port":0,"to":"Material","to_port":0}],"nodes":[{"name":"Material","node_position":{"x":143,"y":-210},"parameters":{"albedo_color":{"a":1,"b":1,"g":1,"r":1,"type":"Color"},"ao_light_affect":1,"depth_scale":1,"emission_energy":1,"metallic":1,"normal_scale":1,"resolution":1,"roughness":1},"type":"material"},{"model_data":{"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":"Gradient","name":"gradient","type":"gradient"}]},"name":"custom_0","node_position":{"x":-433,"y":-109.416656},"parameters":{"gradient":{"points":[{"a":1,"b":0,"g":0,"pos":0,"r":0},{"a":1,"b":0,"g":0,"pos":0.517045,"r":1},{"a":0,"b":1,"g":1,"pos":1,"r":1}],"type":"Gradient"}},"type":"custom"},{"name":"adjust_hsv_0","node_position":{"x":-135.541687,"y":-150.597229},"parameters":{"hue":0,"saturation":1,"value":1},"type":"adjust_hsv"},{"name":"bricks_0","node_position":{"x":-599,"y":-332},"parameters":{"bevel":0.209961,"columns":3,"mortar":0.116211,"pattern":0,"repeat":1,"row_offset":0.5,"rows":6},"type":"bricks"}]} \ No newline at end of file +{ + "connections": [ + { + "from": "bricks_0", + "from_port": 0, + "to": "custom_0", + "to_port": 0 + }, + { + "from": "custom_0", + "from_port": 0, + "to": "adjust_hsv_0", + "to_port": 0 + }, + { + "from": "adjust_hsv_0", + "from_port": 0, + "to": "Material", + "to_port": 0 + } + ], + "nodes": [ + { + "name": "Material", + "node_position": { + "x": 143, + "y": -210 + }, + "parameters": { + "albedo_color": { + "a": 1, + "b": 1, + "g": 1, + "r": 1, + "type": "Color" + }, + "ao_light_affect": 1, + "depth_scale": 1, + "emission_energy": 1, + "metallic": 1, + "normal_scale": 1, + "resolution": 1, + "roughness": 1 + }, + "type": "material" + }, + { + "shader_model": { + "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": "Gradient", + "name": "gradient", + "type": "gradient" + } + ] + }, + "name": "custom_0", + "node_position": { + "x": -433, + "y": -109.416656 + }, + "parameters": { + "gradient": { + "points": [ + { + "a": 1, + "b": 0, + "g": 0, + "pos": 0, + "r": 0 + }, + { + "a": 1, + "b": 0, + "g": 0, + "pos": 0.517045, + "r": 1 + }, + { + "a": 0, + "b": 1, + "g": 1, + "pos": 1, + "r": 1 + } + ], + "type": "Gradient" + } + }, + "type": "custom" + }, + { + "name": "adjust_hsv_0", + "node_position": { + "x": -135.541687, + "y": -150.597229 + }, + "parameters": { + "hue": 0, + "saturation": 1, + "value": 1 + }, + "type": "adjust_hsv" + }, + { + "name": "bricks_0", + "node_position": { + "x": -599, + "y": -332 + }, + "parameters": { + "bevel": 0.209961, + "columns": 3, + "mortar": 0.116211, + "pattern": 0, + "repeat": 1, + "row_offset": 0.5, + "rows": 6 + }, + "type": "bricks" + } + ] +} \ No newline at end of file