Added preview, rendering fixes, better grouping

This commit is contained in:
RodZill4 2019-10-05 11:04:50 +02:00
parent 57cb3b4a14
commit b58770c2a0
14 changed files with 253 additions and 85 deletions

View File

@ -67,7 +67,7 @@ func notify_output_change(output_index : int):
for target in targets:
target.generator.source_changed(target.input_index)
func source_changed(input_index : int):
func source_changed(__):
for i in range(get_output_defs().size()):
notify_output_change(i)
@ -97,12 +97,12 @@ func render(output_index : int, renderer : MMGenRenderer, size : int):
while source is GDScriptFunctionState:
source = yield(source, "completed")
if source == null:
return false
source = { defs="", code="", textures={}, rgba="vec4(0.0)" }
var shader : String = renderer.generate_shader(source)
var status = renderer.render_shader(shader, source.textures, size)
while status is GDScriptFunctionState:
status = yield(status, "completed")
return status
var result = renderer.render_shader(shader, source.textures, size)
while result is GDScriptFunctionState:
result = yield(result, "completed")
return result
func get_shader_code(uv : String, output_index : int, context : MMGenContext):
var rv = _get_shader_code(uv, output_index, context)
@ -125,7 +125,7 @@ func get_shader_code(uv : String, output_index : int, context : MMGenContext):
rv.rgba = "vec4("+rv.rgb+", 1.0)"
return rv
func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
func _get_shader_code(__, __, __):
return null
func _serialize(data):

View File

@ -35,14 +35,13 @@ func source_changed(input_port_index : int):
func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
var source = get_source(0)
if source != null and !updated:
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
updated = true
var result = source.generator.render(source.output_index, context.renderer, pow(2, 4+parameters.size))
while result is GDScriptFunctionState:
result = yield(result, "completed")
result.copy_to_texture(texture)
result.release()
texture.flags = 0
updated = true
var rv = ._get_shader_code(uv, output_index, context)
while rv is GDScriptFunctionState:
rv = yield(rv, "completed")

View File

@ -129,10 +129,28 @@ func _serialize(data):
func edit(node):
node.get_parent().call_deferred("update_view", self)
func create_subgraph(generators):
func create_subgraph(gens):
# Remove material, gen_inputs and gen_outputs nodes
var generators = []
var center = Vector2(0, 0)
var left_bound = 65535
var right_bound = -65536
var count = 0
for g in gens:
if g.name != "Material" and g.name != "gen_inputs" and g.name != "gen_outputs":
generators.push_back(g)
var p = g.position
center += p
count += 1
if left_bound > p.x: left_bound = p.x
if right_bound < p.x: right_bound = p.x
if count == 0:
return
center /= count
var new_graph = get_script().new()
new_graph.name = "graph"
add_child(new_graph)
add_generator(new_graph)
new_graph.position = center
var names : Array = []
for g in generators:
names.push_back(g.name)
@ -140,27 +158,39 @@ func create_subgraph(generators):
new_graph.add_generator(g)
var new_graph_connections = []
var my_new_connections = []
var inputs = null
var outputs = null
var gen_inputs = null
var gen_outputs = null
var inputs = []
var outputs = []
for c in connections:
var src_name = c.from+"."+str(c.from_port)
if names.find(c.from) != -1 and names.find(c.to) != -1:
new_graph_connections.push_back(c)
elif names.find(c.from) != -1:
if outputs == null:
outputs = MMGenIOs.new()
outputs.name = "gen_outputs"
new_graph.add_generator(outputs)
var port_index = outputs.ports.size()
outputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
var port_index = outputs.find(src_name)
if port_index == -1:
port_index = outputs.size()
outputs.push_back(src_name)
if gen_outputs == null:
gen_outputs = MMGenIOs.new()
gen_outputs.name = "gen_outputs"
gen_outputs.position = Vector2(right_bound+300, center.y)
new_graph.add_generator(gen_outputs)
gen_outputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
print(gen_outputs.ports)
my_new_connections.push_back( { from=new_graph.name, from_port=port_index, to=c.to, to_port=c.to_port } )
new_graph_connections.push_back( { from=c.from, from_port=c.from_port, to="gen_outputs", to_port=port_index } )
elif names.find(c.to) != -1:
if inputs == null:
inputs = MMGenIOs.new()
inputs.name = "gen_inputs"
new_graph.add_generator(inputs)
var port_index = inputs.ports.size()
inputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
var port_index = inputs.find(src_name)
if port_index == -1:
port_index = inputs.size()
inputs.push_back(src_name)
if gen_inputs == null:
gen_inputs = MMGenIOs.new()
gen_inputs.name = "gen_inputs"
gen_inputs.position = Vector2(left_bound-300, center.y)
new_graph.add_generator(gen_inputs)
gen_inputs.ports.push_back( { name="port"+str(port_index), type="rgba" } )
my_new_connections.push_back( { from=c.from, from_port=c.from_port, to=new_graph.name, to_port=port_index } )
new_graph_connections.push_back( { from="gen_inputs", from_port=port_index, to=c.to, to_port=c.to_port } )
else:

