material-maker/addons/material_maker/nodes/node_generic.gd

188 lines
6.0 KiB
GDScript

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):
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 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()
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("outputs") and typeof(model_data.outputs) == TYPE_ARRAY:
for i in 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, false, 0, color_right, enable_right, 0, color_right)
else:
model_data.outputs = []
if custom_node_buttons != null:
move_child(custom_node_buttons, get_child_count()-1)
func subst(string, uv = ""):
string = string.replace("$(name)", name)
string = string.replace("$(seed)", str(get_seed()))
string = string.replace("$(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 ]
if value_string != null:
string = string.replace("$(%s)" % p.name, value_string)
return string
func _get_shader_code(uv, slot = 0):
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]
if model_data.has("instance") && generated_variants.empty():
rv.defs = subst(model_data.instance)
var variant_index = generated_variants.find(variant_string)
if variant_index == -1:
variant_index = generated_variants.size()
generated_variants.append(variant_string)
if output.has("rgba"):
rv.code += "vec4 %s_%d_%d_rgba = %s;\n" % [ name, slot, variant_index, subst(output.rgba, uv) ]
if output.has("rgb"):
rv.code += "vec3 %s_%d_%d_rgb = %s;\n" % [ name, slot, variant_index, subst(output.rgb, uv) ]
if output.has("f"):
rv.code += "float %s_%d_%d_f = %s;\n" % [ name, slot, variant_index, subst(output.f, uv) ]
if output.has("rgba"):
rv.rgba = "%s_%d_%d_rgba" % [ name, slot, variant_index ]
if output.has("rgb"):
rv.rgb = "%s_%d_%d_rgb" % [ name, slot, variant_index ]
if output.has("f"):
rv.f = "%s_%d_%d_f" % [ name, slot, variant_index ]
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