diff --git a/addons/material_maker/engine/gen_base.gd b/addons/material_maker/engine/gen_base.gd
index e046681..eb0e861 100644
--- a/addons/material_maker/engine/gen_base.gd
+++ b/addons/material_maker/engine/gen_base.gd
@@ -67,7 +67,7 @@ func notify_output_change(output_index : int):
for target in targets:
target.generator.source_changed(target.input_index)
-func source_changed(input_index : int):
+func source_changed(__):
for i in range(get_output_defs().size()):
notify_output_change(i)
@@ -97,12 +97,12 @@ func render(output_index : int, renderer : MMGenRenderer, size : int):
while source is GDScriptFunctionState:
source = yield(source, "completed")
if source == null:
- return false
+ source = { defs="", code="", textures={}, rgba="vec4(0.0)" }
var shader : String = renderer.generate_shader(source)
- var status = renderer.render_shader(shader, source.textures, size)
- while status is GDScriptFunctionState:
- status = yield(status, "completed")
- return status
+ var result = renderer.render_shader(shader, source.textures, size)
+ while result is GDScriptFunctionState:
+ result = yield(result, "completed")
+ return result
func get_shader_code(uv : String, output_index : int, context : MMGenContext):
var rv = _get_shader_code(uv, output_index, context)
@@ -125,7 +125,7 @@ func get_shader_code(uv : String, output_index : int, context : MMGenContext):
rv.rgba = "vec4("+rv.rgb+", 1.0)"
return rv
-func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
+func _get_shader_code(__, __, __):
return null
func _serialize(data):
diff --git a/addons/material_maker/engine/gen_buffer.gd b/addons/material_maker/engine/gen_buffer.gd
index 9b677c5..217aefc 100644
--- a/addons/material_maker/engine/gen_buffer.gd
+++ b/addons/material_maker/engine/gen_buffer.gd
@@ -35,14 +35,13 @@ func source_changed(input_port_index : int):
func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
var source = get_source(0)
if source != null and !updated:
- 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
- updated = true
+ var result = source.generator.render(source.output_index, context.renderer, pow(2, 4+parameters.size))
+ while result is GDScriptFunctionState:
+ result = yield(result, "completed")
+ result.copy_to_texture(texture)
+ result.release()
+ texture.flags = 0
+ updated = true
var rv = ._get_shader_code(uv, output_index, context)
while rv is GDScriptFunctionState:
rv = yield(rv, "completed")
diff --git a/addons/material_maker/engine/gen_graph.gd b/addons/material_maker/engine/gen_graph.gd
index 2ec4c89..6862c8b 100644
--- a/addons/material_maker/engine/gen_graph.gd
+++ b/addons/material_maker/engine/gen_graph.gd
@@ -129,10 +129,28 @@ func _serialize(data):
func edit(node):
node.get_parent().call_deferred("update_view", self)
-func create_subgraph(generators):
+func create_subgraph(gens):
+ # Remove material, gen_inputs and gen_outputs nodes
+ var generators = []
+ var center = Vector2(0, 0)
+ var left_bound = 65535
+ var right_bound = -65536
+ var count = 0
+ for g in gens:
+ if g.name != "Material" and g.name != "gen_inputs" and g.name != "gen_outputs":
+ generators.push_back(g)
+ var p = g.position
+ center += p
+ count += 1
+ if left_bound > p.x: left_bound = p.x
+ if right_bound < p.x: right_bound = p.x
+ if count == 0:
+ return
+ center /= count
var new_graph = get_script().new()
new_graph.name = "graph"
- add_child(new_graph)
+ add_generator(new_graph)
+ new_graph.position = center
var names : Array = []
for g in generators:
names.push_back(g.name)
@@ -140,27 +158,39 @@ func create_subgraph(generators):
new_graph.add_generator(g)
var new_graph_connections = []
var my_new_connections = []
- var inputs = null
- var outputs = null
+ var gen_inputs = null
+ var gen_outputs = null
+ var inputs = []
+ var outputs = []
for c in connections:
+ var src_name = c.from+"."+str(c.from_port)
if names.find(c.from) != -1 and names.find(c.to) != -1:
new_graph_connections.push_back(c)
elif names.find(c.from) != -1:
- if outputs == null:
- outputs = MMGenIOs.new()
- outputs.name = "gen_outputs"
- new_graph.add_generator(outputs)
- var port_index = outputs.ports.size()
- outputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
+ var port_index = outputs.find(src_name)
+ if port_index == -1:
+ port_index = outputs.size()
+ outputs.push_back(src_name)
+ if gen_outputs == null:
+ gen_outputs = MMGenIOs.new()
+ gen_outputs.name = "gen_outputs"
+ gen_outputs.position = Vector2(right_bound+300, center.y)
+ new_graph.add_generator(gen_outputs)
+ gen_outputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
+ print(gen_outputs.ports)
my_new_connections.push_back( { from=new_graph.name, from_port=port_index, to=c.to, to_port=c.to_port } )
new_graph_connections.push_back( { from=c.from, from_port=c.from_port, to="gen_outputs", to_port=port_index } )
elif names.find(c.to) != -1:
- if inputs == null:
- inputs = MMGenIOs.new()
- inputs.name = "gen_inputs"
- new_graph.add_generator(inputs)
- var port_index = inputs.ports.size()
- inputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
+ var port_index = inputs.find(src_name)
+ if port_index == -1:
+ port_index = inputs.size()
+ inputs.push_back(src_name)
+ if gen_inputs == null:
+ gen_inputs = MMGenIOs.new()
+ gen_inputs.name = "gen_inputs"
+ gen_inputs.position = Vector2(left_bound-300, center.y)
+ new_graph.add_generator(gen_inputs)
+ gen_inputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
my_new_connections.push_back( { from=c.from, from_port=c.from_port, to=new_graph.name, to_port=port_index } )
new_graph_connections.push_back( { from="gen_inputs", from_port=port_index, to=c.to, to_port=c.to_port } )
else:
diff --git a/addons/material_maker/engine/gen_ios.gd b/addons/material_maker/engine/gen_ios.gd
index 1ce1d8c..e4bc433 100644
--- a/addons/material_maker/engine/gen_ios.gd
+++ b/addons/material_maker/engine/gen_ios.gd
@@ -6,24 +6,21 @@ class_name MMGenIOs
IOs just forward their inputs to their outputs and are used to specify graph interfaces
"""
-var mask : int = 3
var ports : Array = []
func get_type():
- return "buffer"
+ return "ios"
func get_type_name():
match name:
"gen_inputs": return "Inputs"
"gen_outputs": return "Outputs"
_: return "IOs"
- return "Buffer"
func get_io_defs():
var rv : Array = []
- if mask != 2:
- for p in ports:
- rv.push_back({ name=p.name, type="rgba" })
+ for p in ports:
+ rv.push_back({ name=p.name, type="rgba" })
return rv
func get_input_defs():
@@ -39,17 +36,15 @@ func source_changed(input_index : int):
notify_output_change(input_index)
func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
- if mask != 2:
- var source = get_source(output_index)
- if source != null:
- var rv = source.generator._get_shader_code(uv, source.output_index, context)
- while rv is GDScriptFunctionState:
- rv = yield(rv, "completed")
- return rv
+ var source = get_source(output_index)
+ if source != null:
+ var rv = source.generator._get_shader_code(uv, source.output_index, context)
+ while rv is GDScriptFunctionState:
+ rv = yield(rv, "completed")
+ return rv
return { defs="", code="", textures={} }
func _serialize(data):
data.type = "ios"
- data.mask = mask
data.ports = ports
return data
diff --git a/addons/material_maker/engine/gen_material.gd b/addons/material_maker/engine/gen_material.gd
index 2fe6e2c..63c76d0 100644
--- a/addons/material_maker/engine/gen_material.gd
+++ b/addons/material_maker/engine/gen_material.gd
@@ -69,11 +69,12 @@ func render_textures(renderer : MMGenRenderer):
if t.has("port"):
var source = get_source(t.port)
if source != null:
- var status = source.generator.render(source.output_index, renderer, 1024)
- while status is GDScriptFunctionState:
- status = yield(status, "completed")
+ var result = source.generator.render(source.output_index, renderer, 1024)
+ while result is GDScriptFunctionState:
+ result = yield(result, "completed")
texture = ImageTexture.new()
- texture.create_from_image(renderer.get_texture().get_data())
+ result.copy_to_texture(texture)
+ result.release()
elif t.has("ports"):
var context : MMGenContext = MMGenContext.new(renderer)
var code = []
@@ -90,11 +91,12 @@ func render_textures(renderer : MMGenRenderer):
else:
code.push_back({ defs="", code="", f=t.default_values[i] })
var shader : String = renderer.generate_combined_shader(code[0], code[1], code[2])
- var status = renderer.render_shader(shader, shader_textures, 1024)
- while status is GDScriptFunctionState:
- status = yield(status, "completed")
+ var result = renderer.render_shader(shader, shader_textures, 1024)
+ while result is GDScriptFunctionState:
+ result = yield(result, "completed")
texture = ImageTexture.new()
- texture.create_from_image(renderer.get_texture().get_data())
+ result.copy_to_texture(texture)
+ result.release()
generated_textures[t.texture] = texture
func update_materials(material_list):
diff --git a/addons/material_maker/engine/loader.gd b/addons/material_maker/engine/loader.gd
index c26bcd1..9998247 100644
--- a/addons/material_maker/engine/loader.gd
+++ b/addons/material_maker/engine/loader.gd
@@ -55,8 +55,6 @@ static func create_gen(data) -> MMGenBase:
generator = MMGenImage.new()
elif data.type == "ios":
generator = MMGenIOs.new()
- if data.has("mask"):
- generator.mask = int(data.mask)
generator.ports = data.ports
elif data.type == "switch":
generator = MMGenSwitch.new()
diff --git a/addons/material_maker/engine/renderer.gd b/addons/material_maker/engine/renderer.gd
index 6f7789f..0ddb537 100644
--- a/addons/material_maker/engine/renderer.gd
+++ b/addons/material_maker/engine/renderer.gd
@@ -92,7 +92,14 @@ func render_shader(shader, textures, render_size):
update_worlds()
yield(get_tree(), "idle_frame")
yield(get_tree(), "idle_frame")
+ return self
+
+func copy_to_texture(t : ImageTexture):
+ get_texture().get_data().lock()
+ t.create_from_image(get_texture().get_data())
+ get_texture().get_data().unlock()
+
+func release():
rendering = false
emit_signal("done")
- return true
diff --git a/addons/material_maker/icons/icons.svg b/addons/material_maker/icons/icons.svg
index 2a31081..a4a4505 100644
--- a/addons/material_maker/icons/icons.svg
+++ b/addons/material_maker/icons/icons.svg
@@ -49,8 +49,8 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="14.304427"
- inkscape:cx="46.907045"
- inkscape:cy="41.347265"
+ inkscape:cx="33.274902"
+ inkscape:cy="30.161917"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
@@ -67,8 +67,8 @@
+ spacingx="16"
+ spacingy="16" />
@@ -265,5 +265,24 @@
id="rect863"
style="opacity:0;fill:#ffed46;fill-opacity:1;stroke:#c7b115;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" />
+
+
+
diff --git a/addons/material_maker/main_window.gd b/addons/material_maker/main_window.gd
index a3afb78..eee325b 100644
--- a/addons/material_maker/main_window.gd
+++ b/addons/material_maker/main_window.gd
@@ -26,7 +26,7 @@ const MENU = [
{ menu="Edit", command="edit_cut", shortcut="Control+X", description="Cut" },
{ menu="Edit", command="edit_copy", shortcut="Control+C", description="Copy" },
{ menu="Edit", command="edit_paste", shortcut="Control+V", description="Paste" },
- { menu="Tools", command="create_subgraph", shortcut="Control+G", description="Create subgraph" },
+ { menu="Tools", command="create_subgraph", shortcut="Control+G", description="Create group" },
{ menu="Tools", command="make_selected_nodes_editable", shortcut="Control+F", description="Make selected nodes editable" },
{ menu="Tools", command="add_to_user_library", description="Add selected node to user library" },
{ menu="Tools", command="save_user_library", description="Save user library" },
@@ -331,14 +331,13 @@ func update_preview_2d(node = null):
node = n
break
if node != null:
- 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)
- preview.set_2d(tex)
+ var result = node.generator.render(0, renderer, 1024)
+ while result is GDScriptFunctionState:
+ result = yield(result, "completed")
+ var tex = ImageTexture.new()
+ result.copy_to_texture(tex)
+ result.release()
+ preview.set_2d(tex)
func update_preview_3d():
var graph_edit = get_current_graph_edit()
diff --git a/addons/material_maker/node_factory.gd b/addons/material_maker/node_factory.gd
index ac2f2c0..9d46086 100644
--- a/addons/material_maker/node_factory.gd
+++ b/addons/material_maker/node_factory.gd
@@ -8,9 +8,11 @@ func _ready():
func create_node(type):
var node = null
- var node_type = load("res://addons/material_maker/nodes/"+type+".tscn")
- if node_type != null:
- node = node_type.instance()
+ var file_name = "res://addons/material_maker/nodes/"+type+".tscn"
+ if ResourceLoader.exists(file_name):
+ var node_type = load(file_name)
+ 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/generic.gd b/addons/material_maker/nodes/generic.gd
index 606efb3..194982d 100644
--- a/addons/material_maker/nodes/generic.gd
+++ b/addons/material_maker/nodes/generic.gd
@@ -6,6 +6,13 @@ var generator = null setget set_generator
var controls = {}
var ignore_parameter_change = ""
+var output_count = 0
+
+var preview : TextureRect
+var preview_index : int = -1
+var preview_position : int
+var preview_size : int
+var preview_timer : Timer
func set_generator(g):
generator = g
@@ -71,6 +78,7 @@ func initialize_properties():
func update_shaders():
get_parent().send_changed_signal()
+ update_preview()
func _on_text_changed(new_text, variable):
ignore_parameter_change = variable
@@ -158,9 +166,15 @@ func update_node():
set_slot(i, enable_left, 0, color_left, false, 0, Color())
var hsizer : HBoxContainer = HBoxContainer.new()
hsizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
- var label : Label = Label.new()
- label.text = input.label if input.has("label") else ""
- hsizer.add_child(label)
+ if input.has("label") and input.label != "":
+ var label : Label = Label.new()
+ label.text = input.label
+ hsizer.add_child(label)
+ else:
+ var control : Control = Control.new()
+ control.rect_min_size.y = 16
+ hsizer.add_child(control)
+
add_child(hsizer)
var input_names_width : int = 0
for c in get_children():
@@ -211,7 +225,9 @@ func update_node():
initialize_properties()
# Outputs
var outputs = generator.get_output_defs()
- for i in range(outputs.size()):
+ var button_width = 0
+ output_count = outputs.size()
+ for i in range(output_count):
var output = outputs[i]
var enable_right = true
var color_right = Color(0.5, 0.5, 0.5)
@@ -222,14 +238,49 @@ func update_node():
"rgb": color_right = Color(0.5, 0.5, 1.0)
"rgba": color_right = Color(0.0, 0.5, 0.0, 0.5)
set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right)
- if i >= get_child_count():
- var control = Control.new()
- control.rect_min_size = Vector2(0, 16)
- add_child(control)
+ var hsizer : HBoxContainer
+ while i >= get_child_count():
+ hsizer = HBoxContainer.new()
+ hsizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
+ add_child(hsizer)
+ hsizer = get_child(i)
+ var has_filler = false
+ for c in hsizer.get_children():
+ if c.size_flags_horizontal & SIZE_EXPAND != 0:
+ has_filler = true
+ break
+ if !has_filler:
+ var empty_control : Control = Control.new()
+ empty_control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
+ hsizer.add_child(empty_control)
+ var button = preload("res://addons/material_maker/widgets/preview_button.tscn").instance()
+ button.size_flags_horizontal = SIZE_SHRINK_END
+ button.size_flags_vertical = SIZE_SHRINK_CENTER
+ hsizer.add_child(button)
+ button.connect("toggled", self, "on_preview_button", [ i ])
+ button_width = button.rect_size.x
+ if !outputs.empty():
+ for i in range(output_count, get_child_count()):
+ var hsizer : HBoxContainer = get_child(i)
+ var empty_control : Control = Control.new()
+ empty_control.rect_min_size.x = button_width
+ hsizer.add_child(empty_control)
+ # Preview
+ if preview == null:
+ preview = TextureRect.new()
+ preview.visible = false
+ preview_position = get_child_count()
+ # Edit buttons
if generator.model == null:
var edit_buttons = preload("res://addons/material_maker/nodes/edit_buttons.tscn").instance()
add_child(edit_buttons)
edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator")
+ # Preview timer
+ preview_timer = Timer.new()
+ preview_timer.one_shot = true
+ preview_timer.connect("timeout", self, "do_update_preview")
+ add_child(preview_timer)
+
func edit_generator():
if generator.has_method("edit"):
@@ -284,3 +335,48 @@ func do_save_generator(file_name : String):
data.node_position = { x=0, y=0 }
file.store_string(to_json(data))
file.close()
+
+func on_preview_button(pressed : bool, index : int):
+ if pressed:
+ preview_index = index
+ var width
+ if preview.visible:
+ for i in range(output_count):
+ if i != index:
+ var line = get_child(i)
+ line.get_child(line.get_child_count()-1).pressed = false
+ update_preview()
+ else:
+ var status = update_preview(get_child(0).rect_size.x)
+ while status is GDScriptFunctionState:
+ status = yield(status, "completed")
+ else:
+ preview_index = -1
+ preview.visible = false
+ remove_child(preview)
+ rect_size = Vector2(0, 0)
+
+func update_preview(size : int = 0):
+ if preview_index == -1:
+ return
+ if size != 0:
+ preview_size = size
+ preview_timer.start(0.2)
+
+func do_update_preview():
+ var renderer = get_parent().renderer
+ var result = generator.render(preview_index, renderer, preview_size)
+ while result is GDScriptFunctionState:
+ result = yield(result, "completed")
+ if preview.texture == null:
+ preview.texture = ImageTexture.new()
+ result.copy_to_texture(preview.texture)
+ result.release()
+ if !preview.visible:
+ add_child(preview)
+ move_child(preview, preview_position)
+ preview.visible = true
+
+
+
+
diff --git a/addons/material_maker/preview.tscn b/addons/material_maker/preview.tscn
index 52e1d75..48f0e95 100644
--- a/addons/material_maker/preview.tscn
+++ b/addons/material_maker/preview.tscn
@@ -3,7 +3,7 @@
[ext_resource path="res://addons/material_maker/preview.gd" type="Script" id=1]
[ext_resource path="res://addons/material_maker/preview_3d.tscn" type="PackedScene" id=2]
-[sub_resource type="World" id=4]
+[sub_resource type="World" id=1]
[sub_resource type="Shader" id=2]
code = "shader_type canvas_item;
@@ -33,7 +33,7 @@ script = ExtResource( 1 )
[node name="MaterialPreview" type="Viewport" parent="."]
size = Vector2( 395, 370 )
own_world = true
-world = SubResource( 4 )
+world = SubResource( 1 )
handle_input_locally = false
render_target_clear_mode = 1
render_target_update_mode = 3
@@ -50,7 +50,7 @@ margin_right = 100.0
margin_bottom = 20.0
rect_min_size = Vector2( 100, 0 )
text = "Cube"
-items = [ "Cube", null, false, -1, null, "Cylinder", null, false, -1, null, "Sphere", null, false, -1, null, "Quad", null, false, -1, null, "Plane", null, false, -1, null ]
+items = [ "Cube", null, false, -1, null, "Cylinder", null, false, -1, null, "Sphere", null, false, -1, null, "Sphere2", null, false, -1, null, "Quad", null, false, -1, null, "Plane", null, false, -1, null ]
selected = 0
[node name="Environment" type="OptionButton" parent="Config"]
diff --git a/addons/material_maker/preview_3d.tscn b/addons/material_maker/preview_3d.tscn
index 7b06440..dd4d76d 100644
--- a/addons/material_maker/preview_3d.tscn
+++ b/addons/material_maker/preview_3d.tscn
@@ -14,7 +14,7 @@ background_sky = SubResource( 1 )
[sub_resource type="Animation" id=3]
loop = true
tracks/0/type = "value"
-tracks/0/path = NodePath("MaterialPreview/Spatial/Objects:rotation_degrees")
+tracks/0/path = NodePath("Objects:rotation_degrees")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = false
@@ -28,7 +28,7 @@ tracks/0/keys = {
[node name="Preview3d" type="Spatial"]
-[node name="Objects" type="Spatial" parent="." instance=ExtResource( 1 )]
+[node name="Objects" parent="." instance=ExtResource( 1 )]
transform = Transform( -0.799512, 0, 0.60065, 0, 1, 0, -0.60065, 0, -0.799512, 0, 0, 0 )
[node name="OmniLight" type="OmniLight" parent="."]
diff --git a/addons/material_maker/widgets/preview_button.tscn b/addons/material_maker/widgets/preview_button.tscn
new file mode 100644
index 0000000..52bfa9c
--- /dev/null
+++ b/addons/material_maker/widgets/preview_button.tscn
@@ -0,0 +1,21 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://addons/material_maker/icons/icons.svg" type="Texture" id=1]
+
+[sub_resource type="AtlasTexture" id=1]
+flags = 4
+atlas = ExtResource( 1 )
+region = Rect2( 16, 32, 16, 16 )
+
+[sub_resource type="AtlasTexture" id=2]
+flags = 4
+atlas = ExtResource( 1 )
+region = Rect2( 0, 32, 16, 16 )
+
+[node name="PreviewButton" type="TextureButton"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+toggle_mode = true
+shortcut_in_tooltip = false
+texture_normal = SubResource( 1 )
+texture_pressed = SubResource( 2 )