View File

@ -6,24 +6,21 @@ class_name MMGenIOs
IOs just forward their inputs to their outputs and are used to specify graph interfaces
"""
var mask : int = 3
var ports : Array = []
func get_type():
return "buffer"
return "ios"
func get_type_name():
match name:
"gen_inputs": return "Inputs"
"gen_outputs": return "Outputs"
_: return "IOs"
return "Buffer"
func get_io_defs():
var rv : Array = []
if mask != 2:
for p in ports:
rv.push_back({ name=p.name, type="rgba" })
for p in ports:
rv.push_back({ name=p.name, type="rgba" })
return rv
func get_input_defs():
@ -39,17 +36,15 @@ func source_changed(input_index : int):
notify_output_change(input_index)
func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
if mask != 2:
var source = get_source(output_index)
if source != null:
var rv = source.generator._get_shader_code(uv, source.output_index, context)
while rv is GDScriptFunctionState:
rv = yield(rv, "completed")
return rv
var source = get_source(output_index)
if source != null:
var rv = source.generator._get_shader_code(uv, source.output_index, context)
while rv is GDScriptFunctionState:
rv = yield(rv, "completed")
return rv
return { defs="", code="", textures={} }
func _serialize(data):
data.type = "ios"
data.mask = mask
data.ports = ports
return data

View File

@ -69,11 +69,12 @@ func render_textures(renderer : MMGenRenderer):
if t.has("port"):
var source = get_source(t.port)
if source != null:
var status = source.generator.render(source.output_index, renderer, 1024)
while status is GDScriptFunctionState:
status = yield(status, "completed")
var result = source.generator.render(source.output_index, renderer, 1024)
while result is GDScriptFunctionState:
result = yield(result, "completed")
texture = ImageTexture.new()
texture.create_from_image(renderer.get_texture().get_data())
result.copy_to_texture(texture)
result.release()
elif t.has("ports"):
var context : MMGenContext = MMGenContext.new(renderer)
var code = []
@ -90,11 +91,12 @@ func render_textures(renderer : MMGenRenderer):
else:
code.push_back({ defs="", code="", f=t.default_values[i] })
var shader : String = renderer.generate_combined_shader(code[0], code[1], code[2])
var status = renderer.render_shader(shader, shader_textures, 1024)
while status is GDScriptFunctionState:
status = yield(status, "completed")
var result = renderer.render_shader(shader, shader_textures, 1024)
while result is GDScriptFunctionState:
result = yield(result, "completed")
texture = ImageTexture.new()
texture.create_from_image(renderer.get_texture().get_data())
result.copy_to_texture(texture)
result.release()
generated_textures[t.texture] = texture
func update_materials(material_list):

View File

@ -55,8 +55,6 @@ static func create_gen(data) -> MMGenBase:
generator = MMGenImage.new()
elif data.type == "ios":
generator = MMGenIOs.new()
if data.has("mask"):
generator.mask = int(data.mask)
generator.ports = data.ports
elif data.type == "switch":
generator = MMGenSwitch.new()

View File

@ -92,7 +92,14 @@ func render_shader(shader, textures, render_size):
update_worlds()
yield(get_tree(), "idle_frame")
yield(get_tree(), "idle_frame")
return self
func copy_to_texture(t : ImageTexture):
get_texture().get_data().lock()
t.create_from_image(get_texture().get_data())
get_texture().get_data().unlock()
func release():
rendering = false
emit_signal("done")
return true

View File

@ -49,8 +49,8 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="14.304427"
inkscape:cx="46.907045"
inkscape:cy="41.347265"
inkscape:cx="33.274902"
inkscape:cy="30.161917"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
@ -67,8 +67,8 @@
<inkscape:grid
type="xygrid"
id="grid815"
spacingx="4.2333332"
spacingy="4.2333332" />
spacingx="16"
spacingy="16" />
</sodipodi:namedview>
<metadata
id="metadata5">
@ -265,5 +265,24 @@
id="rect863"
style="opacity:0;fill:#ffed46;fill-opacity:1;stroke:#c7b115;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" />
</g>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.96038949;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 14.281124,319.9133 c -3.380125,5.56722 -9.3711249,5.74887 -12.9027613,0 2.6589695,-5.76337 10.0526323,-5.46131 12.9027613,0 z"
id="path5159"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<ellipse
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path5162"
cx="7.8297439"
cy="319.77344"
rx="1.0486264"
ry="0.87385535" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path5166"
d="m 30.429971,319.84339 c -3.380125,5.56722 -9.371125,5.74887 -12.902762,0"
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.96038949;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -26,7 +26,7 @@ const MENU = [
{ menu="Edit", command="edit_cut", shortcut="Control+X", description="Cut" },
{ menu="Edit", command="edit_copy", shortcut="Control+C", description="Copy" },
{ menu="Edit", command="edit_paste", shortcut="Control+V", description="Paste" },
{ menu="Tools", command="create_subgraph", shortcut="Control+G", description="Create subgraph" },
{ menu="Tools", command="create_subgraph", shortcut="Control+G", description="Create group" },
{ menu="Tools", command="make_selected_nodes_editable", shortcut="Control+F", description="Make selected nodes editable" },
{ menu="Tools", command="add_to_user_library", description="Add selected node to user library" },
{ menu="Tools", command="save_user_library", description="Save user library" },
@ -331,14 +331,13 @@ func update_preview_2d(node = null):
node = n
break
if node != null:
var status = node.generator.render(0, renderer, 1024)
while status is GDScriptFunctionState:
status = yield(status, "completed")
if status:
var image = renderer.get_texture().get_data()
var tex = ImageTexture.new()
tex.create_from_image(image)
preview.set_2d(tex)
var result = node.generator.render(0, renderer, 1024)
while result is GDScriptFunctionState:
result = yield(result, "completed")
var tex = ImageTexture.new()
result.copy_to_texture(tex)
result.release()
preview.set_2d(tex)
func update_preview_3d():
var graph_edit = get_current_graph_edit()

View File

@ -8,9 +8,11 @@ func _ready():
func create_node(type):
var node = null
var node_type = load("res://addons/material_maker/nodes/"+type+".tscn")
if node_type != null:
node = node_type.instance()
var file_name = "res://addons/material_maker/nodes/"+type+".tscn"
if ResourceLoader.exists(file_name):
var node_type = load(file_name)
if node_type != null:
node = node_type.instance()
else:
node = preload("res://addons/material_maker/nodes/generic.tscn").instance()
return node

View File

@ -6,6 +6,13 @@ var generator = null setget set_generator
var controls = {}
var ignore_parameter_change = ""
var output_count = 0
var preview : TextureRect
var preview_index : int = -1
var preview_position : int
var preview_size : int
var preview_timer : Timer
func set_generator(g):
generator = g
@ -71,6 +78,7 @@ func initialize_properties():
func update_shaders():
get_parent().send_changed_signal()
update_preview()
func _on_text_changed(new_text, variable):
ignore_parameter_change = variable
@ -158,9 +166,15 @@ func update_node():
set_slot(i, enable_left, 0, color_left, false, 0, Color())
var hsizer : HBoxContainer = HBoxContainer.new()
hsizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
var label : Label = Label.new()
label.text = input.label if input.has("label") else ""
hsizer.add_child(label)
if input.has("label") and input.label != "":
var label : Label = Label.new()
label.text = input.label
hsizer.add_child(label)
else:
var control : Control = Control.new()
control.rect_min_size.y = 16
hsizer.add_child(control)
add_child(hsizer)
var input_names_width : int = 0
for c in get_children():
@ -211,7 +225,9 @@ func update_node():
initialize_properties()
# Outputs
var outputs = generator.get_output_defs()
for i in range(outputs.size()):
var button_width = 0
output_count = outputs.size()
for i in range(output_count):
var output = outputs[i]
var enable_right = true
var color_right = Color(0.5, 0.5, 0.5)
@ -222,14 +238,49 @@ func update_node():
"rgb": color_right = Color(0.5, 0.5, 1.0)
"rgba": color_right = Color(0.0, 0.5, 0.0, 0.5)
set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right)
if i >= get_child_count():
var control = Control.new()
control.rect_min_size = Vector2(0, 16)
add_child(control)
var hsizer : HBoxContainer
while i >= get_child_count():
hsizer = HBoxContainer.new()
hsizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
add_child(hsizer)
hsizer = get_child(i)
var has_filler = false
for c in hsizer.get_children():
if c.size_flags_horizontal & SIZE_EXPAND != 0:
has_filler = true
break
if !has_filler:
var empty_control : Control = Control.new()
empty_control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
hsizer.add_child(empty_control)
var button = preload("res://addons/material_maker/widgets/preview_button.tscn").instance()
button.size_flags_horizontal = SIZE_SHRINK_END
button.size_flags_vertical = SIZE_SHRINK_CENTER
hsizer.add_child(button)
button.connect("toggled", self, "on_preview_button", [ i ])
button_width = button.rect_size.x
if !outputs.empty():
for i in range(output_count, get_child_count()):
var hsizer : HBoxContainer = get_child(i)
var empty_control : Control = Control.new()
empty_control.rect_min_size.x = button_width
hsizer.add_child(empty_control)
# Preview
if preview == null:
preview = TextureRect.new()
preview.visible = false
preview_position = get_child_count()
# Edit buttons
if generator.model == null:
var edit_buttons = preload("res://addons/material_maker/nodes/edit_buttons.tscn").instance()
add_child(edit_buttons)
edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator")
# Preview timer
preview_timer = Timer.new()
preview_timer.one_shot = true
preview_timer.connect("timeout", self, "do_update_preview")
add_child(preview_timer)
func edit_generator():
if generator.has_method("edit"):
@ -284,3 +335,48 @@ func do_save_generator(file_name : String):
data.node_position = { x=0, y=0 }
file.store_string(to_json(data))
file.close()
func on_preview_button(pressed : bool, index : int):
if pressed:
preview_index = index
var width
if preview.visible:
for i in range(output_count):
if i != index:
var line = get_child(i)
line.get_child(line.get_child_count()-1).pressed = false
update_preview()
else:
var status = update_preview(get_child(0).rect_size.x)
while status is GDScriptFunctionState:
status = yield(status, "completed")
else:
preview_index = -1
preview.visible = false
remove_child(preview)
rect_size = Vector2(0, 0)
func update_preview(size : int = 0):
if preview_index == -1:
return
if size != 0:
preview_size = size
preview_timer.start(0.2)
func do_update_preview():
var renderer = get_parent().renderer
var result = generator.render(preview_index, renderer, preview_size)
while result is GDScriptFunctionState:
result = yield(result, "completed")
if preview.texture == null:
preview.texture = ImageTexture.new()
result.copy_to_texture(preview.texture)
result.release()
if !preview.visible:
add_child(preview)
move_child(preview, preview_position)
preview.visible = true

View File

@ -3,7 +3,7 @@
[ext_resource path="res://addons/material_maker/preview.gd" type="Script" id=1]
[ext_resource path="res://addons/material_maker/preview_3d.tscn" type="PackedScene" id=2]
[sub_resource type="World" id=4]
[sub_resource type="World" id=1]
[sub_resource type="Shader" id=2]
code = "shader_type canvas_item;
@ -33,7 +33,7 @@ script = ExtResource( 1 )
[node name="MaterialPreview" type="Viewport" parent="."]
size = Vector2( 395, 370 )
own_world = true
world = SubResource( 4 )
world = SubResource( 1 )
handle_input_locally = false
render_target_clear_mode = 1
render_target_update_mode = 3
@ -50,7 +50,7 @@ margin_right = 100.0
margin_bottom = 20.0
rect_min_size = Vector2( 100, 0 )
text = "Cube"
items = [ "Cube", null, false, -1, null, "Cylinder", null, false, -1, null, "Sphere", null, false, -1, null, "Quad", null, false, -1, null, "Plane", null, false, -1, null ]
items = [ "Cube", null, false, -1, null, "Cylinder", null, false, -1, null, "Sphere", null, false, -1, null, "Sphere2", null, false, -1, null, "Quad", null, false, -1, null, "Plane", null, false, -1, null ]
selected = 0
[node name="Environment" type="OptionButton" parent="Config"]

View File

@ -14,7 +14,7 @@ background_sky = SubResource( 1 )
[sub_resource type="Animation" id=3]
loop = true
tracks/0/type = "value"
tracks/0/path = NodePath("MaterialPreview/Spatial/Objects:rotation_degrees")
tracks/0/path = NodePath("Objects:rotation_degrees")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = false
@ -28,7 +28,7 @@ tracks/0/keys = {
[node name="Preview3d" type="Spatial"]
[node name="Objects" type="Spatial" parent="." instance=ExtResource( 1 )]
[node name="Objects" parent="." instance=ExtResource( 1 )]
transform = Transform( -0.799512, 0, 0.60065, 0, 1, 0, -0.60065, 0, -0.799512, 0, 0, 0 )
[node name="OmniLight" type="OmniLight" parent="."]

View File

@ -0,0 +1,21 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/material_maker/icons/icons.svg" type="Texture" id=1]
[sub_resource type="AtlasTexture" id=1]
flags = 4
atlas = ExtResource( 1 )
region = Rect2( 16, 32, 16, 16 )
[sub_resource type="AtlasTexture" id=2]
flags = 4
atlas = ExtResource( 1 )
region = Rect2( 0, 32, 16, 16 )
[node name="PreviewButton" type="TextureButton"]
anchor_right = 1.0
anchor_bottom = 1.0
toggle_mode = true
shortcut_in_tooltip = false
texture_normal = SubResource( 1 )
texture_pressed = SubResource( 2 )