More refactoring and added buffer generator

This commit is contained in:
Rodolphe Suescun 2019-08-18 16:28:50 +02:00
parent e9a21454c1
commit d8d9aaa9b4
7 changed files with 105 additions and 56 deletions

View File

@ -9,16 +9,7 @@ class OutputPort:
func _init(g : MMGenBase, o : int): func _init(g : MMGenBase, o : int):
generator = g generator = g
output_index = o output_index = o
"""
func get_shader():
return generator.get_shader(output_index)
func get_shader_code(uv):
return generator.get_shader_code(uv, output_index)
func get_globals():
return generator.get_globals()
"""
func to_str(): func to_str():
return generator.name+"("+str(output_index)+")" return generator.name+"("+str(output_index)+")"
@ -81,16 +72,20 @@ func get_globals():
func render(output_index : int, renderer : MMGenRenderer, size : int): func render(output_index : int, renderer : MMGenRenderer, size : int):
var context : MMGenContext = MMGenContext.new(renderer) var context : MMGenContext = MMGenContext.new(renderer)
var source = get_shader_code("UV", output_index, context) var source = get_shader_code("UV", output_index, context)
while source is GDScriptFunctionState:
source = yield(source, "completed")
if source == null: if source == null:
return false return false
var shader : String = renderer.generate_shader(source) var shader : String = renderer.generate_shader(source)
var status = renderer.render_shader(shader, {}, 1024) var status = renderer.render_shader(shader, source.textures, size)
while status is GDScriptFunctionState: while status is GDScriptFunctionState:
status = yield(status, "completed") status = yield(status, "completed")
return status return status
func get_shader_code(uv : String, output_index : int, context : MMGenContext): func get_shader_code(uv : String, output_index : int, context : MMGenContext):
var rv = _get_shader_code(uv, output_index, context) var rv = _get_shader_code(uv, output_index, context)
while rv is GDScriptFunctionState:
rv = yield(rv, "completed")
if rv != null: if rv != null:
if !rv.has("f"): if !rv.has("f"):
if rv.has("rgb"): if rv.has("rgb"):

View File

@ -2,6 +2,8 @@ tool
extends MMGenBase extends MMGenBase
class_name MMGenBuffer class_name MMGenBuffer
var texture : ImageTexture = ImageTexture.new()
func _ready(): func _ready():
if !parameters.has("size"): if !parameters.has("size"):
parameters.size = 4 parameters.size = 4
@ -16,7 +18,28 @@ func get_parameter_defs():
return [ { name="size", type="size", first=4, last=11, default=4 } ] return [ { name="size", type="size", first=4, last=11, default=4 } ]
func get_input_defs(): func get_input_defs():
return [ ] return [ { name="in", type="rgba" } ]
func get_output_defs(): func get_output_defs():
return [ ] return [ { rgba="" } ]
func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
var source = get_source(0)
if source != null:
print(parameters.size)
var status = source.generator.render(source.output_index, context.renderer, pow(2, 4+parameters.size))
while status is GDScriptFunctionState:
status = yield(status, "completed")
if status:
var image : Image = context.renderer.get_texture().get_data()
texture.create_from_image(image)
texture.flags = 0
var rv = { defs="" }
var variant_index = context.get_variant(self, uv)
if variant_index == -1:
variant_index = context.get_variant(self, uv)
var texture_name = name+"_tex"
rv.code = "vec4 %s_%d = texture(%s, %s);\n" % [ name, variant_index, texture_name, uv ]
rv.rgba = "%s_%d" % [ name, variant_index ]
rv.textures = { texture_name:texture }
return rv

View File

@ -39,8 +39,7 @@ func _ready():
func generate_material(renderer : MMGenRenderer): func generate_material(renderer : MMGenRenderer):
var source = get_source(0) var source = get_source(0)
if source != null: if source != null:
var shader : String = renderer.generate_shader(source) var status = source.generator.render(source.output_index, renderer, 512)
var status = renderer.render_shader(shader, {}, 512)
while status is GDScriptFunctionState: while status is GDScriptFunctionState:
status = yield(status, "completed") status = yield(status, "completed")
print("Render status: "+str(status)) print("Render status: "+str(status))

View File

