mirror of
https://github.com/Relintai/material-maker.git
synced 2024-11-13 06:27:18 +01:00
Updated loader and random seed handling (#15)
Loader is not a lot more generic and deserialization code moved to generators. There is now a small dice button on nodes that create random patterns that can be used to freeze the seed. Frozen nodes can thus be moved without affecting the seed. Graph nodes can also transmit their seed to their children (this behavior can be enabled/disabled using the dice button at the top right of the graph pane).
This commit is contained in:
parent
c466d20229
commit
c121f7c00a
@ -34,6 +34,9 @@ var position : Vector2 = Vector2(0, 0)
|
||||
var model = null
|
||||
var parameters = {}
|
||||
|
||||
var seed_locked : bool = false
|
||||
var seed_value : int = 0
|
||||
|
||||
func _ready() -> void:
|
||||
init_parameters()
|
||||
|
||||
@ -49,9 +52,28 @@ func toggle_editable() -> bool:
|
||||
func is_editable() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func has_randomness():
|
||||
return false
|
||||
|
||||
func get_seed() -> int:
|
||||
if !seed_locked:
|
||||
var s : int = ((int(position.x) * 0x1f1f1f1f) ^ int(position.y)) % 65536
|
||||
if get_parent().get("transmits_seed") != null and get_parent().transmits_seed:
|
||||
s += get_parent().get_seed()
|
||||
return s
|
||||
else:
|
||||
return seed_value
|
||||
|
||||
func toggle_lock_seed():
|
||||
if !seed_locked:
|
||||
seed_value = get_seed()
|
||||
seed_locked = !seed_locked
|
||||
return seed_locked
|
||||
|
||||
func is_seed_locked():
|
||||
return seed_locked
|
||||
|
||||
func init_parameters() -> void:
|
||||
for p in get_parameter_defs():
|
||||
if !parameters.has(p.name):
|
||||
@ -64,6 +86,9 @@ func init_parameters() -> void:
|
||||
|
||||
func set_position(p) -> void:
|
||||
position = p
|
||||
if has_randomness() and !is_seed_locked():
|
||||
for i in range(get_output_defs().size()):
|
||||
notify_output_change(i)
|
||||
|
||||
func get_type() -> String:
|
||||
return "generic"
|
||||
@ -163,6 +188,7 @@ func get_shader_code(uv : String, output_index : int, context : MMGenContext) ->
|
||||
func _get_shader_code(__, __, __) -> Dictionary:
|
||||
return {}
|
||||
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
print("cannot save "+name)
|
||||
return data
|
||||
@ -171,8 +197,35 @@ func serialize():
|
||||
var rv = { name=name, type=get_type(), parameters={}, node_position={ x=position.x, y=position.y } }
|
||||
for p in parameters.keys():
|
||||
rv.parameters[p] = MMType.serialize_value(parameters[p])
|
||||
if seed_locked:
|
||||
rv.seed_value = seed_value
|
||||
if model != null:
|
||||
rv.type = model
|
||||
else:
|
||||
rv = _serialize(rv)
|
||||
return rv
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
pass
|
||||
|
||||
func deserialize(data : Dictionary) -> void:
|
||||
_deserialize(data)
|
||||
if data.has("name"):
|
||||
name = data.name
|
||||
if data.has("node_position"):
|
||||
position.x = data.node_position.x
|
||||
position.y = data.node_position.y
|
||||
if data.has("parameters"):
|
||||
for p in data.parameters.keys():
|
||||
set_parameter(p, MMType.deserialize_value(data.parameters[p]))
|
||||
else:
|
||||
for p in get_parameter_defs():
|
||||
if data.has(p.name) and p.name != "type":
|
||||
set_parameter(p.name, MMType.deserialize_value(data[p.name]))
|
||||
if data.has("seed_value"):
|
||||
seed_locked = true
|
||||
seed_value = data.seed_value
|
||||
else:
|
||||
seed_locked = false
|
||||
_post_load()
|
||||
|
||||
|
@ -33,3 +33,9 @@ func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.text = text
|
||||
data.size = { x=size.x, y=size.y }
|
||||
return data
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
if data.has("text"):
|
||||
text = data.text
|
||||
if data.has("size"):
|
||||
size = Vector2(data.size.x, data.size.y)
|
||||
|
@ -175,6 +175,10 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
|
||||
rv[convolution_params.output_type] = "%s_%d" % [ genname, variant_index ]
|
||||
return rv
|
||||
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.convolution_params = convolution_params
|
||||
return data
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
set_convolution_params(data.convolution_params)
|
||||
|
@ -5,10 +5,13 @@ class_name MMGenGraph
|
||||
var label : String = "Graph"
|
||||
var connections = []
|
||||
|
||||
var editable = false
|
||||
var editable : bool = false
|
||||
|
||||
var transmits_seed : bool = true
|
||||
|
||||
signal connections_changed(removed_connections, added_connections)
|
||||
|
||||
|
||||
func fix_remotes() -> void:
|
||||
for c in get_children():
|
||||
if c is MMGenRemote:
|
||||
@ -17,6 +20,11 @@ func fix_remotes() -> void:
|
||||
func _post_load() -> void:
|
||||
fix_remotes()
|
||||
|
||||
|
||||
func has_randomness():
|
||||
return transmits_seed
|
||||
|
||||
|
||||
func get_type() -> String:
|
||||
return "graph"
|
||||
|
||||
@ -203,13 +211,6 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
|
||||
return rv
|
||||
return { globals=[], defs="", code="", textures={} }
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.label = label
|
||||
data.nodes = []
|
||||
for c in get_children():
|
||||
data.nodes.append(c.serialize())
|
||||
data.connections = connections
|
||||
return data
|
||||
|
||||
func edit(node) -> void:
|
||||
node.get_parent().call_deferred("update_view", self)
|
||||
@ -300,3 +301,19 @@ func create_subgraph(gens : Array) -> void:
|
||||
new_graph.add_child(gen_parameters)
|
||||
fix_remotes()
|
||||
new_graph.fix_remotes()
|
||||
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.label = label
|
||||
data.nodes = []
|
||||
for c in get_children():
|
||||
data.nodes.append(c.serialize())
|
||||
data.connections = connections
|
||||
return data
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
if data.has("label"):
|
||||
label = data.label
|
||||
var nodes = data.nodes if data.has("nodes") else []
|
||||
var connections = data.connections if data.has("connections") else []
|
||||
load("res://addons/material_maker/engine/loader.gd").add_to_gen_graph(self, nodes, connections)
|
||||
|
@ -97,3 +97,6 @@ func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.type = "ios"
|
||||
data.ports = ports
|
||||
return data
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
ports = data.ports
|
||||
|
@ -134,11 +134,6 @@ func set_parameter(p : String, v) -> void:
|
||||
if name == "gen_parameters":
|
||||
get_parent().parameters[p] = v
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.type = "remote"
|
||||
data.widgets = widgets
|
||||
return data
|
||||
|
||||
func create_linked_control(label : String) -> String:
|
||||
var n = get_next_widget_name()
|
||||
widgets.push_back({ name=n, label=label, type="linked_control", linked_widgets=[] })
|
||||
@ -219,3 +214,12 @@ func remove_configuration(widget_name : String, config_name : String) -> void:
|
||||
if widget.type == "config_control":
|
||||
widget.configurations.erase(config_name)
|
||||
emit_signal("parameter_changed", "__update_all__", null)
|
||||
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.type = "remote"
|
||||
data.widgets = widgets
|
||||
return data
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
set_widgets(data.widgets.duplicate(true))
|
||||
|
@ -16,6 +16,9 @@ func toggle_editable() -> bool:
|
||||
func is_editable() -> bool:
|
||||
return editable
|
||||
|
||||
func has_randomness():
|
||||
return uses_seed
|
||||
|
||||
func get_type() -> String:
|
||||
return "shader"
|
||||
|
||||
@ -45,24 +48,30 @@ func get_output_defs():
|
||||
func set_shader_model(data: Dictionary):
|
||||
shader_model = data
|
||||
init_parameters()
|
||||
uses_seed = false
|
||||
if shader_model.has("outputs"):
|
||||
for i in range(shader_model.outputs.size()):
|
||||
var output = shader_model.outputs[i]
|
||||
var output_code = ""
|
||||
if output.has("rgba"):
|
||||
shader_model.outputs[i].type = "rgba"
|
||||
output_code = output.rgba
|
||||
elif output.has("rgb"):
|
||||
shader_model.outputs[i].type = "rgb"
|
||||
else:
|
||||
output_code = output.rgb
|
||||
elif output.has("f"):
|
||||
shader_model.outputs[i].type = "f"
|
||||
|
||||
func set_position(p) -> void:
|
||||
.set_position(p)
|
||||
if uses_seed:
|
||||
source_changed(0)
|
||||
|
||||
func get_seed() -> int:
|
||||
var s = ((int(position.x) * 0x1f1f1f1f) ^ int(position.y)) % 65536
|
||||
return s
|
||||
output_code = output.f
|
||||
else:
|
||||
print("Unsupported output type")
|
||||
if output_code.find("$seed") != -1 or output_code.find("$(seed)") != -1:
|
||||
uses_seed = true
|
||||
if shader_model.has("code"):
|
||||
if shader_model.code.find("$seed") != -1 or shader_model.code.find("$(seed)") != -1:
|
||||
uses_seed = true
|
||||
if shader_model.has("instance"):
|
||||
if shader_model.instance.find("$seed") != -1 or shader_model.instance.find("$(seed)") != -1:
|
||||
uses_seed = true
|
||||
|
||||
func find_keyword_call(string, keyword):
|
||||
var search_string = "$%s(" % keyword
|
||||
@ -156,7 +165,6 @@ func subst(string, context, uv = "") -> Dictionary:
|
||||
var tmp_string = replace_variable(string, "seed", str(get_seed()))
|
||||
if tmp_string != string:
|
||||
string = tmp_string
|
||||
uses_seed = true
|
||||
if uv != "":
|
||||
string = replace_variable(string, "uv", "("+uv+")")
|
||||
if shader_model.has("parameters") and typeof(shader_model.parameters) == TYPE_ARRAY:
|
||||
@ -213,7 +221,6 @@ func subst(string, context, uv = "") -> Dictionary:
|
||||
return { string=string, globals=required_globals, defs=required_defs, code=required_code, textures=required_textures }
|
||||
|
||||
func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary:
|
||||
uses_seed = false
|
||||
var genname = "o"+str(get_instance_id())
|
||||
var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ]
|
||||
var rv = { globals=[], defs="", code="", textures={} }
|
||||
@ -278,10 +285,18 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
|
||||
rv.globals.push_back(shader_model.global)
|
||||
return rv
|
||||
|
||||
|
||||
func _serialize(data: Dictionary) -> Dictionary:
|
||||
data.shader_model = shader_model
|
||||
return data
|
||||
|
||||
func _deserialize(data : Dictionary) -> void:
|
||||
if data.has("shader_model"):
|
||||
set_shader_model(data.shader_model)
|
||||
elif data.has("model_data"):
|
||||
set_shader_model(data.model_data)
|
||||
|
||||
|
||||
func edit(node) -> void:
|
||||
if shader_model != null:
|
||||
var edit_window = load("res://addons/material_maker/widgets/node_editor/node_editor.tscn").instance()
|
||||
|
@ -40,6 +40,7 @@ static func create_gen(data) -> MMGenBase:
|
||||
{ keyword="connections", type=MMGenGraph },
|
||||
{ keyword="nodes", type=MMGenGraph },
|
||||
{ keyword="shader_model", type=MMGenShader },
|
||||
{ keyword="convolution_params", type=MMGenConvolution },
|
||||
{ keyword="model_data", type=MMGenShader },
|
||||
{ keyword="convolution_params", type=MMGenConvolution },
|
||||
{ keyword="widgets", type=MMGenRemote }
|
||||
@ -48,40 +49,20 @@ static func create_gen(data) -> MMGenBase:
|
||||
material = MMGenMaterial,
|
||||
buffer = MMGenBuffer,
|
||||
image = MMGenImage,
|
||||
ios = MMGenIOs,
|
||||
switch = MMGenSwitch,
|
||||
export = MMGenExport,
|
||||
comment = MMGenComment,
|
||||
debug = MMGenDebug
|
||||
}
|
||||
var generator = null
|
||||
if data.has("connections") and data.has("nodes"):
|
||||
generator = MMGenGraph.new()
|
||||
if data.has("label"):
|
||||
generator.label = data.label
|
||||
add_to_gen_graph(generator, data.nodes, data.connections)
|
||||
elif data.has("shader_model"):
|
||||
generator = MMGenShader.new()
|
||||
generator.set_shader_model(data.shader_model)
|
||||
elif data.has("convolution_params"):
|
||||
generator = MMGenConvolution.new()
|
||||
generator.set_convolution_params(data.convolution_params)
|
||||
elif data.has("model_data"):
|
||||
generator = MMGenShader.new()
|
||||
generator.set_shader_model(data.model_data)
|
||||
elif data.has("widgets"):
|
||||
generator = MMGenRemote.new()
|
||||
generator.set_widgets(data.widgets.duplicate(true))
|
||||
elif data.has("type"):
|
||||
for g in guess:
|
||||
if data.has(g.keyword):
|
||||
generator = g.type.new()
|
||||
break
|
||||
if generator == null and data.has("type"):
|
||||
if types.has(data.type):
|
||||
generator = types[data.type].new()
|
||||
elif data.type == "comment":
|
||||
generator = MMGenComment.new()
|
||||
if data.has("text"):
|
||||
generator.text = data.text
|
||||
if data.has("size"):
|
||||
generator.size = Vector2(data.size.x, data.size.y)
|
||||
elif data.type == "ios":
|
||||
generator = MMGenIOs.new()
|
||||
generator.ports = data.ports
|
||||
else:
|
||||
var file = File.new()
|
||||
var gen_paths = [ STD_GENDEF_PATH, OS.get_executable_path().get_base_dir()+"/generators" ]
|
||||
@ -101,22 +82,10 @@ static func create_gen(data) -> MMGenBase:
|
||||
print("Cannot find description for "+data.type)
|
||||
if generator != null:
|
||||
generator.name = data.type
|
||||
else:
|
||||
if generator == null:
|
||||
print("LOADER: data not supported:"+str(data))
|
||||
if generator != null:
|
||||
if data.has("name"):
|
||||
generator.name = data.name
|
||||
if data.has("node_position"):
|
||||
generator.position.x = data.node_position.x
|
||||
generator.position.y = data.node_position.y
|
||||
if data.has("parameters"):
|
||||
for p in data.parameters.keys():
|
||||
generator.set_parameter(p, MMType.deserialize_value(data.parameters[p]))
|
||||
else:
|
||||
for p in generator.get_parameter_defs():
|
||||
if data.has(p.name) and p.name != "type":
|
||||
generator.set_parameter(p.name, MMType.deserialize_value(data[p.name]))
|
||||
generator._post_load()
|
||||
generator.deserialize(data)
|
||||
return generator
|
||||
|
||||
static func get_generator_list() -> Array:
|
||||
|
@ -15,6 +15,7 @@ var generator = null
|
||||
onready var timer : Timer = $Timer
|
||||
|
||||
onready var subgraph_ui : HBoxContainer = $GraphUI/SubGraphUI
|
||||
onready var button_transmits_seed : Button = $GraphUI/SubGraphUI/ButtonTransmitsSeed
|
||||
|
||||
signal save_path_changed
|
||||
signal graph_changed
|
||||
@ -127,6 +128,12 @@ func update_view(g) -> void:
|
||||
subgraph_ui.visible = generator != top_generator
|
||||
subgraph_ui.get_node("Label").text = generator.label
|
||||
center_view()
|
||||
if generator.get_parent() is MMGenGraph:
|
||||
button_transmits_seed.visible = true
|
||||
button_transmits_seed.pressed = generator.transmits_seed
|
||||
else:
|
||||
button_transmits_seed.visible = false
|
||||
|
||||
|
||||
func clear_material() -> void:
|
||||
if top_generator != null:
|
||||
@ -325,3 +332,8 @@ func edit_subgraph(g : MMGenGraph) -> void:
|
||||
if !g.is_editable():
|
||||
g.toggle_editable()
|
||||
update_view(g)
|
||||
|
||||
|
||||
func _on_ButtonTransmitsSeed_toggled(button_pressed):
|
||||
if button_pressed != generator.transmits_seed:
|
||||
generator.transmits_seed = button_pressed
|
||||
|
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=6 format=2]
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://addons/material_maker/graph_edit.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/material_maker/icons/icons.svg" type="Texture" id=2]
|
||||
@ -9,11 +9,16 @@ bg_color = Color( 0.6, 0.6, 0.6, 0 )
|
||||
[sub_resource type="AtlasTexture" id=2]
|
||||
flags = 4
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 15.4016, 47.1451, 16.7512, 17.8319 )
|
||||
region = Rect2( 64, 32, 16, 16 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=3]
|
||||
flags = 4
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 15.4016, 47.1451, 16.7512, 17.8319 )
|
||||
|
||||
[sub_resource type="AtlasTexture" id=4]
|
||||
flags = 4
|
||||
atlas = ExtResource( 2 )
|
||||
region = Rect2( 0, 48, 16, 16 )
|
||||
|
||||
[node name="GraphEdit" type="GraphEdit"]
|
||||
@ -37,7 +42,7 @@ margin_bottom = 24.0
|
||||
alignment = 2
|
||||
|
||||
[node name="SubGraphUI" type="HBoxContainer" parent="GraphUI"]
|
||||
margin_left = 362.0
|
||||
margin_left = 330.0
|
||||
margin_right = 544.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 9
|
||||
@ -48,23 +53,33 @@ margin_bottom = 24.0
|
||||
rect_min_size = Vector2( 150, 0 )
|
||||
size_flags_horizontal = 9
|
||||
|
||||
[node name="ButtonUp" type="Button" parent="GraphUI/SubGraphUI"]
|
||||
[node name="ButtonTransmitsSeed" type="Button" parent="GraphUI/SubGraphUI"]
|
||||
margin_left = 154.0
|
||||
margin_right = 182.0
|
||||
margin_bottom = 24.0
|
||||
hint_tooltip = "Affect children seeds"
|
||||
size_flags_horizontal = 9
|
||||
toggle_mode = true
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="ButtonUp" type="Button" parent="GraphUI/SubGraphUI"]
|
||||
margin_left = 186.0
|
||||
margin_right = 214.0
|
||||
margin_bottom = 24.0
|
||||
hint_tooltip = "Back to parent"
|
||||
size_flags_horizontal = 9
|
||||
icon = SubResource( 2 )
|
||||
icon = SubResource( 3 )
|
||||
|
||||
[node name="ButtonShowTree" type="Button" parent="GraphUI"]
|
||||
margin_left = 548.0
|
||||
margin_right = 576.0
|
||||
margin_bottom = 24.0
|
||||
hint_tooltip = "Show hierarchy"
|
||||
icon = SubResource( 3 )
|
||||
icon = SubResource( 4 )
|
||||
[connection signal="connection_request" from="." to="." method="connect_node"]
|
||||
[connection signal="disconnection_request" from="." to="." method="disconnect_node"]
|
||||
[connection signal="timeout" from="Timer" to="." method="do_send_changed_signal"]
|
||||
[connection signal="text_changed" from="GraphUI/SubGraphUI/Label" to="." method="_on_Label_text_changed"]
|
||||
[connection signal="toggled" from="GraphUI/SubGraphUI/ButtonTransmitsSeed" to="." method="_on_ButtonTransmitsSeed_toggled"]
|
||||
[connection signal="pressed" from="GraphUI/SubGraphUI/ButtonUp" to="." method="on_ButtonUp_pressed"]
|
||||
[connection signal="pressed" from="GraphUI/ButtonShowTree" to="." method="_on_ButtonShowTree_pressed"]
|
||||
|
@ -3,15 +3,19 @@ extends GraphNode
|
||||
class_name MMGraphNodeBase
|
||||
|
||||
var generator : MMGenBase = null setget set_generator
|
||||
var fixed_seed = false
|
||||
|
||||
func _ready() -> void:
|
||||
connect("offset_changed", self, "_on_offset_changed")
|
||||
|
||||
func _draw():
|
||||
if generator.has_randomness():
|
||||
var icon = preload("res://addons/material_maker/icons/randomness_unlocked.tres") if fixed_seed else preload("res://addons/material_maker/icons/randomness_locked.tres")
|
||||
if generator != null and generator.has_randomness():
|
||||
var icon = preload("res://addons/material_maker/icons/randomness_locked.tres") if generator.is_seed_locked() else preload("res://addons/material_maker/icons/randomness_unlocked.tres")
|
||||
draw_texture_rect(icon, Rect2(rect_size.x-48, 4, 16, 16), false)
|
||||
if !is_connected("gui_input", self, "_on_gui_input"):
|
||||
connect("gui_input", self, "_on_gui_input")
|
||||
else:
|
||||
if is_connected("gui_input", self, "_on_gui_input"):
|
||||
disconnect("gui_input", self, "_on_gui_input")
|
||||
|
||||
func set_generator(g) -> void:
|
||||
generator = g
|
||||
@ -21,5 +25,5 @@ func _on_offset_changed() -> void:
|
||||
|
||||
func _on_gui_input(event):
|
||||
if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT and Rect2(rect_size.x-48, 4, 16, 16).has_point(event.position):
|
||||
fixed_seed = !fixed_seed
|
||||
generator.toggle_lock_seed()
|
||||
update()
|
||||
|
Loading…
Reference in New Issue
Block a user