material-maker/addons/material_maker/engine/gen_convolution.gd
RodZill4 c121f7c00a 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).
2019-11-04 07:58:17 +01:00

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)