@ -3,7 +3,6 @@ extends MMGenBase
class_name MMGenShader class_name MMGenShader
var shader_model : Dictionary = {} var shader_model : Dictionary = {}
var generated_variants = []
func get_type(): func get_type():
return "shader" return "shader"
@ -19,6 +18,18 @@ func get_parameter_defs():
else: else:
return shader_model.parameters return shader_model.parameters
func get_input_defs():
if shader_model == null or !shader_model.has("inputs"):
return []
else:
return shader_model.inputs
func get_output_defs():
if shader_model == null or !shader_model.has("outputs"):
return []
else:
return shader_model.outputs
func set_shader_model(data: Dictionary): func set_shader_model(data: Dictionary):
shader_model = data shader_model = data
init_parameters() init_parameters()
@ -43,6 +54,7 @@ func find_keyword_call(string, keyword):
func replace_input(string, context, input, type, src, default): func replace_input(string, context, input, type, src, default):
var required_defs = "" var required_defs = ""
var required_code = "" var required_code = ""
var required_textures = {}
while true: while true:
var uv = find_keyword_call(string, input) var uv = find_keyword_call(string, input)
if uv == null: if uv == null:
@ -52,15 +64,17 @@ func replace_input(string, context, input, type, src, default):
break break
var src_code var src_code
if src == null: if src == null:
src_code = subst(default, "(%s)" % uv) src_code = subst(default, context, "(%s)" % uv)
else: else:
print(src.to_str())
src_code = src.generator.get_shader_code(uv, src.output_index, context) src_code = src.generator.get_shader_code(uv, src.output_index, context)
while src_code is GDScriptFunctionState:
src_code = yield(src_code, "completed")
src_code.string = src_code[type] src_code.string = src_code[type]
required_defs += src_code.defs required_defs += src_code.defs
required_code += src_code.code required_code += src_code.code
required_textures = src_code.textures
string = string.replace("$%s(%s)" % [ input, uv ], src_code.string) string = string.replace("$%s(%s)" % [ input, uv ], src_code.string)
return { string=string, defs=required_defs, code=required_code } return { string=string, defs=required_defs, code=required_code, textures=required_textures }
func is_word_letter(l): func is_word_letter(l):
return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1 return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1
@ -86,6 +100,7 @@ func replace_variable(string, variable, value):
func subst(string, context, uv = ""): func subst(string, context, uv = ""):
var required_defs = "" var required_defs = ""
var required_code = "" var required_code = ""
var required_textures = {}
string = replace_variable(string, "name", name) string = replace_variable(string, "name", name)
string = replace_variable(string, "seed", str(get_seed())) string = replace_variable(string, "seed", str(get_seed()))
if uv != "": if uv != "":
@ -113,20 +128,29 @@ func subst(string, context, uv = ""):
var input = shader_model.inputs[i] var input = shader_model.inputs[i]
var source = get_source(i) var source = get_source(i)
var result = replace_input(string, context, input.name, input.type, source, input.default) var result = replace_input(string, context, input.name, input.type, source, input.default)
while result is GDScriptFunctionState:
result = yield(result, "completed")
string = result.string string = result.string
required_defs += result.defs required_defs += result.defs
required_code += result.code required_code += result.code
return { string=string, defs=required_defs, code=required_code } for t in result.textures.keys():
required_textures[t] = result.textures[t]
return { string=string, defs=required_defs, code=required_code, textures=required_textures }
func _get_shader_code(uv : String, output_index : int, context : MMGenContext): func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ] var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ]
var rv = { defs="", code="" } var rv = { defs="", code="", textures={} }
var variant_string = uv+","+str(output_index) var variant_string = uv+","+str(output_index)
if shader_model != null and shader_model.has("outputs") and shader_model.outputs.size() > output_index: if shader_model != null and shader_model.has("outputs") and shader_model.outputs.size() > output_index:
var output = shader_model.outputs[output_index] var output = shader_model.outputs[output_index]
rv.defs = "" rv.defs = ""
if shader_model.has("instance") && !context.has_variant(self): if shader_model.has("instance") && !context.has_variant(self):
rv.defs += subst(shader_model.instance, context).string var subst_output = subst(shader_model.instance, context, uv)
while subst_output is GDScriptFunctionState:
subst_output = yield(subst_output, "completed")
rv.defs += subst_output.string
for t in subst_output.textures.keys():
rv.textures[t] = subst_output.textures[t]
for p in shader_model.parameters: for p in shader_model.parameters:
if p.type == "gradient": if p.type == "gradient":
var g = parameters[p.name] var g = parameters[p.name]
@ -137,13 +161,16 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
var variant_index = context.get_variant(self, variant_string) var variant_index = context.get_variant(self, variant_string)
if variant_index == -1: if variant_index == -1:
variant_index = context.get_variant(self, variant_string) variant_index = context.get_variant(self, variant_string)
generated_variants.append(variant_string)
for t in output_info: for t in output_info:
if output.has(t.field): if output.has(t.field):
var subst_output = subst(output[t.field], context, uv) var subst_output = subst(output[t.field], context, uv)
while subst_output is GDScriptFunctionState:
subst_output = yield(subst_output, "completed")
rv.defs += subst_output.defs rv.defs += subst_output.defs
rv.code += subst_output.code rv.code += subst_output.code
rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, output_index, variant_index, t.field, subst_output.string ] rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, output_index, variant_index, t.field, subst_output.string ]
for t in subst_output.textures.keys():
rv.textures[t] = subst_output.textures[t]
for t in output_info: for t in output_info:
if output.has(t.field): if output.has(t.field):
rv[t.field] = "%s_%d_%d_%s" % [ name, output_index, variant_index, t.field ] rv[t.field] = "%s_%d_%d_%s" % [ name, output_index, variant_index, t.field ]

View File

