mirror of
https://github.com/Relintai/material-maker.git
synced 2024-11-13 06:27:18 +01:00
c121f7c00a
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).
185 lines
6.8 KiB
GDScript
185 lines
6.8 KiB
GDScript
tool
|
|
extends MMGenBase
|
|
class_name MMGenConvolution
|
|
|
|
var convolution_params : Dictionary = {}
|
|
|
|
func get_type() -> String:
|
|
return "convolution"
|
|
|
|
func get_type_name() -> String:
|
|
if convolution_params.has("name"):
|
|
return convolution_params.name
|
|
return .get_type_name()
|
|
|
|
func get_parameter_defs() -> Array:
|
|
var rv : Array = [ { name="size", type="size", first=4, last=11, default=7 } ]
|
|
if convolution_params.has("parameters"):
|
|
for p in convolution_params.parameters:
|
|
rv.push_back(p)
|
|
return rv
|
|
|
|
func get_input_defs() -> Array:
|
|
return [ { name="in", type=convolution_params.input_type } ]
|
|
|
|
func get_output_defs() -> Array:
|
|
return [ { type=convolution_params.output_type } ]
|
|
|
|
func set_convolution_params(data: Dictionary) -> void:
|
|
convolution_params = data
|
|
|
|
func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary:
|
|
var genname = "o"+str(get_instance_id())
|
|
var epsilon = 1.0/pow(2, parameters.size)
|
|
var types = { "rgba": { type="vec4", init="vec4(0.0)" }, "rgb": { type="vec3", init="vec3(0.0)" }, "f": { type="float", init="0.0" } }
|
|
var rv = { globals=[], defs="", code="", textures={} }
|
|
var source = get_source(0)
|
|
if source == null:
|
|
return rv
|
|
var variant_index = context.get_variant(self, uv)
|
|
if variant_index == -1:
|
|
variant_index = context.get_variant(self, uv)
|
|
# Calculate matrix
|
|
var errors = 0
|
|
var sum = [ 0.0, 0.0, 0.0, 0.0 ]
|
|
var matrix = []
|
|
var expr : Expression = null
|
|
var expr_variables : PoolStringArray
|
|
var expr_values : Array
|
|
var expr_variables_x_index : int
|
|
if convolution_params.has("matrix_function"):
|
|
expr = Expression.new()
|
|
expr_variables = PoolStringArray(["size"])
|
|
expr_values = [ pow(2, parameters.size) ]
|
|
if convolution_params.has("parameters"):
|
|
for p in convolution_params.parameters:
|
|
expr_variables.push_back(p.name)
|
|
if parameters.has(p.name):
|
|
expr_values.push_back(parameters[p.name])
|
|
elif p.has("default"):
|
|
expr_values.push_back(p.default)
|
|
else:
|
|
expr_values.push_back(0)
|
|
errors += 1
|
|
print("No value for "+p.name)
|
|
expr_variables_x_index = expr_values.size()
|
|
expr_variables.push_back("x")
|
|
expr_values.push_back(0)
|
|
expr_variables.push_back("y")
|
|
expr_values.push_back(0)
|
|
var error = expr.parse(convolution_params.matrix_function, expr_variables)
|
|
if error != OK:
|
|
print("Error in expression: "+expr.get_error_text())
|
|
return rv
|
|
for dy in range(-convolution_params.y, convolution_params.y+1):
|
|
var line = []
|
|
for dx in range(-convolution_params.x, convolution_params.x+1):
|
|
var coef = 0.0
|
|
if convolution_params.has("matrix") and dy+convolution_params.y < convolution_params.matrix.size() and dx+convolution_params.x < convolution_params.matrix[dy+convolution_params.y].size() and convolution_params.matrix[dy+convolution_params.y][dx+convolution_params.x] != null:
|
|
coef = convolution_params.matrix[dy+convolution_params.y][dx+convolution_params.x]
|
|
elif convolution_params.has("matrix_sparse") and convolution_params.matrix_sparse.has(str(dy)) and convolution_params.matrix_sparse[str(dy)].has(str(dx)):
|
|
coef = convolution_params.matrix_sparse[str(dy)][str(dx)]
|
|
elif expr != null:
|
|
expr_values[expr_variables_x_index] = dx
|
|
expr_values[expr_variables_x_index+1] = dy
|
|
coef = expr.execute(expr_values)
|
|
if typeof(coef) == TYPE_INT:
|
|
coef = float(coef)
|
|
match convolution_params.output_type:
|
|
"f":
|
|
if typeof(coef) == TYPE_REAL or convolution_params.input_type == "f":
|
|
sum[0] += coef
|
|
else:
|
|
errors += 1
|
|
"rgb":
|
|
if typeof(coef) == TYPE_REAL:
|
|
sum[0] += coef
|
|
sum[1] += coef
|
|
sum[2] += coef
|
|
coef = [ coef, coef, coef ]
|
|
if convolution_params.input_type != "f" and convolution_params.input_type != "rgb":
|
|
errors += 1
|
|
elif typeof(coef) == TYPE_ARRAY and coef.size() == 3:
|
|
if convolution_params.input_type == "f" or convolution_params.input_type == "rgb":
|
|
sum[0] += coef[0]
|
|
sum[1] += coef[1]
|
|
sum[2] += coef[2]
|
|
else:
|
|
errors += 1
|
|
else:
|
|
errors += 1
|
|
"rgba":
|
|
if typeof(coef) == TYPE_REAL:
|
|
sum[0] += coef
|
|
sum[1] += coef
|
|
sum[2] += coef
|
|
sum[3] += coef
|
|
coef = [ coef, coef, coef, coef ]
|
|
if convolution_params.input_type != "f" and convolution_params.input_type != "rgba":
|
|
errors += 1
|
|
elif typeof(coef) == TYPE_ARRAY and coef.size() == 4:
|
|
if convolution_params.input_type == "f" or convolution_params.input_type == "rgba":
|
|
sum[0] += coef[0]
|
|
sum[1] += coef[1]
|
|
sum[2] += coef[2]
|
|
sum[3] += coef[3]
|
|
else:
|
|
errors += 1
|
|
else:
|
|
errors += 1
|
|
line.push_back(coef)
|
|
matrix.push_back(line)
|
|
# Generate code
|
|
rv.code += "%s %s_%d = %s;\n" % [ types[convolution_params.output_type].type, genname, variant_index, types[convolution_params.output_type].init ]
|
|
if errors > 0:
|
|
pass
|
|
else:
|
|
if convolution_params.has("normalized") and convolution_params.normalized:
|
|
for i in range(sum.size()):
|
|
if sum[i] != 0:
|
|
sum[i] = 1.0/sum[i]
|
|
else:
|
|
sum[i] = 1.0
|
|
else:
|
|
sum = [ 1.0, 1.0, 1.0, 1.0 ]
|
|
for dy in range(-convolution_params.y, convolution_params.y+1):
|
|
var line = matrix[dy+convolution_params.y]
|
|
for dx in range(-convolution_params.x, convolution_params.x+1):
|
|
var coef = line[dx+convolution_params.x]
|
|
var uv_str = "(%s)+vec2(%.9f,%.9f)" % [ uv, dx*epsilon, dy*epsilon ]
|
|
var src_code = source.generator.get_shader_code(uv_str, source.output_index, context)
|
|
while src_code is GDScriptFunctionState:
|
|
src_code = yield(src_code, "completed")
|
|
# Add global definitions
|
|
if src_code.has("globals"):
|
|
for d in src_code.globals:
|
|
if rv.globals.find(d) == -1:
|
|
rv.globals.push_back(d)
|
|
# Add generated definitions
|
|
if src_code.has("defs"):
|
|
rv.defs += src_code.defs
|
|
# Add generated code
|
|
if src_code.has("code"):
|
|
rv.code += src_code.code
|
|
var coef_str : String
|
|
match convolution_params.output_type:
|
|
"f":
|
|
coef_str = "%.9f" % [ coef * sum[0] ]
|
|
"rgb":
|
|
coef_str = "vec3(%.9f, %.9f, %.9f)" % [ coef[0] * sum[0], coef[1] * sum[1], coef[2] * sum[2] ]
|
|
"rgba":
|
|
coef_str = "vec4(%.9f, %.9f, %.9f, %.9f)" % [ coef[0] * sum[0], coef[1] * sum[1], coef[2] * sum[2], coef[3] * sum[3] ]
|
|
rv.code += "%s_%d += %s*%s;\n" % [ genname, variant_index, coef_str, src_code[convolution_params.input_type] ]
|
|
for t in src_code.textures.keys():
|
|
rv.textures[t] = src_code.textures[t]
|
|
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)
|