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):
generator = g
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():
return generator.name+"("+str(output_index)+")"
@ -81,16 +72,20 @@ func get_globals():
func render(output_index : int, renderer : MMGenRenderer, size : int):
var context : MMGenContext = MMGenContext.new(renderer)
var source = get_shader_code("UV", output_index, context)
while source is GDScriptFunctionState:
source = yield(source, "completed")
if source == null:
return false
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:
status = yield(status, "completed")
return status
func get_shader_code(uv : String, output_index : int, context : MMGenContext):
var rv = _get_shader_code(uv, output_index, context)
while rv is GDScriptFunctionState:
rv = yield(rv, "completed")
if rv != null:
if !rv.has("f"):
if rv.has("rgb"):

View File

@ -2,6 +2,8 @@ tool
extends MMGenBase
class_name MMGenBuffer
var texture : ImageTexture = ImageTexture.new()
func _ready():
if !parameters.has("size"):
parameters.size = 4
@ -16,7 +18,28 @@ func get_parameter_defs():
return [ { name="size", type="size", first=4, last=11, default=4 } ]
func get_input_defs():
return [ ]
return [ { name="in", type="rgba" } ]
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):
var source = get_source(0)
if source != null:
var shader : String = renderer.generate_shader(source)
var status = renderer.render_shader(shader, {}, 512)
var status = source.generator.render(source.output_index, renderer, 512)
while status is GDScriptFunctionState:
status = yield(status, "completed")
print("Render status: "+str(status))

View File

@ -3,7 +3,6 @@ extends MMGenBase
class_name MMGenShader
var shader_model : Dictionary = {}
var generated_variants = []
func get_type():
return "shader"
@ -19,6 +18,18 @@ func get_parameter_defs():
else:
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):
shader_model = data
init_parameters()
@ -43,6 +54,7 @@ func find_keyword_call(string, keyword):
func replace_input(string, context, input, type, src, default):
var required_defs = ""
var required_code = ""
var required_textures = {}
while true:
var uv = find_keyword_call(string, input)
if uv == null:
@ -52,15 +64,17 @@ func replace_input(string, context, input, type, src, default):
break
var src_code
if src == null:
src_code = subst(default, "(%s)" % uv)
src_code = subst(default, context, "(%s)" % uv)
else:
print(src.to_str())
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]
required_defs += src_code.defs
required_code += src_code.code
required_textures = src_code.textures
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):
return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1
@ -86,6 +100,7 @@ func replace_variable(string, variable, value):
func subst(string, context, uv = ""):
var required_defs = ""
var required_code = ""
var required_textures = {}
string = replace_variable(string, "name", name)
string = replace_variable(string, "seed", str(get_seed()))
if uv != "":
@ -113,20 +128,29 @@ func subst(string, context, uv = ""):
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")
string = result.string
required_defs += result.defs
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):
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)
if shader_model != null and shader_model.has("outputs") and shader_model.outputs.size() > output_index:
var output = shader_model.outputs[output_index]
rv.defs = ""
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:
if p.type == "gradient":
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)
if variant_index == -1:
variant_index = context.get_variant(self, variant_string)
generated_variants.append(variant_string)
for t in output_info:
if output.has(t.field):
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.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 ]
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" % [ 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)
code += file.get_as_text()
code += "\n"
if src_code.has("textures"):
for t in src_code.textures.keys():
code += "uniform sampler2D "+t+";\n"
if src_code.has("globals"):
for g in src_code.globals:
code += g
@ -84,7 +87,7 @@ func render_shader(shader, textures, render_size):
shader_material.shader.code = shader
if textures != null:
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
update_worlds()
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)"):
uses_seed = true
# Parameters
print("Parameters")
controls = []
var sizer = null
for p in generator.get_parameter_defs():
if !p.has("name") or !p.has("type"):
continue
print(p.name)
var control = null
if p.type == "float":
if p.has("widget") and p.widget == "spinbox":
@ -141,35 +139,39 @@ func update_node(data):
control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
sizer.add_child(control)
initialize_properties()
if data.has("inputs") and typeof(data.inputs) == TYPE_ARRAY:
for i in range(data.inputs.size()):
var input = data.inputs[i]
var enable_left = false
var color_left = Color(0.5, 0.5, 0.5)
if typeof(input) == TYPE_DICTIONARY:
if input.type == "rgb":
enable_left = true
color_left = Color(0.5, 0.5, 1.0)
elif input.type == "rgba":
enable_left = true
color_left = Color(0.0, 0.5, 0.0, 0.5)
else:
enable_left = true
set_slot(i, enable_left, 0, color_left, false, 0, Color())
if data.has("outputs") and typeof(data.outputs) == TYPE_ARRAY:
for i in range(data.outputs.size()):
var output = 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, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right)
# Inputs
var inputs = generator.get_input_defs()
for i in range(inputs.size()):
var input = inputs[i]
print(input)
var enable_left = false
var color_left = Color(0.5, 0.5, 0.5)
if typeof(input) == TYPE_DICTIONARY:
if input.type == "rgb":
enable_left = true
color_left = Color(0.5, 0.5, 1.0)
elif input.type == "rgba":
enable_left = true
color_left = Color(0.0, 0.5, 0.0, 0.5)
else:
enable_left = true
set_slot(i, enable_left, 0, color_left, false, 0, Color())
# Outputs
var outputs = generator.get_output_defs()
for i in range(outputs.size()):
var output = outputs[i]
print(output)
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, 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:
move_child(custom_node_buttons, get_child_count()-1)