@ -18,6 +18,9 @@ static func generate_shader(src_code):
file.open("res://addons/material_maker/common.shader", File.READ) file.open("res://addons/material_maker/common.shader", File.READ)
code += file.get_as_text() code += file.get_as_text()
code += "\n" code += "\n"
if src_code.has("textures"):
for t in src_code.textures.keys():
code += "uniform sampler2D "+t+";\n"
if src_code.has("globals"): if src_code.has("globals"):
for g in src_code.globals: for g in src_code.globals:
code += g code += g
@ -84,7 +87,7 @@ func render_shader(shader, textures, render_size):
shader_material.shader.code = shader shader_material.shader.code = shader
if textures != null: if textures != null:
for k in textures.keys(): for k in textures.keys():
shader_material.set_shader_param(k+"_tex", textures[k]) shader_material.set_shader_param(k, textures[k])
render_target_update_mode = Viewport.UPDATE_ONCE render_target_update_mode = Viewport.UPDATE_ONCE
update_worlds() update_worlds()
yield(get_tree(), "idle_frame") yield(get_tree(), "idle_frame")

View File

@ -1 +1 @@
{"global":"","inputs":[{"default":"0.0","label":"Input","name":"input","type":"f"}],"instance":"","name":"Colorize","outputs":[{"rgba":"$gradient($input($uv))"}],"parameters":[{"default":{"points":[{"a":1,"b":0,"g":0,"pos":0,"r":0},{"a":1,"b":1,"g":1,"pos":1,"r":1}],"type":"Gradient"},"label":"","name":"gradient","type":"gradient"}]} {"global":"","inputs":[{"default":"$uv.x","label":"Input","name":"input","type":"f"}],"instance":"","name":"Colorize","outputs":[{"rgba":"$gradient($input($uv))"}],"parameters":[{"default":{"points":[{"a":1,"b":0,"g":0,"pos":0,"r":0},{"a":1,"b":1,"g":1,"pos":1,"r":1}],"type":"Gradient"},"label":"","name":"gradient","type":"gradient"}]}

View File

@ -86,13 +86,11 @@ func update_node(data):
if data.has("instance") and data.instance.find("$(seed)"): if data.has("instance") and data.instance.find("$(seed)"):
uses_seed = true uses_seed = true
# Parameters # Parameters
print("Parameters")
controls = [] controls = []
var sizer = null var sizer = null
for p in generator.get_parameter_defs(): for p in generator.get_parameter_defs():
if !p.has("name") or !p.has("type"): if !p.has("name") or !p.has("type"):
continue continue
print(p.name)
var control = null var control = null
if p.type == "float": if p.type == "float":
if p.has("widget") and p.widget == "spinbox": if p.has("widget") and p.widget == "spinbox":
@ -141,35 +139,39 @@ func update_node(data):
control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
sizer.add_child(control) sizer.add_child(control)
initialize_properties() initialize_properties()
if data.has("inputs") and typeof(data.inputs) == TYPE_ARRAY: # Inputs
for i in range(data.inputs.size()): var inputs = generator.get_input_defs()
var input = data.inputs[i] for i in range(inputs.size()):
var enable_left = false var input = inputs[i]
var color_left = Color(0.5, 0.5, 0.5) print(input)
if typeof(input) == TYPE_DICTIONARY: var enable_left = false
if input.type == "rgb": var color_left = Color(0.5, 0.5, 0.5)
enable_left = true if typeof(input) == TYPE_DICTIONARY:
color_left = Color(0.5, 0.5, 1.0) if input.type == "rgb":
elif input.type == "rgba": enable_left = true
enable_left = true color_left = Color(0.5, 0.5, 1.0)
color_left = Color(0.0, 0.5, 0.0, 0.5) elif input.type == "rgba":
else: enable_left = true
enable_left = true color_left = Color(0.0, 0.5, 0.0, 0.5)
set_slot(i, enable_left, 0, color_left, false, 0, Color()) else:
if data.has("outputs") and typeof(data.outputs) == TYPE_ARRAY: enable_left = true
for i in range(data.outputs.size()): set_slot(i, enable_left, 0, color_left, false, 0, Color())
var output = data.outputs[i] # Outputs
var enable_right = false var outputs = generator.get_output_defs()
var color_right = Color(0.5, 0.5, 0.5) for i in range(outputs.size()):
if typeof(output) == TYPE_DICTIONARY: var output = outputs[i]
if output.has("rgb"): print(output)
enable_right = true var enable_right = false
color_right = Color(0.5, 0.5, 1.0) var color_right = Color(0.5, 0.5, 0.5)
elif output.has("rgba"): if typeof(output) == TYPE_DICTIONARY:
enable_right = true if output.has("rgb"):
color_right = Color(0.0, 0.5, 0.0, 0.5) enable_right = true
elif output.has("f"): color_right = Color(0.5, 0.5, 1.0)
enable_right = true elif output.has("rgba"):
set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right) enable_right = true
color_right = Color(0.0, 0.5, 0.0, 0.5)
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: if custom_node_buttons != null:
move_child(custom_node_buttons, get_child_count()-1) move_child(custom_node_buttons, get_child_count()-1)