Prepared function generation for inputs

This commit is contained in:
RodZill4 2019-12-12 23:11:43 +01:00
parent 8282ab24fe
commit 2a51e3b726
2 changed files with 90 additions and 30 deletions

View File

@ -4,10 +4,19 @@ class_name MMGenContext
var variants : Dictionary = {}
var parent_context : MMGenContext = null
func _init(p = null) -> void:
parent_context = p
func has_variant(generator) -> bool:
return variants.has(generator)
return variants.has(generator) or parent_context != null and parent_context.has_variant(generator)
func touch_variant(generator) -> void:
if !variants.has(generator):
variants[generator] = []
if parent_context != null:
parent_context.touch_variant(generator)
func get_variant(generator, variant) -> int:
var rv = -1
@ -17,4 +26,5 @@ func get_variant(generator, variant) -> int:
variants[generator].push_back(variant)
else:
variants[generator] = [variant]
touch_variant(generator)
return rv

View File

@ -7,6 +7,13 @@ var uses_seed = false
var editable = false
const PORT_TYPES : Dictionary = {
rgba = { type="vec4" },
rgb = { type="vec3" },
f = { type="float" }
}
const GENERATE_FUNCTIONS : bool = false
func toggle_editable() -> bool:
editable = !editable
if editable:
@ -90,7 +97,19 @@ func find_keyword_call(string, keyword):
parenthesis_level -= 1
return ""
func replace_input(string, context, input, type, src, default) -> Dictionary:
func replace_input_with_function_call(string : String, input : String) -> String:
var genname = "o"+str(get_instance_id())
while true:
var uv = find_keyword_call(string, input)
if uv == null:
break
elif uv == "":
print("syntax error")
break
string = string.replace("$%s(%s)" % [ input, uv ], "%s_input_%s(%s)" % [ genname, input, uv ])
return string
func replace_input(string : String, context, input : String, type : String, src : OutputPort, default : String) -> Dictionary:
var required_globals = []
var required_defs = ""
var required_code = ""
@ -134,7 +153,7 @@ func replace_input(string, context, input, type, src, default) -> Dictionary:
func is_word_letter(l) -> bool:
return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1
func replace_variable(string, variable, value) -> String:
func replace_variable(string : String, variable : String, value : String) -> String:
string = string.replace("$(%s)" % variable, value)
var keyword_size = variable.length()+1
var new_string = ""
@ -152,7 +171,7 @@ func replace_variable(string, variable, value) -> String:
string = string.right(keyword_size)
return new_string
func subst(string, context, uv = "") -> Dictionary:
func subst(string : String, context : MMGenContext, uv : String = "") -> Dictionary:
var genname = "o"+str(get_instance_id())
var required_globals = []
var required_defs = ""
@ -199,30 +218,36 @@ func subst(string, context, uv = "") -> Dictionary:
for i in range(shader_model.inputs.size()):
var input = shader_model.inputs[i]
var source = get_source(i)
var result = replace_input(string, context, input.name, input.type, source, input.default)
while result is GDScriptFunctionState:
result = yield(result, "completed")
if string != result.string:
changed = true
if result.new_pass_required:
new_pass_required = true
string = result.string
# Add global definitions
for d in result.globals:
if required_globals.find(d) == -1:
required_globals.push_back(d)
# Add generated definitions
required_defs += result.defs
# Add generated code
required_code += result.code
for t in result.textures.keys():
required_textures[t] = result.textures[t]
if GENERATE_FUNCTIONS:
string = replace_input_with_function_call(string, input.name)
else:
var result = replace_input(string, context, input.name, input.type, source, input.default)
while result is GDScriptFunctionState:
result = yield(result, "completed")
if string != result.string:
changed = true
if result.new_pass_required:
new_pass_required = true
string = result.string
# Add global definitions
for d in result.globals:
if required_globals.find(d) == -1:
required_globals.push_back(d)
# Add generated definitions
required_defs += result.defs
# Add generated code
required_code += result.code
for t in result.textures.keys():
required_textures[t] = result.textures[t]
cont = changed and new_pass_required
return { string=string, globals=required_globals, defs=required_defs, code=required_code, textures=required_textures }
func create_input_function(function_name : String, input_index : int, context : MMGenContext) -> Dictionary:
var rv = { globals=[], defs="", code="", textures={} }
return rv
func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary:
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={} }
if shader_model != null and shader_model.has("outputs") and shader_model.outputs.size() > output_index:
var output = shader_model.outputs[output_index]
@ -231,8 +256,10 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
while subst_output is GDScriptFunctionState:
subst_output = yield(subst_output, "completed")
rv.defs += subst_output.string
# process textures
for t in subst_output.textures.keys():
rv.textures[t] = subst_output.textures[t]
# Generate functions for gradients
for p in shader_model.parameters:
if p.type == "gradient":
var g = parameters[p.name]
@ -240,6 +267,29 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
g = MMGradient.new()
g.deserialize(parameters[p.name])
rv.defs += g.get_shader(genname+"_p_"+p.name+"_gradient_fct")
# Generate functions for inputs
if shader_model.has("inputs"):
for i in range(shader_model.inputs.size()):
if GENERATE_FUNCTIONS:
var input = shader_model.inputs[i]
var source = get_source(i)
var string = "$%s(uv)" % input.name
var local_context = MMGenContext.new(context)
var result = replace_input(string, local_context, input.name, input.type, source, input.default)
while result is GDScriptFunctionState:
result = yield(result, "completed")
# Add global definitions
for d in result.globals:
if rv.globals.find(d) == -1:
rv.globals.push_back(d)
# Add generated definitions
rv.defs += result.defs
# Add textures
for t in result.textures.keys():
rv.textures[t] = result.textures[t]
rv.defs += "%s %s_input_%s(vec2 uv) {\n" % [ PORT_TYPES[input.type].type, genname, input.name ]
rv.defs += "%s\n" % result.code
rv.defs += "return %s;\n}\n" % result.string
# Add inline code
if shader_model.has("code"):
var variant_index = context.get_variant(self, uv)
@ -262,9 +312,9 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
var variant_index = context.get_variant(self, variant_string)
if variant_index == -1:
variant_index = context.get_variant(self, variant_string)
for t in output_info:
if output.has(t.field):
var subst_output = subst(output[t.field], context, uv)
for f in PORT_TYPES.keys():
if output.has(f):
var subst_output = subst(output[f], context, uv)
while subst_output is GDScriptFunctionState:
subst_output = yield(subst_output, "completed")
# Add global definitions
@ -275,12 +325,12 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -
rv.defs += subst_output.defs
# Add generated code
rv.code += subst_output.code
rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, genname, output_index, variant_index, t.field, subst_output.string ]
rv.code += "%s %s_%d_%d_%s = %s;\n" % [ PORT_TYPES[f].type, genname, output_index, variant_index, f, subst_output.string ]
for t in subst_output.textures.keys():
rv.textures[t] = subst_output.textures[t]
for t in output_info:
if output.has(t.field):
rv[t.field] = "%s_%d_%d_%s" % [ genname, output_index, variant_index, t.field ]
for f in PORT_TYPES.keys():
if output.has(f):
rv[f] = "%s_%d_%d_%s" % [ genname, output_index, variant_index, f ]
if shader_model.has("global") && rv.globals.find(shader_model.global) == -1:
rv.globals.push_back(shader_model.global)
return rv