mirror of
https://github.com/Relintai/material-maker.git
synced 2024-11-13 06:27:18 +01:00
Implemented save and shader generator editing...
This commit is contained in:
parent
0bcdbb2204
commit
27d5ddbe97
@ -18,6 +18,7 @@ class OutputPort:
|
||||
return generator.name+"("+str(output_index)+")"
|
||||
|
||||
var position : Vector2 = Vector2(0, 0)
|
||||
var model = null
|
||||
var parameters = {}
|
||||
|
||||
func _ready():
|
||||
@ -112,3 +113,18 @@ func get_shader_code(uv : String, output_index : int, context : MMGenContext):
|
||||
|
||||
func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
|
||||
return null
|
||||
|
||||
func _serialize(data):
|
||||
print("cannot save "+name)
|
||||
return data
|
||||
|
||||
func serialize():
|
||||
var rv = { name=name, parameters={}, node_position={ x=position.x, y=position.y } }
|
||||
for p in parameters.keys():
|
||||
rv.parameters[p] = MMType.serialize_value(parameters[p])
|
||||
if model != null:
|
||||
rv.type = model
|
||||
else:
|
||||
rv = _serialize(rv)
|
||||
|
||||
return rv
|
@ -38,3 +38,7 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
|
||||
while rv is GDScriptFunctionState:
|
||||
rv = yield(rv, "completed")
|
||||
return rv
|
||||
|
||||
func _serialize(data):
|
||||
data.type = "buffer"
|
||||
return data
|
||||
|
@ -21,6 +21,14 @@ func remove_generator(generator : MMGenBase):
|
||||
if c.from != generator.name and c.to != generator.name:
|
||||
new_connections.append(c)
|
||||
connections = new_connections
|
||||
generator.queue_free()
|
||||
|
||||
func replace_generator(old : MMGenBase, new : MMGenBase):
|
||||
new.name = old.name
|
||||
new.position = old.position
|
||||
remove_child(old)
|
||||
old.free()
|
||||
add_child(new)
|
||||
|
||||
func connect_children(from, from_port : int, to, to_port : int):
|
||||
# disconnect target
|
||||
@ -47,4 +55,11 @@ func disconnect_children(from, from_port : int, to, to_port : int):
|
||||
if remove == -1:
|
||||
break
|
||||
connections.remove(remove)
|
||||
return true
|
||||
return true
|
||||
|
||||
func _serialize(data):
|
||||
data.nodes = []
|
||||
for c in get_children():
|
||||
data.nodes.append(c.serialize())
|
||||
data.connections = connections
|
||||
return data
|
||||
|
@ -129,3 +129,7 @@ func export_textures(prefix, size = null):
|
||||
update_spatial_material(new_material, prefix)
|
||||
ResourceSaver.save("%s.tres" % [ prefix ], new_material)
|
||||
resource_filesystem.scan()
|
||||
|
||||
func _serialize(data):
|
||||
data.type = "material"
|
||||
return data
|
||||
|
@ -120,7 +120,7 @@ func subst(string, context, uv = ""):
|
||||
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"
|
||||
value_string = name+"__"+p.name+"_gradient_fct"
|
||||
if value_string != null:
|
||||
string = replace_variable(string, p.name, value_string)
|
||||
if shader_model.has("inputs") and typeof(shader_model.inputs) == TYPE_ARRAY:
|
||||
@ -157,7 +157,7 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
|
||||
if !(g is MMGradient):
|
||||
g = MMGradient.new()
|
||||
g.deserialize(parameters[p.name])
|
||||
rv.defs += g.get_shader(p.name+"_gradient_fct")
|
||||
rv.defs += g.get_shader(name+"__"+p.name+"_gradient_fct")
|
||||
var variant_index = context.get_variant(self, variant_string)
|
||||
if variant_index == -1:
|
||||
variant_index = context.get_variant(self, variant_string)
|
||||
@ -181,3 +181,7 @@ func get_globals():
|
||||
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
|
||||
|
||||
func _serialize(data):
|
||||
data.shader_model = shader_model
|
||||
return data
|
||||
|
@ -2,14 +2,14 @@ tool
|
||||
extends Object
|
||||
class_name MMGenLoader
|
||||
|
||||
func load_gen(filename: String) -> MMGenBase:
|
||||
static func load_gen(filename: String) -> MMGenBase:
|
||||
var file = File.new()
|
||||
if file.open(filename, File.READ) == OK:
|
||||
var data = parse_json(file.get_as_text())
|
||||
return create_gen(data)
|
||||
return null
|
||||
|
||||
func add_to_gen_graph(gen_graph, generators, connections):
|
||||
static func add_to_gen_graph(gen_graph, generators, connections):
|
||||
var rv = { generators=[], connections=[] }
|
||||
for n in generators:
|
||||
var g = create_gen(n)
|
||||
@ -27,7 +27,7 @@ func add_to_gen_graph(gen_graph, generators, connections):
|
||||
rv.connections.append(c)
|
||||
return rv
|
||||
|
||||
func create_gen(data) -> MMGenBase:
|
||||
static func create_gen(data) -> MMGenBase:
|
||||
var generator = null
|
||||
if data.has("connections") and data.has("nodes"):
|
||||
generator = MMGenGraph.new()
|
||||
@ -35,6 +35,9 @@ func create_gen(data) -> MMGenBase:
|
||||
elif data.has("shader_model"):
|
||||
generator = MMGenShader.new()
|
||||
generator.set_shader_model(data.shader_model)
|
||||
elif data.has("model_data"):
|
||||
generator = MMGenShader.new()
|
||||
generator.set_shader_model(data.model_data)
|
||||
elif data.has("type"):
|
||||
if data.type == "material":
|
||||
generator = MMGenMaterial.new()
|
||||
@ -44,13 +47,13 @@ func create_gen(data) -> MMGenBase:
|
||||
generator = MMGenImage.new()
|
||||
else:
|
||||
var file = File.new()
|
||||
if file.open("res://addons/material_maker/library/"+data.type+".mml", File.READ) == OK:
|
||||
print("loaded description "+data.type+".mml")
|
||||
if file.open("res://addons/material_maker/nodes/"+data.type+".mmg", File.READ) == OK:
|
||||
generator = create_gen(parse_json(file.get_as_text()))
|
||||
generator.model = data.type
|
||||
file.close()
|
||||
elif file.open("res://addons/material_maker/nodes/"+data.type+".mmn", File.READ) == OK:
|
||||
generator = MMGenShader.new()
|
||||
print("loaded description "+data.type+".mmn")
|
||||
generator.model = data.type
|
||||
generator.set_shader_model(parse_json(file.get_as_text()))
|
||||
file.close()
|
||||
else:
|
||||
@ -58,7 +61,7 @@ func create_gen(data) -> MMGenBase:
|
||||
if generator != null:
|
||||
generator.name = data.type
|
||||
else:
|
||||
print(data)
|
||||
print("LOADER: data not supported:"+str(data))
|
||||
if generator != null:
|
||||
if data.has("name"):
|
||||
generator.name = data.name
|
||||
@ -67,5 +70,5 @@ func create_gen(data) -> MMGenBase:
|
||||
generator.position.y = data.node_position.y
|
||||
if data.has("parameters"):
|
||||
for p in data.parameters.keys():
|
||||
generator.parameters[p] = data.parameters[p]
|
||||
generator.parameters[p] = MMType.deserialize_value(data.parameters[p])
|
||||
return generator
|
||||
|
@ -134,16 +134,14 @@ func create_nodes(data, position : Vector2 = Vector2(0, 0)):
|
||||
if data.has("type"):
|
||||
data = { nodes=[data], connections=[] }
|
||||
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)
|
||||
var new_stuff = MMGenLoader.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):
|
||||
clear_material()
|
||||
var loader = MMGenLoader.new()
|
||||
generator = loader.load_gen(filename)
|
||||
generator = MMGenLoader.load_gen(filename)
|
||||
if generator != null:
|
||||
add_child(generator)
|
||||
update_graph(generator.get_children(), generator.connections)
|
||||
@ -152,11 +150,7 @@ func load_file(filename):
|
||||
center_view()
|
||||
|
||||
func save_file(filename):
|
||||
var data = { nodes = [] }
|
||||
for c in get_children():
|
||||
if c is GraphNode:
|
||||
data.nodes.append(c.serialize())
|
||||
data.connections = get_connection_list()
|
||||
var data = generator.serialize()
|
||||
var file = File.new()
|
||||
if file.open(filename, File.WRITE) == OK:
|
||||
file.store_string(to_json(data))
|
||||
@ -191,7 +185,7 @@ func serialize_selection():
|
||||
center += n.offset+0.5*n.rect_size
|
||||
center /= nodes.size()
|
||||
for n in nodes:
|
||||
var s = n.serialize()
|
||||
var s = n.generator.serialize()
|
||||
var p = n.offset-center
|
||||
s.node_position = { x=p.x, y=p.y }
|
||||
data.nodes.append(s)
|
||||
|
@ -254,7 +254,8 @@
|
||||
},
|
||||
{
|
||||
"tree_item":"Miscellaneous/Custom",
|
||||
"type":"custom"
|
||||
"type":"custom",
|
||||
"shader_model":{}
|
||||
},
|
||||
{
|
||||
"tree_item":"Miscellaneous/Remote",
|
||||
|
@ -25,6 +25,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="make_selected_nodes_editable", 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" },
|
||||
{ menu="Help", command="show_doc", description="User manual" },
|
||||
@ -233,19 +234,33 @@ func edit_paste_is_disabled():
|
||||
var data = parse_json(OS.clipboard)
|
||||
return data == null
|
||||
|
||||
func add_to_user_library():
|
||||
func get_selected_nodes():
|
||||
var graph_edit = $VBoxContainer/HBoxContainer/Projects.get_current_tab_control()
|
||||
if graph_edit != null and graph_edit is GraphEdit:
|
||||
var selected_nodes = []
|
||||
for n in graph_edit.get_children():
|
||||
if n is GraphNode and n.selected:
|
||||
selected_nodes.append(n)
|
||||
if !selected_nodes.empty():
|
||||
var dialog = preload("res://addons/material_maker/widgets/line_dialog.tscn").instance()
|
||||
dialog.set_texts("New library element", "Select a name for the new library element")
|
||||
add_child(dialog)
|
||||
dialog.connect("ok", self, "do_add_to_user_library", [ selected_nodes ])
|
||||
dialog.popup_centered()
|
||||
return selected_nodes
|
||||
else:
|
||||
return []
|
||||
|
||||
func make_selected_nodes_editable():
|
||||
var selected_nodes = get_selected_nodes()
|
||||
if !selected_nodes.empty():
|
||||
for n in selected_nodes:
|
||||
print(n.name)
|
||||
n.generator.model = null
|
||||
n.update_node()
|
||||
|
||||
func add_to_user_library():
|
||||
var selected_nodes = get_selected_nodes()
|
||||
if !selected_nodes.empty():
|
||||
var dialog = preload("res://addons/material_maker/widgets/line_dialog.tscn").instance()
|
||||
dialog.set_texts("New library element", "Select a name for the new library element")
|
||||
add_child(dialog)
|
||||
dialog.connect("ok", self, "do_add_to_user_library", [ selected_nodes ])
|
||||
dialog.popup_centered()
|
||||
|
||||
func do_add_to_user_library(name, nodes):
|
||||
var data
|
||||
|
1
addons/material_maker/nodes/combine.mmg
Normal file
1
addons/material_maker/nodes/combine.mmg
Normal file
@ -0,0 +1 @@
|
||||
{"name":"uniform","node_position":{"x":-130,"y":-66},"parameters":{"color":{"a":1,"b":1,"g":1,"r":1,"type":"Color"},"name":0},"shader_model":{"global":"","inputs":[{"default":"0.0","label":"R","name":"r","type":"f"},{"default":"0.0","label":"G","name":"g","type":"f"},{"default":"0.0","label":"B","name":"b","type":"f"},{"default":"1.0","label":"A","name":"a","type":"f"}],"instance":"","name":"Combine","outputs":[{"rgba":"vec4($r($uv), $g($uv), $b($uv), $a($uv))"}],"parameters":[]}}
|
6
addons/material_maker/nodes/edit_buttons.gd
Normal file
6
addons/material_maker/nodes/edit_buttons.gd
Normal file
@ -0,0 +1,6 @@
|
||||
extends HBoxContainer
|
||||
|
||||
func connect_buttons(object, edit_fct, load_fct, save_fct):
|
||||
$Edit.connect("pressed", object, edit_fct)
|
||||
$Load.connect("pressed", object, load_fct)
|
||||
$Save.connect("pressed", object, save_fct)
|
31
addons/material_maker/nodes/edit_buttons.tscn
Normal file
31
addons/material_maker/nodes/edit_buttons.tscn
Normal file
@ -0,0 +1,31 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://addons/material_maker/nodes/edit_buttons.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/material_maker/icons/edit.png" type="Texture" id=2]
|
||||
[ext_resource path="res://addons/material_maker/icons/load.png" type="Texture" id=3]
|
||||
[ext_resource path="res://addons/material_maker/icons/save.png" type="Texture" id=4]
|
||||
|
||||
[node name="NodeEditButtons" type="HBoxContainer"]
|
||||
margin_right = 91.0
|
||||
margin_bottom = 22.0
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Edit" type="Button" parent="."]
|
||||
margin_right = 27.0
|
||||
margin_bottom = 22.0
|
||||
icon = ExtResource( 2 )
|
||||
flat = true
|
||||
|
||||
[node name="Load" type="Button" parent="."]
|
||||
margin_left = 31.0
|
||||
margin_right = 59.0
|
||||
margin_bottom = 22.0
|
||||
icon = ExtResource( 3 )
|
||||
flat = true
|
||||
|
||||
[node name="Save" type="Button" parent="."]
|
||||
margin_left = 63.0
|
||||
margin_right = 91.0
|
||||
margin_bottom = 22.0
|
||||
icon = ExtResource( 4 )
|
||||
flat = true
|
@ -12,6 +12,13 @@ func set_generator(g):
|
||||
generator = g
|
||||
update_node()
|
||||
|
||||
func on_close_request():
|
||||
print("close")
|
||||
generator.get_parent().remove_generator(generator)
|
||||
|
||||
func on_offset_changed():
|
||||
generator.position = offset
|
||||
|
||||
func initialize_properties():
|
||||
for o in controls:
|
||||
if o == null:
|
||||
@ -73,6 +80,7 @@ func update_node():
|
||||
c.queue_free()
|
||||
else:
|
||||
custom_node_buttons = c
|
||||
rect_size = Vector2(0, 0)
|
||||
# Rebuild node
|
||||
title = generator.get_type_name()
|
||||
# Parameters
|
||||
@ -133,7 +141,6 @@ func update_node():
|
||||
var inputs = generator.get_input_defs()
|
||||
for i in range(inputs.size()):
|
||||
var input = inputs[i]
|
||||
print(input)
|
||||
var enable_left = false
|
||||
var color_left = Color(0.5, 0.5, 0.5)
|
||||
if typeof(input) == TYPE_DICTIONARY:
|
||||
@ -146,11 +153,14 @@ func update_node():
|
||||
else:
|
||||
enable_left = true
|
||||
set_slot(i, enable_left, 0, color_left, false, 0, Color())
|
||||
if i >= get_child_count():
|
||||
var control = Control.new()
|
||||
control.rect_min_size = Vector2(0, 16)
|
||||
add_child(control)
|
||||
# Outputs
|
||||
var outputs = generator.get_output_defs()
|
||||
for i in range(outputs.size()):
|
||||
var output = outputs[i]
|
||||
print(output)
|
||||
var enable_right = false
|
||||
var color_right = Color(0.5, 0.5, 0.5)
|
||||
if typeof(output) == TYPE_DICTIONARY:
|
||||
@ -163,5 +173,69 @@ func update_node():
|
||||
elif output.has("f"):
|
||||
enable_right = true
|
||||
set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right)
|
||||
if custom_node_buttons != null:
|
||||
move_child(custom_node_buttons, get_child_count()-1)
|
||||
if i >= get_child_count():
|
||||
var control = Control.new()
|
||||
control.rect_min_size = Vector2(0, 16)
|
||||
add_child(control)
|
||||
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")
|
||||
|
||||
func edit_generator():
|
||||
var edit_window = load("res://addons/material_maker/widgets/node_editor/node_editor.tscn").instance()
|
||||
get_parent().add_child(edit_window)
|
||||
if generator.shader_model != null:
|
||||
edit_window.set_model_data(generator.shader_model)
|
||||
edit_window.connect("node_changed", self, "update_generator")
|
||||
edit_window.popup_centered()
|
||||
|
||||
func update_generator(shader_model):
|
||||
generator.shader_model = shader_model
|
||||
update_node()
|
||||
|
||||
func load_generator():
|
||||
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("*.mmg,*.mmn;Material Maker Generator")
|
||||
dialog.connect("file_selected", self, "do_load_generator")
|
||||
dialog.popup_centered()
|
||||
|
||||
func do_load_generator(file_name : String):
|
||||
print(file_name)
|
||||
var new_generator = null
|
||||
if file_name.ends_with(".mmn"):
|
||||
var file = File.new()
|
||||
if file.open(file_name, File.READ) == OK:
|
||||
new_generator = MMGenShader.new()
|
||||
new_generator.set_shader_model(parse_json(file.get_as_text()))
|
||||
file.close()
|
||||
else:
|
||||
new_generator = MMGenLoader.load_gen(file_name)
|
||||
if new_generator != null:
|
||||
var parent_generator = generator.get_parent()
|
||||
print("before: "+generator.name)
|
||||
parent_generator.replace_generator(generator, new_generator)
|
||||
generator = new_generator
|
||||
print("after: "+generator.name)
|
||||
update_node()
|
||||
|
||||
func save_generator():
|
||||
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("*.mmg;Material Maker Generator")
|
||||
dialog.connect("file_selected", self, "do_save_generator")
|
||||
dialog.popup_centered()
|
||||
|
||||
func do_save_generator(file_name : String):
|
||||
var data = generator.serialize()
|
||||
var file = File.new()
|
||||
if file.open(file_name, File.WRITE) == OK:
|
||||
file.store_string(to_json(data))
|
||||
file.close()
|
||||
|
@ -3,8 +3,10 @@
|
||||
[ext_resource path="res://addons/material_maker/nodes/generic.gd" type="Script" id=1]
|
||||
|
||||
[node name="Generic" type="GraphNode"]
|
||||
margin_right = 82.0
|
||||
margin_right = 95.0
|
||||
margin_bottom = 29.0
|
||||
title = "Generic"
|
||||
show_close = true
|
||||
script = ExtResource( 1 )
|
||||
[connection signal="close_request" from="." to="." method="on_close_request"]
|
||||
[connection signal="offset_changed" from="." to="." method="on_offset_changed"]
|
||||
|
@ -47,8 +47,7 @@ func close_material_maker():
|
||||
material_maker = null
|
||||
|
||||
func generate_material(ptex_filename: String) -> Material:
|
||||
var loader = MMGenLoader.new()
|
||||
var generator = loader.load_gen(ptex_filename)
|
||||
var generator = MMGenLoader.load_gen(ptex_filename)
|
||||
add_child(generator)
|
||||
var material = generator.get_node("Material")
|
||||
var return_value = material.generate_material(renderer)
|
||||
|
@ -36,7 +36,7 @@ func sort():
|
||||
|
||||
func get_color(x):
|
||||
sort()
|
||||
if points.size() >0:
|
||||
if points.size() > 0:
|
||||
if x < points[0].v:
|
||||
return points[0].c
|
||||
var s = points.size()-1
|
||||
@ -96,3 +96,7 @@ func deserialize(v):
|
||||
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))
|
||||
elif typeof(v) == TYPE_OBJECT and v.get_script() == get_script():
|
||||
clear()
|
||||
for p in v.points:
|
||||
add_point(p.v, p.c)
|
||||
|
@ -5,8 +5,8 @@ const Gradient = preload("res://addons/material_maker/types/gradient.gd")
|
||||
|
||||
static func serialize_value(value):
|
||||
if typeof(value) == TYPE_COLOR:
|
||||
return { type= "Color", r=value.r, g=value.g, b=value.b, a=value.a }
|
||||
elif typeof(value) == TYPE_OBJECT && value.has_method("serialize"):
|
||||
return { type="Color", r=value.r, g=value.g, b=value.b, a=value.a }
|
||||
elif typeof(value) == TYPE_OBJECT and value.has_method("serialize"):
|
||||
return value.serialize()
|
||||
return value
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user