mirror of
https://github.com/Relintai/material-maker.git
synced 2024-12-23 21:16:54 +01:00
Updated switch node and refactored generator edit feature.
This commit is contained in:
parent
cdfc247fc1
commit
c8414f47df
@ -40,6 +40,12 @@ func _ready():
|
|||||||
func can_be_deleted() -> bool:
|
func can_be_deleted() -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
func toggle_editable():
|
||||||
|
return false
|
||||||
|
|
||||||
|
func is_editable():
|
||||||
|
return false
|
||||||
|
|
||||||
func init_parameters():
|
func init_parameters():
|
||||||
for p in get_parameter_defs():
|
for p in get_parameter_defs():
|
||||||
if !parameters.has(p.name):
|
if !parameters.has(p.name):
|
||||||
|
@ -5,12 +5,26 @@ class_name MMGenGraph
|
|||||||
var label : String = "Graph"
|
var label : String = "Graph"
|
||||||
var connections = []
|
var connections = []
|
||||||
|
|
||||||
|
var editable = false
|
||||||
|
|
||||||
|
|
||||||
func get_type():
|
func get_type():
|
||||||
return "graph"
|
return "graph"
|
||||||
|
|
||||||
func get_type_name():
|
func get_type_name():
|
||||||
return label
|
return label
|
||||||
|
|
||||||
|
|
||||||
|
func toggle_editable():
|
||||||
|
editable = !editable
|
||||||
|
if editable:
|
||||||
|
model = null
|
||||||
|
return true
|
||||||
|
|
||||||
|
func is_editable():
|
||||||
|
return editable
|
||||||
|
|
||||||
|
|
||||||
func get_parameter_defs():
|
func get_parameter_defs():
|
||||||
if has_node("gen_parameters"):
|
if has_node("gen_parameters"):
|
||||||
return get_node("gen_parameters").get_parameter_defs()
|
return get_node("gen_parameters").get_parameter_defs()
|
||||||
|
@ -5,6 +5,17 @@ class_name MMGenShader
|
|||||||
var shader_model : Dictionary = {}
|
var shader_model : Dictionary = {}
|
||||||
var uses_seed = false
|
var uses_seed = false
|
||||||
|
|
||||||
|
var editable = false
|
||||||
|
|
||||||
|
func toggle_editable():
|
||||||
|
editable = !editable
|
||||||
|
if editable:
|
||||||
|
model = null
|
||||||
|
return true
|
||||||
|
|
||||||
|
func is_editable():
|
||||||
|
return editable
|
||||||
|
|
||||||
func get_type():
|
func get_type():
|
||||||
return "shader"
|
return "shader"
|
||||||
|
|
||||||
|
@ -6,32 +6,48 @@ class_name MMGenSwitch
|
|||||||
Texture generator switch
|
Texture generator switch
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
var editable = false
|
||||||
|
|
||||||
func get_type():
|
func get_type():
|
||||||
return "switch"
|
return "switch"
|
||||||
|
|
||||||
func get_type_name():
|
func get_type_name():
|
||||||
return "Switch"
|
return "Switch"
|
||||||
|
|
||||||
|
func toggle_editable():
|
||||||
|
editable = !editable
|
||||||
|
return true
|
||||||
|
|
||||||
|
func is_editable():
|
||||||
|
return editable
|
||||||
|
|
||||||
func get_parameter_defs():
|
func get_parameter_defs():
|
||||||
|
var choices = parameters.choices if parameters.has("choices") else 2
|
||||||
return [
|
return [
|
||||||
{ name="outputs", label="Outputs", type="float", min=1, max=5, step=1, default=2 },
|
{ name="outputs", label="Outputs", type="float", min=1, max=5, step=1, default=2 },
|
||||||
{ name="choices", label="Choices", type="float", min=2, max=5, step=1, default=2 },
|
{ name="choices", label="Choices", type="float", min=2, max=5, step=1, default=2 },
|
||||||
{ name="source", label="Source", type="float", min=0, max=1, step=1, default=0 },
|
{ name="source", label="Source", type="float", min=0, max=choices-1, step=1, default=0 },
|
||||||
]
|
]
|
||||||
|
|
||||||
func get_input_defs():
|
func get_input_defs():
|
||||||
var rv : Array = []
|
var rv : Array = []
|
||||||
for c in range(parameters.choices):
|
for c in range(parameters.choices):
|
||||||
for o in range(parameters.outputs):
|
for o in range(parameters.outputs):
|
||||||
rv.push_back({ name=PoolByteArray([64+o]).get_string_from_ascii()+str(c), type="rgba" })
|
var n = PoolByteArray([65+o]).get_string_from_ascii()+str(c)
|
||||||
|
rv.push_back({ name=n, label=n, type="rgba" })
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
func get_output_defs():
|
func get_output_defs():
|
||||||
var rv : Array = []
|
var rv : Array = []
|
||||||
for o in range(parameters.outputs):
|
for o in range(parameters.outputs):
|
||||||
rv.push_back({ name=PoolByteArray([64+o]).get_string_from_ascii(), type="rgba" })
|
var n = PoolByteArray([65+o]).get_string_from_ascii()
|
||||||
|
rv.push_back({ name=n, type="rgba" })
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
func set_parameter(p, v):
|
||||||
|
.set_parameter(p, v)
|
||||||
|
emit_signal("parameter_changed", "__update_all__", null)
|
||||||
|
|
||||||
func source_changed(input_index : int):
|
func source_changed(input_index : int):
|
||||||
notify_output_change(input_index % int(parameters.outputs))
|
notify_output_change(input_index % int(parameters.outputs))
|
||||||
|
|
||||||
@ -42,7 +58,7 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
|
|||||||
while rv is GDScriptFunctionState:
|
while rv is GDScriptFunctionState:
|
||||||
rv = yield(rv, "completed")
|
rv = yield(rv, "completed")
|
||||||
return rv
|
return rv
|
||||||
return { defs="", code="", textures={} }
|
return { globals=[], defs="", code="", textures={} }
|
||||||
|
|
||||||
func _serialize(data):
|
func _serialize(data):
|
||||||
return data
|
return data
|
||||||
|
@ -30,7 +30,7 @@ const MENU = [
|
|||||||
{ menu="View", command="view_reset_zoom", shortcut="Control+0", description="Reset zoom" },
|
{ menu="View", command="view_reset_zoom", shortcut="Control+0", description="Reset zoom" },
|
||||||
{ menu="Tools", submenu="create", description="Create" },
|
{ menu="Tools", submenu="create", description="Create" },
|
||||||
{ menu="Tools", command="create_subgraph", shortcut="Control+G", description="Create group" },
|
{ 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="make_selected_nodes_editable", shortcut="Control+E", description="Make selected nodes editable" },
|
||||||
{ menu="Tools" },
|
{ menu="Tools" },
|
||||||
{ menu="Tools", command="add_to_user_library", description="Add selected node to user library" },
|
{ menu="Tools", command="add_to_user_library", description="Add selected node to user library" },
|
||||||
{ menu="Tools", command="save_user_library", description="Save user library" },
|
{ menu="Tools", command="save_user_library", description="Save user library" },
|
||||||
@ -308,7 +308,7 @@ func make_selected_nodes_editable():
|
|||||||
var selected_nodes = get_selected_nodes()
|
var selected_nodes = get_selected_nodes()
|
||||||
if !selected_nodes.empty():
|
if !selected_nodes.empty():
|
||||||
for n in selected_nodes:
|
for n in selected_nodes:
|
||||||
n.generator.model = null
|
if n.generator.toggle_editable():
|
||||||
n.update_node()
|
n.update_node()
|
||||||
|
|
||||||
func add_to_user_library():
|
func add_to_user_library():
|
||||||
|
@ -62,7 +62,7 @@ margin_left = 125.0
|
|||||||
margin_right = 171.0
|
margin_right = 171.0
|
||||||
margin_bottom = 20.0
|
margin_bottom = 20.0
|
||||||
text = "Tools"
|
text = "Tools"
|
||||||
items = [ "Create", null, 0, false, false, -1, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 18, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 19, 268435526, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 21, 0, null, "", false, "Save user library", null, 0, false, false, 22, 0, null, "", false ]
|
items = [ "Create", null, 0, false, false, -1, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 18, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 19, 268435525, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 21, 0, null, "", false, "Save user library", null, 0, false, false, 22, 0, null, "", false ]
|
||||||
|
|
||||||
[node name="Help" type="MenuButton" parent="VBoxContainer/Menu"]
|
[node name="Help" type="MenuButton" parent="VBoxContainer/Menu"]
|
||||||
margin_left = 175.0
|
margin_left = 175.0
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
tool
|
|
||||||
extends "res://addons/material_maker/nodes/node_generic.gd"
|
|
||||||
|
|
||||||
func _on_Edit_pressed():
|
|
||||||
var edit_window = load("res://addons/material_maker/widgets/node_editor/node_editor.tscn").instance()
|
|
||||||
get_parent().add_child(edit_window)
|
|
||||||
if model_data != null:
|
|
||||||
edit_window.set_model_data(model_data)
|
|
||||||
edit_window.connect("node_changed", self, "update_node")
|
|
||||||
edit_window.popup_centered()
|
|
||||||
|
|
||||||
func _on_Load_pressed():
|
|
||||||
var dialog = FileDialog.new()
|
|
||||||
add_child(dialog)
|
|
||||||
dialog.rect_min_size = Vector2(500, 500)
|
|
||||||
dialog.access = FileDialog.ACCESS_FILESYSTEM
|
|
||||||
dialog.mode = FileDialog.MODE_OPEN_FILE
|
|
||||||
dialog.add_filter("*.mmn;Material Maker Node")
|
|
||||||
dialog.connect("file_selected", self, "do_load_node")
|
|
||||||
dialog.popup_centered()
|
|
||||||
|
|
||||||
func do_load_node(file_name):
|
|
||||||
set_model(file_name)
|
|
||||||
|
|
||||||
func _on_Save_pressed():
|
|
||||||
var dialog = FileDialog.new()
|
|
||||||
add_child(dialog)
|
|
||||||
dialog.rect_min_size = Vector2(500, 500)
|
|
||||||
dialog.access = FileDialog.ACCESS_FILESYSTEM
|
|
||||||
dialog.mode = FileDialog.MODE_SAVE_FILE
|
|
||||||
dialog.add_filter("*.mmn;Material Maker Node")
|
|
||||||
dialog.connect("file_selected", self, "do_save_node")
|
|
||||||
dialog.popup_centered()
|
|
||||||
|
|
||||||
func do_save_node(file_name):
|
|
||||||
var file = File.new()
|
|
||||||
if file.open(file_name, File.WRITE) == OK:
|
|
||||||
file.store_string(to_json(model_data))
|
|
||||||
file.close()
|
|
||||||
model = file_name
|
|
||||||
|
|
||||||
func deserialize(data):
|
|
||||||
if data.has("model_data"):
|
|
||||||
update_node(data.model_data)
|
|
||||||
.deserialize(data)
|
|
||||||
|
|
||||||
func serialize():
|
|
||||||
var file = model
|
|
||||||
model = "custom"
|
|
||||||
var return_value = .serialize()
|
|
||||||
model = file
|
|
||||||
return_value.model_data = model_data
|
|
||||||
return return_value
|
|
@ -1,65 +0,0 @@
|
|||||||
[gd_scene load_steps=6 format=2]
|
|
||||||
|
|
||||||
[ext_resource path="res://addons/material_maker/nodes/custom.gd" type="Script" id=1]
|
|
||||||
[ext_resource path="res://addons/material_maker/icons/icons.svg" type="Texture" id=2]
|
|
||||||
|
|
||||||
[sub_resource type="AtlasTexture" id=1]
|
|
||||||
flags = 4
|
|
||||||
atlas = ExtResource( 2 )
|
|
||||||
region = Rect2( 16, 16, 15, 17 )
|
|
||||||
|
|
||||||
[sub_resource type="AtlasTexture" id=2]
|
|
||||||
flags = 4
|
|
||||||
atlas = ExtResource( 2 )
|
|
||||||
region = Rect2( 48, 16, 16, 16 )
|
|
||||||
|
|
||||||
[sub_resource type="AtlasTexture" id=3]
|
|
||||||
flags = 4
|
|
||||||
atlas = ExtResource( 2 )
|
|
||||||
region = Rect2( 32, 16, 16, 16 )
|
|
||||||
|
|
||||||
[node name="Custom" type="GraphNode"]
|
|
||||||
margin_left = 1.0
|
|
||||||
margin_top = 2.0
|
|
||||||
margin_right = 95.0
|
|
||||||
margin_bottom = 53.0
|
|
||||||
mouse_filter = 1
|
|
||||||
title = "Custom"
|
|
||||||
show_close = true
|
|
||||||
slot/0/left_enabled = false
|
|
||||||
slot/0/left_type = 0
|
|
||||||
slot/0/left_color = Color( 1, 1, 1, 1 )
|
|
||||||
slot/0/right_enabled = false
|
|
||||||
slot/0/right_type = 0
|
|
||||||
slot/0/right_color = Color( 1, 1, 1, 1 )
|
|
||||||
script = ExtResource( 1 )
|
|
||||||
model = null
|
|
||||||
|
|
||||||
[node name="CustomNodeButtons" type="HBoxContainer" parent="."]
|
|
||||||
margin_left = 16.0
|
|
||||||
margin_top = 24.0
|
|
||||||
margin_right = 92.0
|
|
||||||
margin_bottom = 47.0
|
|
||||||
|
|
||||||
[node name="Edit" type="Button" parent="CustomNodeButtons"]
|
|
||||||
margin_right = 27.0
|
|
||||||
margin_bottom = 23.0
|
|
||||||
icon = SubResource( 1 )
|
|
||||||
flat = true
|
|
||||||
|
|
||||||
[node name="Load" type="Button" parent="CustomNodeButtons"]
|
|
||||||
margin_left = 31.0
|
|
||||||
margin_right = 59.0
|
|
||||||
margin_bottom = 23.0
|
|
||||||
icon = SubResource( 2 )
|
|
||||||
flat = true
|
|
||||||
|
|
||||||
[node name="Save" type="Button" parent="CustomNodeButtons"]
|
|
||||||
margin_left = 63.0
|
|
||||||
margin_right = 76.0
|
|
||||||
margin_bottom = 23.0
|
|
||||||
icon = SubResource( 3 )
|
|
||||||
flat = true
|
|
||||||
[connection signal="pressed" from="CustomNodeButtons/Edit" to="." method="_on_Edit_pressed"]
|
|
||||||
[connection signal="pressed" from="CustomNodeButtons/Load" to="." method="_on_Load_pressed"]
|
|
||||||
[connection signal="pressed" from="CustomNodeButtons/Save" to="." method="_on_Save_pressed"]
|
|
@ -28,7 +28,9 @@ func on_offset_changed():
|
|||||||
func on_parameter_changed(p, v):
|
func on_parameter_changed(p, v):
|
||||||
if ignore_parameter_change == p:
|
if ignore_parameter_change == p:
|
||||||
return
|
return
|
||||||
if controls.has(p):
|
if p == "__update_all__":
|
||||||
|
call_deferred("update_node")
|
||||||
|
elif controls.has(p):
|
||||||
var o = controls[p]
|
var o = controls[p]
|
||||||
if o is LineEdit:
|
if o is LineEdit:
|
||||||
o.text = str(v)
|
o.text = str(v)
|
||||||
@ -140,14 +142,33 @@ func create_parameter_control(p : Dictionary):
|
|||||||
control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance()
|
control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance()
|
||||||
return control
|
return control
|
||||||
|
|
||||||
func update_node():
|
func save_preview_widget():
|
||||||
# Clean node
|
|
||||||
var custom_node_buttons = null
|
|
||||||
if preview != null:
|
if preview != null:
|
||||||
remove_child(preview)
|
remove_child(preview)
|
||||||
if preview_timer != null:
|
if preview_timer != null:
|
||||||
preview_timer.stop()
|
preview_timer.stop()
|
||||||
remove_child(preview_timer)
|
remove_child(preview_timer)
|
||||||
|
|
||||||
|
func restore_preview_widget():
|
||||||
|
if preview == null:
|
||||||
|
preview = TextureRect.new()
|
||||||
|
preview.visible = false
|
||||||
|
preview_position = get_child_count()
|
||||||
|
if preview.visible:
|
||||||
|
add_child(preview)
|
||||||
|
update_preview()
|
||||||
|
set_slot(preview_position, false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0))
|
||||||
|
# Preview timer
|
||||||
|
if preview_timer == null:
|
||||||
|
preview_timer = Timer.new()
|
||||||
|
preview_timer.one_shot = true
|
||||||
|
preview_timer.connect("timeout", self, "do_update_preview")
|
||||||
|
add_child(preview_timer)
|
||||||
|
|
||||||
|
func update_node():
|
||||||
|
# Clean node
|
||||||
|
var custom_node_buttons = null
|
||||||
|
save_preview_widget()
|
||||||
for c in get_children():
|
for c in get_children():
|
||||||
remove_child(c)
|
remove_child(c)
|
||||||
c.free()
|
c.free()
|
||||||
@ -275,23 +296,14 @@ func update_node():
|
|||||||
var empty_control : Control = Control.new()
|
var empty_control : Control = Control.new()
|
||||||
empty_control.rect_min_size.x = button_width
|
empty_control.rect_min_size.x = button_width
|
||||||
hsizer.add_child(empty_control)
|
hsizer.add_child(empty_control)
|
||||||
# Preview
|
|
||||||
if preview == null:
|
|
||||||
preview = TextureRect.new()
|
|
||||||
preview.visible = false
|
|
||||||
preview_position = get_child_count()
|
|
||||||
# Edit buttons
|
# Edit buttons
|
||||||
if generator.model == null:
|
if generator.is_editable():
|
||||||
var edit_buttons = preload("res://addons/material_maker/nodes/edit_buttons.tscn").instance()
|
var edit_buttons = preload("res://addons/material_maker/nodes/edit_buttons.tscn").instance()
|
||||||
add_child(edit_buttons)
|
add_child(edit_buttons)
|
||||||
edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator")
|
edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator")
|
||||||
# Preview timer
|
set_slot(edit_buttons.get_index(), false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0))
|
||||||
if preview_timer == null:
|
# Preview
|
||||||
preview_timer = Timer.new()
|
restore_preview_widget()
|
||||||
preview_timer.one_shot = true
|
|
||||||
preview_timer.connect("timeout", self, "do_update_preview")
|
|
||||||
add_child(preview_timer)
|
|
||||||
|
|
||||||
|
|
||||||
func edit_generator():
|
func edit_generator():
|
||||||
if generator.has_method("edit"):
|
if generator.has_method("edit"):
|
||||||
@ -350,15 +362,18 @@ func do_save_generator(file_name : String):
|
|||||||
file.store_string(to_json(data))
|
file.store_string(to_json(data))
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
func update_preview_buttons(index : int):
|
||||||
|
for i in range(output_count):
|
||||||
|
if i != index:
|
||||||
|
var line = get_child(i)
|
||||||
|
line.get_child(line.get_child_count()-1).pressed = false
|
||||||
|
|
||||||
func on_preview_button(pressed : bool, index : int):
|
func on_preview_button(pressed : bool, index : int):
|
||||||
if pressed:
|
if pressed:
|
||||||
preview_index = index
|
preview_index = index
|
||||||
var width
|
var width
|
||||||
if preview.visible:
|
if preview.visible:
|
||||||
for i in range(output_count):
|
update_preview_buttons(index)
|
||||||
if i != index:
|
|
||||||
var line = get_child(i)
|
|
||||||
line.get_child(line.get_child_count()-1).pressed = false
|
|
||||||
update_preview()
|
update_preview()
|
||||||
else:
|
else:
|
||||||
var status = update_preview(get_child(0).rect_size.x)
|
var status = update_preview(get_child(0).rect_size.x)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
tool
|
tool
|
||||||
extends "res://addons/material_maker/node_base.gd"
|
extends GraphNode
|
||||||
|
|
||||||
var generator = null
|
var generator = null
|
||||||
|
|
||||||
|
@ -1,281 +0,0 @@
|
|||||||
tool
|
|
||||||
extends "res://addons/material_maker/node_base.gd"
|
|
||||||
|
|
||||||
export(String) var model = null setget set_model
|
|
||||||
var model_data = null
|
|
||||||
var uses_seed = false
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
show_close = true
|
|
||||||
connect("offset_changed", self, "_on_offset_changed")
|
|
||||||
|
|
||||||
func set_model(m):
|
|
||||||
if m != null and typeof(m) == TYPE_STRING:
|
|
||||||
var file = File.new()
|
|
||||||
var file_name = m
|
|
||||||
if !file.file_exists(file_name):
|
|
||||||
file_name = "res://addons/material_maker/nodes/%s.mmn" % [ m ]
|
|
||||||
if file.file_exists(file_name):
|
|
||||||
if file.open(file_name, File.READ) != OK:
|
|
||||||
return
|
|
||||||
var data = file.get_as_text()
|
|
||||||
var status = validate_json(data)
|
|
||||||
file.close()
|
|
||||||
if status != "":
|
|
||||||
print("Incorrect node description (%s)" % status)
|
|
||||||
return
|
|
||||||
data = parse_json(data)
|
|
||||||
model = m
|
|
||||||
update_node(data)
|
|
||||||
else:
|
|
||||||
print("set_model error "+str(m))
|
|
||||||
|
|
||||||
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":
|
|
||||||
remove_child(c)
|
|
||||||
c.queue_free()
|
|
||||||
else:
|
|
||||||
custom_node_buttons = c
|
|
||||||
# Rebuild node
|
|
||||||
title = data.name
|
|
||||||
model_data = data
|
|
||||||
uses_seed = false
|
|
||||||
if model_data.has("instance") and model_data.instance.find("$(seed)"):
|
|
||||||
uses_seed = true
|
|
||||||
if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY:
|
|
||||||
var control_list = []
|
|
||||||
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
|
|
||||||
control_list.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(control_list)
|
|
||||||
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]
|
|
||||||
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())
|
|
||||||
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]
|
|
||||||
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)
|
|
||||||
else:
|
|
||||||
model_data.outputs = []
|
|
||||||
if custom_node_buttons != null:
|
|
||||||
move_child(custom_node_buttons, get_child_count()-1)
|
|
||||||
|
|
||||||
func find_keyword_call(string, keyword):
|
|
||||||
var search_string = "$%s(" % keyword
|
|
||||||
var position = string.find(search_string)
|
|
||||||
if position == -1:
|
|
||||||
return null
|
|
||||||
var parenthesis_level = 0
|
|
||||||
var parameter_begin = position+search_string.length()
|
|
||||||
var parameter_end = -1
|
|
||||||
for i in range(parameter_begin, string.length()):
|
|
||||||
if string[i] == '(':
|
|
||||||
parenthesis_level += 1
|
|
||||||
elif string[i] == ')':
|
|
||||||
if parenthesis_level == 0:
|
|
||||||
return string.substr(parameter_begin, i-parameter_begin)
|
|
||||||
parenthesis_level -= 1
|
|
||||||
return ""
|
|
||||||
|
|
||||||
func replace_input(string, input, type, src, default):
|
|
||||||
var required_defs = ""
|
|
||||||
var required_code = ""
|
|
||||||
while true:
|
|
||||||
var uv = find_keyword_call(string, input)
|
|
||||||
if uv == null:
|
|
||||||
break
|
|
||||||
elif uv == "":
|
|
||||||
print("syntax error")
|
|
||||||
break
|
|
||||||
var src_code
|
|
||||||
if src == null:
|
|
||||||
src_code = subst(default, "(%s)" % uv)
|
|
||||||
else:
|
|
||||||
src_code = src.get_shader_code(uv)
|
|
||||||
src_code.string = src_code[type]
|
|
||||||
required_defs += src_code.defs
|
|
||||||
required_code += src_code.code
|
|
||||||
string = string.replace("$%s(%s)" % [ input, uv ], src_code.string)
|
|
||||||
return { string=string, defs=required_defs, code=required_code }
|
|
||||||
|
|
||||||
func is_word_letter(l):
|
|
||||||
return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1
|
|
||||||
|
|
||||||
func replace_variable(string, variable, value):
|
|
||||||
string = string.replace("$(%s)" % variable, value)
|
|
||||||
var keyword_size = variable.length()+1
|
|
||||||
var new_string = ""
|
|
||||||
while !string.empty():
|
|
||||||
var pos = string.find("$"+variable)
|
|
||||||
if pos == -1:
|
|
||||||
new_string += string
|
|
||||||
break
|
|
||||||
new_string += string.left(pos)
|
|
||||||
string = string.right(pos)
|
|
||||||
if string.empty() or !is_word_letter(string[0]):
|
|
||||||
new_string += value
|
|
||||||
else:
|
|
||||||
new_string += "$"+variable
|
|
||||||
string = string.right(keyword_size)
|
|
||||||
return new_string
|
|
||||||
|
|
||||||
func subst(string, uv = ""):
|
|
||||||
var required_defs = ""
|
|
||||||
var required_code = ""
|
|
||||||
string = replace_variable(string, "name", name)
|
|
||||||
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 !p.has("name") or !p.has("type"):
|
|
||||||
continue
|
|
||||||
var value = parameters[p.name]
|
|
||||||
var value_string = null
|
|
||||||
if p.type == "float":
|
|
||||||
value_string = "%.9f" % value
|
|
||||||
elif p.type == "size":
|
|
||||||
value_string = "%.9f" % pow(2, value+p.first)
|
|
||||||
elif p.type == "enum":
|
|
||||||
value_string = p.values[value].value
|
|
||||||
elif p.type == "color":
|
|
||||||
value_string = "vec4(%.9f, %.9f, %.9f, %.9f)" % [ value.r, value.g, value.b, value.a ]
|
|
||||||
elif p.type == "gradient":
|
|
||||||
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]
|
|
||||||
var source = get_source(i)
|
|
||||||
var result = replace_input(string, input.name, input.type, source, input.default)
|
|
||||||
string = result.string
|
|
||||||
required_defs += result.defs
|
|
||||||
required_code += result.code
|
|
||||||
return { string=string, defs=required_defs, code=required_code }
|
|
||||||
|
|
||||||
func _get_shader_code(uv, slot = 0):
|
|
||||||
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]
|
|
||||||
rv.defs = ""
|
|
||||||
if model_data.has("instance") && generated_variants.empty():
|
|
||||||
rv.defs += subst(model_data.instance).string
|
|
||||||
for p in model_data.parameters:
|
|
||||||
if p.type == "gradient":
|
|
||||||
rv.defs += parameters[p.name].get_shader(p.name+"_gradient_fct")
|
|
||||||
var variant_index = generated_variants.find(variant_string)
|
|
||||||
if variant_index == -1:
|
|
||||||
variant_index = generated_variants.size()
|
|
||||||
generated_variants.append(variant_string)
|
|
||||||
for t in output_info:
|
|
||||||
if output.has(t.field):
|
|
||||||
var subst_output = subst(output[t.field], 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 ]
|
|
||||||
for t in output_info:
|
|
||||||
if output.has(t.field):
|
|
||||||
rv[t.field] = "%s_%d_%d_%s" % [ name, slot, 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)
|
|
||||||
return list
|
|
||||||
|
|
||||||
func _on_offset_changed():
|
|
||||||
update_shaders()
|
|
||||||
|
|
||||||
func serialize():
|
|
||||||
var return_value = .serialize()
|
|
||||||
return_value.type = model
|
|
||||||
return return_value
|
|
87
addons/material_maker/nodes/switch.gd
Normal file
87
addons/material_maker/nodes/switch.gd
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
tool
|
||||||
|
extends MMGraphNodeGeneric
|
||||||
|
|
||||||
|
var fixed_lines : int = 0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
update_node()
|
||||||
|
|
||||||
|
func update_preview_buttons(index : int):
|
||||||
|
for i in range(generator.parameters.outputs):
|
||||||
|
if i != index:
|
||||||
|
var line = get_child(i)
|
||||||
|
line.get_child(2).pressed = false
|
||||||
|
|
||||||
|
func update_node():
|
||||||
|
print("update_node")
|
||||||
|
if generator == null or !generator.parameters.has("outputs") or !generator.parameters.has("choices"):
|
||||||
|
return
|
||||||
|
save_preview_widget()
|
||||||
|
var new_fixed_lines = 3 if generator.editable else 1
|
||||||
|
if new_fixed_lines != fixed_lines:
|
||||||
|
fixed_lines = new_fixed_lines
|
||||||
|
# Remove all lines
|
||||||
|
while get_child_count() > 0:
|
||||||
|
var remove = get_child(0)
|
||||||
|
remove_child(remove)
|
||||||
|
remove.free()
|
||||||
|
var lines_list = []
|
||||||
|
if generator.editable:
|
||||||
|
lines_list.push_back( { name="outputs", min=1, max=5 } )
|
||||||
|
lines_list.push_back( { name="choices", min=2, max=5 } )
|
||||||
|
lines_list.push_back( { name="source", min=0, max=generator.parameters.choices-1 } )
|
||||||
|
for l in lines_list:
|
||||||
|
var sizer = HBoxContainer.new()
|
||||||
|
var input_label = Label.new()
|
||||||
|
sizer.add_child(input_label)
|
||||||
|
var control : HSlider = HSlider.new()
|
||||||
|
control.name = l.name
|
||||||
|
control.value = generator.parameters[l.name]
|
||||||
|
control.min_value = l.min
|
||||||
|
control.max_value = l.max
|
||||||
|
control.step = 1
|
||||||
|
control.rect_min_size.x = 75
|
||||||
|
sizer.add_child(control)
|
||||||
|
control.connect("value_changed", self, "_on_value_changed", [ l.name ])
|
||||||
|
controls[l.name] = control
|
||||||
|
sizer.add_child(preload("res://addons/material_maker/widgets/preview_button.tscn").instance())
|
||||||
|
add_child(sizer)
|
||||||
|
else:
|
||||||
|
# Keep lines with controls
|
||||||
|
while get_child_count() > output_count and get_child_count() > fixed_lines:
|
||||||
|
var remove = get_child(get_child_count()-1)
|
||||||
|
remove_child(remove)
|
||||||
|
remove.free()
|
||||||
|
# Populate the GraphNode
|
||||||
|
var output_count : int = generator.parameters.outputs
|
||||||
|
var input_count : int = output_count * generator.parameters.choices
|
||||||
|
controls["source"].max_value = generator.parameters.choices-1
|
||||||
|
while get_child_count() < input_count:
|
||||||
|
var sizer = HBoxContainer.new()
|
||||||
|
var input_label = Label.new()
|
||||||
|
sizer.add_child(input_label)
|
||||||
|
if get_child_count() < 5:
|
||||||
|
var space = Control.new()
|
||||||
|
space.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
|
||||||
|
sizer.add_child(space)
|
||||||
|
sizer.add_child(preload("res://addons/material_maker/widgets/preview_button.tscn").instance())
|
||||||
|
add_child(sizer)
|
||||||
|
rect_size = Vector2(0, 0)
|
||||||
|
for i in range(get_child_count()):
|
||||||
|
var sizer = get_child(i)
|
||||||
|
var has_input = true
|
||||||
|
var has_output = false
|
||||||
|
if i < 5:
|
||||||
|
has_output = i < output_count
|
||||||
|
sizer.get_child(2).visible = has_output
|
||||||
|
sizer.get_child(2).connect("toggled", self, "on_preview_button", [ i ])
|
||||||
|
if i >= input_count:
|
||||||
|
sizer.get_child(0).text = ""
|
||||||
|
has_input = false
|
||||||
|
else:
|
||||||
|
sizer.get_child(0).text = PoolByteArray([65+i%int(output_count)]).get_string_from_ascii()+str(1+i/int(output_count))
|
||||||
|
sizer.get_child(0).add_color_override("font_color", Color(1.0, 1.0, 1.0) if i/int(output_count) == generator.parameters.source else Color(0.5, 0.5, 0.5))
|
||||||
|
set_slot(i, has_input, 0, Color(0.0, 0.5, 0.0, 0.5), has_output, 0, Color(0.0, 0.5, 0.0, 0.5))
|
||||||
|
# Preview
|
||||||
|
restore_preview_widget()
|
||||||
|
print("update_node end")
|
129
addons/material_maker/nodes/switch.tscn
Normal file
129
addons/material_maker/nodes/switch.tscn
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/material_maker/nodes/switch.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://addons/material_maker/widgets/preview_button.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="Theme" id=1]
|
||||||
|
|
||||||
|
[node name="Switch" type="GraphNode"]
|
||||||
|
margin_left = -1.0
|
||||||
|
margin_top = -1.0
|
||||||
|
margin_right = 150.0
|
||||||
|
margin_bottom = 78.0
|
||||||
|
mouse_filter = 1
|
||||||
|
size_flags_stretch_ratio = 0.13
|
||||||
|
theme = SubResource( 1 )
|
||||||
|
title = "Switch"
|
||||||
|
show_close = true
|
||||||
|
slot/0/left_enabled = false
|
||||||
|
slot/0/left_type = 0
|
||||||
|
slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
|
||||||
|
slot/0/right_enabled = true
|
||||||
|
slot/0/right_type = 0
|
||||||
|
slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
|
||||||
|
slot/1/left_enabled = false
|
||||||
|
slot/1/left_type = 0
|
||||||
|
slot/1/left_color = Color( 1, 1, 1, 1 )
|
||||||
|
slot/1/right_enabled = false
|
||||||
|
slot/1/right_type = 0
|
||||||
|
slot/1/right_color = Color( 1, 1, 1, 1 )
|
||||||
|
slot/2/left_enabled = false
|
||||||
|
slot/2/left_type = 0
|
||||||
|
slot/2/left_color = Color( 1, 1, 1, 1 )
|
||||||
|
slot/2/right_enabled = false
|
||||||
|
slot/2/right_type = 0
|
||||||
|
slot/2/right_color = Color( 1, 1, 1, 1 )
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="HBox1" type="HBoxContainer" parent="."]
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 24.0
|
||||||
|
margin_right = 135.0
|
||||||
|
margin_bottom = 40.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="HBox1"]
|
||||||
|
margin_top = 1.0
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 15.0
|
||||||
|
rect_min_size = Vector2( 20, 0 )
|
||||||
|
text = "A0"
|
||||||
|
|
||||||
|
[node name="outputs" type="HSlider" parent="HBox1"]
|
||||||
|
margin_left = 24.0
|
||||||
|
margin_right = 99.0
|
||||||
|
margin_bottom = 16.0
|
||||||
|
rect_min_size = Vector2( 75, 0 )
|
||||||
|
hint_tooltip = "Output count"
|
||||||
|
min_value = 1.0
|
||||||
|
max_value = 5.0
|
||||||
|
value = 2.0
|
||||||
|
|
||||||
|
[node name="PreviewButton" parent="HBox1" instance=ExtResource( 2 )]
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 103.0
|
||||||
|
margin_right = 119.0
|
||||||
|
margin_bottom = 16.0
|
||||||
|
|
||||||
|
[node name="HBox2" type="HBoxContainer" parent="."]
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 40.0
|
||||||
|
margin_right = 135.0
|
||||||
|
margin_bottom = 56.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="HBox2"]
|
||||||
|
margin_top = 1.0
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 15.0
|
||||||
|
rect_min_size = Vector2( 20, 0 )
|
||||||
|
text = "A0"
|
||||||
|
|
||||||
|
[node name="choices" type="HSlider" parent="HBox2"]
|
||||||
|
margin_left = 24.0
|
||||||
|
margin_right = 99.0
|
||||||
|
margin_bottom = 16.0
|
||||||
|
rect_min_size = Vector2( 75, 0 )
|
||||||
|
hint_tooltip = "Choice count"
|
||||||
|
min_value = 2.0
|
||||||
|
max_value = 5.0
|
||||||
|
value = 2.0
|
||||||
|
|
||||||
|
[node name="PreviewButton" parent="HBox2" instance=ExtResource( 2 )]
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 103.0
|
||||||
|
margin_right = 119.0
|
||||||
|
margin_bottom = 16.0
|
||||||
|
|
||||||
|
[node name="HBox3" type="HBoxContainer" parent="."]
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 57.0
|
||||||
|
margin_right = 135.0
|
||||||
|
margin_bottom = 73.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="HBox3"]
|
||||||
|
margin_top = 1.0
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 15.0
|
||||||
|
rect_min_size = Vector2( 20, 0 )
|
||||||
|
text = "A0"
|
||||||
|
|
||||||
|
[node name="source" type="HSlider" parent="HBox3"]
|
||||||
|
margin_left = 24.0
|
||||||
|
margin_right = 99.0
|
||||||
|
margin_bottom = 16.0
|
||||||
|
rect_min_size = Vector2( 75, 0 )
|
||||||
|
hint_tooltip = "Choice"
|
||||||
|
max_value = 4.0
|
||||||
|
value = 1.0
|
||||||
|
ticks_on_borders = true
|
||||||
|
|
||||||
|
[node name="PreviewButton" parent="HBox3" instance=ExtResource( 2 )]
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 103.0
|
||||||
|
margin_right = 119.0
|
||||||
|
margin_bottom = 16.0
|
||||||
|
[connection signal="value_changed" from="HBox1/outputs" to="." method="_on_value_changed" binds= [ "outputs" ]]
|
||||||
|
[connection signal="value_changed" from="HBox2/choices" to="." method="_on_value_changed" binds= [ "choices" ]]
|
||||||
|
[connection signal="value_changed" from="HBox3/source" to="." method="_on_value_changed" binds= [ "source" ]]
|
@ -179,5 +179,4 @@ file_logging/enable_file_logging=true
|
|||||||
|
|
||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
quality/filters/anisotropic_filter_level=16
|
|
||||||
environment/default_environment="res://default_env.tres"
|
environment/default_environment="res://default_env.tres"
|
||||||
|
Loading…
Reference in New Issue
Block a user