Started adding the "remote node"
Started adding the "remote" node, that can control important parameters of the graph and save/restore configurations of groups of parameters. This should help creating easily configurable materials. Added new "mosaic" example
1
addons/material_maker/examples/mosaic.ptex
Normal file
@ -0,0 +1 @@
|
||||
{"connections":[{"from":"blend_0","from_port":0,"to":"Material","to_port":0},{"from":"voronoi_0","from_port":2,"to":"blend_0","to_port":1},{"from":"voronoi_0","from_port":1,"to":"colorize_0","to_port":0},{"from":"colorize_0","from_port":0,"to":"blend_0","to_port":0},{"from":"voronoi_0","from_port":1,"to":"colorize_1","to_port":0},{"from":"colorize_1","from_port":0,"to":"normal_map_0","to_port":0},{"from":"normal_map_0","from_port":0,"to":"Material","to_port":4},{"from":"uniform_0","from_port":0,"to":"Material","to_port":1},{"from":"voronoi_0","from_port":1,"to":"colorize_2","to_port":0},{"from":"colorize_2","from_port":0,"to":"Material","to_port":2}],"nodes":[{"intensity":1,"name":"voronoi_0","node_position":{"x":-543.5,"y":-11.5},"scale_x":32,"scale_y":32,"type":"voronoi"},{"amount":0.5,"name":"normal_map_0","node_position":{"x":-165.5,"y":133.5},"size":5,"type":"normal_map"},{"albedo_color":{"a":1,"b":1,"g":1,"r":1,"type":"Color"},"ao_light_affect":1,"depth_scale":1,"emission_energy":1,"metallic":1,"name":"Material","node_position":{"x":30,"y":-44},"normal_scale":1,"resolution":1,"roughness":1,"type":"material"},{"gradient":[{"b":1,"g":1,"pos":0.045455,"r":1},{"b":0,"g":0,"pos":0.109091,"r":0}],"name":"colorize_1","node_position":{"x":-349.5,"y":138.5},"type":"colorize"},{"gradient":[{"b":1,"g":1,"pos":0.063636,"r":1},{"b":0,"g":0,"pos":0.072727,"r":0}],"name":"colorize_0","node_position":{"x":-317.5,"y":-169.5},"type":"colorize"},{"color":{"a":1,"b":0.109375,"g":0.109375,"r":0.109375,"type":"Color"},"name":"uniform_0","node_position":{"x":-127.5,"y":-3.5},"type":"uniform"},{"gradient":[{"b":1,"g":1,"pos":0,"r":1},{"b":0.109375,"g":0.109375,"pos":0.236364,"r":0.109375}],"name":"colorize_2","node_position":{"x":-306.5,"y":39.5},"type":"colorize"},{"amount":1,"blend_type":3,"name":"blend_0","node_position":{"x":-294.5,"y":-94.5},"type":"blend"}]}
|
BIN
addons/material_maker/icons/add.png
Normal file
After Width: | Height: | Size: 203 B |
BIN
addons/material_maker/icons/add_config.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
addons/material_maker/icons/add_link.png
Normal file
After Width: | Height: | Size: 505 B |
BIN
addons/material_maker/icons/config.png
Normal file
After Width: | Height: | Size: 441 B |
121
addons/material_maker/icons/icons.svg
Normal file
@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="icons.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8"
|
||||
inkscape:cx="127.97633"
|
||||
inkscape:cy="1033.5955"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid815" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||
id="rect4533"
|
||||
width="238.125"
|
||||
height="174.625"
|
||||
x="-10.583333"
|
||||
y="-3.3020833"
|
||||
ry="0.82414269" />
|
||||
<g
|
||||
id="g4582"
|
||||
transform="matrix(1.2003144,0.26398218,-0.26389538,1.2007092,-4.1100858,-17.15364)"
|
||||
inkscape:export-filename="link.png"
|
||||
inkscape:export-xdpi="15.926786"
|
||||
inkscape:export-ydpi="15.926786">
|
||||
<path
|
||||
id="path4540"
|
||||
d="m 52.110175,11.249997 c -2.182497,-2.09336 -5.682294,-2.0795701 -7.847077,0.03092 l -5.999358,5.848887 c -1.693669,1.651191 -2.053303,4.081962 -1.084529,6.064327 l 2.668997,-2.602056 c 0.06832,-0.475315 0.288771,-0.934614 0.666689,-1.303055 l 5.999358,-5.848887 c 0.927764,-0.904495 2.427677,-0.910404 3.363033,-0.01325 0.935356,0.897155 0.941467,2.347581 0.0137,3.252076 l -5.999358,5.848886 c -0.305037,0.297386 -0.672368,0.495758 -1.060703,0.598709 l -2.79438,2.724294 c 2.027594,0.834538 4.455047,0.445994 6.106241,-1.163787 l 5.999357,-5.848886 C 54.306929,16.727686 54.292669,13.34336 52.110175,11.25 Z"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.5892244;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path4542"
|
||||
d="m 47.703334,18.314275 c -2.043073,-0.877257 -4.511855,-0.499459 -6.184325,1.131064 l -5.999358,5.848887 c -2.164785,2.11049 -2.150524,5.494815 0.03197,7.588174 2.182497,2.09336 5.682293,2.079573 7.847078,-0.03092 l 5.999358,-5.848887 c 1.67245,-1.630503 2.042985,-4.020862 1.11922,-5.989301 l -2.724165,2.655841 c -0.08761,0.429031 -0.302522,0.839174 -0.646213,1.174244 l -5.999357,5.848887 c -0.927764,0.904494 -2.427678,0.910405 -3.363034,0.01325 -0.935356,-0.897154 -0.941466,-2.34758 -0.0137,-3.252075 l 5.999358,-5.848887 c 0.343694,-0.335073 0.766059,-0.54623 1.209002,-0.634439 z"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.5892244;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:export-ydpi="16.531826"
|
||||
inkscape:export-xdpi="16.531826"
|
||||
inkscape:export-filename="remove.png"
|
||||
id="g4564"
|
||||
transform="matrix(0.82426401,0.81188676,-0.82426401,0.81188676,84.358228,-6.2929802)"
|
||||
style="fill:#ff0909;fill-opacity:1">
|
||||
<rect
|
||||
style="opacity:1;fill:#ff0909;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||
id="rect4560"
|
||||
width="5.2916665"
|
||||
height="26.458334"
|
||||
x="10.583333"
|
||||
y="8.604167"
|
||||
ry="0" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ff0909;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||
id="rect4562"
|
||||
width="26.458332"
|
||||
height="5.2916665"
|
||||
x="0"
|
||||
y="19.1875"
|
||||
ry="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g4645"
|
||||
inkscape:export-filename="config.png"
|
||||
inkscape:export-xdpi="16.559999"
|
||||
inkscape:export-ydpi="16.559999"
|
||||
transform="matrix(1.0254261,0,0,1.0022479,-9.1237225,-33.22013)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4598"
|
||||
d="m 23.783078,44.110649 -4.508983,4.648736 -3.980261,-5.27284 a 12.770835,12.770835 0 0 0 -2.631282,1.045173 l 0.825522,6.441784 -6.571368,-0.17469 a 12.770835,12.770835 0 0 0 -0.7896172,2.557631 12.770835,12.770835 0 0 0 -0.027504,0.173796 l 5.5120272,3.347264 -4.1861363,4.972095 a 12.770835,12.770835 0 0 0 1.6563998,2.37002 l 5.9760855,-2.194035 1.267643,6.324612 a 12.770835,12.770835 0 0 0 2.907828,0.192046 l 1.997862,-6.001057 5.727797,2.948399 a 12.770835,12.770835 0 0 0 1.98019,-2.135962 l -3.455675,-5.317616 5.926699,-2.662342 a 12.770835,12.770835 0 0 0 -0.414249,-2.850168 l -6.383635,-0.620945 1.631047,-6.361785 a 12.770835,12.770835 0 0 0 -2.46039,-1.430116 z m -4.472442,8.529047 a 3.1927084,3.1927084 0 0 1 2.523332,3.744269 3.1927084,3.1927084 0 0 1 -3.744267,2.523336 3.1927084,3.1927084 0 0 1 -2.523335,-3.744269 3.1927084,3.1927084 0 0 1 3.74427,-2.523336 z"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80446196;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.3 KiB |
BIN
addons/material_maker/icons/link.png
Normal file
After Width: | Height: | Size: 476 B |
BIN
addons/material_maker/icons/remove.png
Normal file
After Width: | Height: | Size: 399 B |
@ -197,5 +197,9 @@
|
||||
{
|
||||
"tree_item":"Miscellaneous/Export",
|
||||
"type":"export"
|
||||
},
|
||||
{
|
||||
"tree_item":"Miscellaneous/Remote",
|
||||
"type":"remote"
|
||||
}
|
||||
]}
|
@ -6,7 +6,7 @@
|
||||
[ext_resource path="res://addons/material_maker/widgets/tabs.gd" type="Script" id=4]
|
||||
[ext_resource path="res://addons/material_maker/renderer.tscn" type="PackedScene" id=5]
|
||||
|
||||
[node name="MainWindow" type="Panel" index="0"]
|
||||
[node name="MainWindow" type="Panel"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
|
63
addons/material_maker/nodes/remote.gd
Normal file
@ -0,0 +1,63 @@
|
||||
tool
|
||||
extends "res://addons/material_maker/node_base.gd"
|
||||
|
||||
const LinkedControl = preload("res://addons/material_maker/widgets/linked_widgets/linked_control.tscn")
|
||||
const ConfigControl = preload("res://addons/material_maker/widgets/linked_widgets/config_control.tscn")
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _get_shader_code(uv):
|
||||
var rv = { defs="", code="" }
|
||||
rv.rgb = "vec3(1.0)"
|
||||
return rv
|
||||
|
||||
func add_control(widget):
|
||||
var controls = widget.get_associated_controls()
|
||||
$Controls.add_child(controls.label)
|
||||
$Controls.add_child(widget)
|
||||
$Controls.add_child(controls.buttons)
|
||||
|
||||
|
||||
func _on_AddLink_pressed():
|
||||
var widget = LinkedControl.instance()
|
||||
add_control(widget)
|
||||
widget.pick_linked()
|
||||
|
||||
func _on_AddConfig_pressed():
|
||||
var widget = ConfigControl.instance()
|
||||
add_control(widget)
|
||||
widget.pick_linked()
|
||||
|
||||
func _on_Remote_resize_request(new_minsize):
|
||||
print("_on_Remote_resize_request")
|
||||
rect_size = new_minsize
|
||||
|
||||
func _on_HBoxContainer_minimum_size_changed():
|
||||
print("_on_HBoxContainer_minimum_size_changed "+str($HBoxContainer.rect_min_size))
|
||||
|
||||
func serialize():
|
||||
var widgets = []
|
||||
for i in range(1, $Controls.get_child_count(), 3):
|
||||
widgets.append($Controls.get_child(i).serialize())
|
||||
var data = { type="remote", node_position={x=offset.x,y=offset.y}, editable=true, widgets=widgets }
|
||||
return data
|
||||
|
||||
func deserialize(data):
|
||||
if data.has("node_position"):
|
||||
offset.x = data.node_position.x
|
||||
offset.y = data.node_position.y
|
||||
call_deferred("do_deserialize", data)
|
||||
|
||||
func do_deserialize(data):
|
||||
if data.has("widgets"):
|
||||
for w in data.widgets:
|
||||
var widget
|
||||
if w.type == "linked_control":
|
||||
widget = LinkedControl.instance()
|
||||
elif w.type == "config_control":
|
||||
widget = ConfigControl.instance()
|
||||
else:
|
||||
continue
|
||||
add_control(widget)
|
||||
widget.deserialize(w)
|
139
addons/material_maker/nodes/remote.tscn
Normal file
@ -0,0 +1,139 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://addons/material_maker/nodes/remote.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/material_maker/icons/link.png" type="Texture" id=2]
|
||||
[ext_resource path="res://addons/material_maker/icons/config.png" type="Texture" id=3]
|
||||
|
||||
[sub_resource type="Theme" id=1]
|
||||
|
||||
|
||||
[node name="Remote" type="GraphNode"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 95.0
|
||||
margin_bottom = 55.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
theme = SubResource( 1 )
|
||||
title = "Remote"
|
||||
offset = Vector2( 0, 0 )
|
||||
show_close = true
|
||||
resizable = false
|
||||
selected = false
|
||||
comment = false
|
||||
overlay = 0
|
||||
slot/0/left_enabled = false
|
||||
slot/0/left_type = 0
|
||||
slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
|
||||
slot/0/right_enabled = false
|
||||
slot/0/right_type = 0
|
||||
slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
|
||||
slot/1/left_enabled = false
|
||||
slot/1/left_type = 0
|
||||
slot/1/left_color = Color( 1, 1, 1, 1 )
|
||||
slot/1/right_enabled = false
|
||||
slot/1/right_type = 0
|
||||
slot/1/right_color = Color( 1, 1, 1, 1 )
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Theme", "slot" ]
|
||||
|
||||
[node name="Controls" type="GridContainer" parent="." index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 16.0
|
||||
margin_top = 24.0
|
||||
margin_right = 79.0
|
||||
margin_bottom = 24.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
columns = 3
|
||||
_sections_unfolded = [ "Hint" ]
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="." index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 16.0
|
||||
margin_top = 24.0
|
||||
margin_right = 79.0
|
||||
margin_bottom = 46.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
|
||||
[node name="AddLink" type="Button" parent="HBoxContainer" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 28.0
|
||||
margin_bottom = 22.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
hint_tooltip = "Add linked control"
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
icon = ExtResource( 2 )
|
||||
flat = false
|
||||
align = 1
|
||||
_sections_unfolded = [ "Hint", "Rect", "Size Flags" ]
|
||||
|
||||
[node name="AddConfig" type="Button" parent="HBoxContainer" index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 32.0
|
||||
margin_right = 60.0
|
||||
margin_bottom = 22.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
hint_tooltip = "Add configurations"
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
icon = ExtResource( 3 )
|
||||
flat = false
|
||||
align = 1
|
||||
_sections_unfolded = [ "Hint" ]
|
||||
|
||||
[connection signal="pressed" from="HBoxContainer/AddLink" to="." method="_on_AddLink_pressed"]
|
||||
|
||||
[connection signal="pressed" from="HBoxContainer/AddConfig" to="." method="_on_AddConfig_pressed"]
|
||||
|
||||
|
@ -6,6 +6,15 @@ signal ok
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func set_texts(title, label):
|
||||
window_title = title
|
||||
$VBoxContainer/Label.text = label
|
||||
$VBoxContainer/LineEdit.grab_focus()
|
||||
$VBoxContainer/LineEdit.grab_click_focus()
|
||||
|
||||
func _on_OK_pressed():
|
||||
emit_signal("ok", $VBoxContainer/LineEdit.text)
|
||||
_on_LineEdit_text_entered($VBoxContainer/LineEdit.text)
|
||||
|
||||
func _on_LineEdit_text_entered(new_text):
|
||||
emit_signal("ok", new_text)
|
||||
queue_free()
|
||||
|
@ -146,6 +146,8 @@ flat = false
|
||||
align = 1
|
||||
_sections_unfolded = [ "Rect" ]
|
||||
|
||||
[connection signal="text_entered" from="VBoxContainer/LineEdit" to="." method="_on_LineEdit_text_entered"]
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/OK" to="." method="_on_OK_pressed"]
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/Cancel" to="." method="queue_free"]
|
||||
|
121
addons/material_maker/widgets/linked_widgets/config_control.gd
Normal file
@ -0,0 +1,121 @@
|
||||
tool
|
||||
extends "res://addons/material_maker/widgets/linked_widgets/linked_control_base.gd"
|
||||
|
||||
var configurations = {}
|
||||
|
||||
var current = null
|
||||
onready var button = null
|
||||
|
||||
func _ready():
|
||||
update_options()
|
||||
|
||||
func update_options():
|
||||
# Seems "clear" might cause crashes, so we create a new button...
|
||||
if button != null:
|
||||
button.hide()
|
||||
button.queue_free()
|
||||
button = OptionButton.new()
|
||||
button.connect("item_selected", self, "_on_item_selected")
|
||||
button.connect("mouse_entered", self, "_on_mouse_entered")
|
||||
button.connect("mouse_exited", self, "_on_mouse_exited")
|
||||
add_child(button)
|
||||
# Create list of configurations
|
||||
var keys = configurations.keys()
|
||||
keys.sort()
|
||||
# if no configuration is selected, select the first one
|
||||
if current == null and !keys.empty():
|
||||
current = keys[0]
|
||||
for c in keys:
|
||||
button.add_item(c)
|
||||
button.add_separator()
|
||||
button.add_item("<add configuration>")
|
||||
if current != null:
|
||||
button.add_separator()
|
||||
button.add_item("<update "+current+">")
|
||||
button.add_item("<remove "+current+">")
|
||||
for i in range(button.get_item_count()):
|
||||
if button.get_item_text(i) == current:
|
||||
button.selected = i
|
||||
break
|
||||
|
||||
func add_linked(node, widget):
|
||||
linked_widgets.append({ node=node, widget=widget })
|
||||
|
||||
func apply_configuration(c):
|
||||
for w in configurations[c]:
|
||||
w.widget.set(WIDGETS[get_widget_type(w.widget)].value_attr , w.value)
|
||||
w.node.set(w.widget.name, w.value)
|
||||
var graph_node = get_parent()
|
||||
while !(graph_node is GraphNode):
|
||||
graph_node = graph_node.get_parent()
|
||||
graph_node.update_shaders()
|
||||
|
||||
func do_update_configuration(name):
|
||||
var configuration = []
|
||||
for w in linked_widgets:
|
||||
configuration.append({ node=w.node, widget=w.widget, value=w.node.get(w.widget.name) })
|
||||
configurations[name] = configuration
|
||||
current = name
|
||||
update_options()
|
||||
|
||||
func update_configuration():
|
||||
var dialog = preload("res://addons/material_maker/widgets/line_dialog.tscn").instance()
|
||||
add_child(dialog)
|
||||
dialog.set_texts("Configuration", "Enter a name for the new configuration")
|
||||
dialog.connect("ok", self, "do_update_configuration", [])
|
||||
dialog.popup_centered()
|
||||
|
||||
func _on_item_selected(ID):
|
||||
var count = configurations.keys().size()
|
||||
if ID >= 0 && ID < count:
|
||||
current = button.get_item_text(ID)
|
||||
update_options()
|
||||
apply_configuration(current)
|
||||
elif ID == count+1:
|
||||
button.selected = 0
|
||||
update_configuration()
|
||||
elif ID == count+3:
|
||||
do_update_configuration(current)
|
||||
else:
|
||||
configurations.erase(current)
|
||||
current = null
|
||||
update_options()
|
||||
|
||||
func serialize():
|
||||
var data = .serialize()
|
||||
data.type = "config_control"
|
||||
var data_configurations = {}
|
||||
var keys = configurations.keys()
|
||||
for k in keys:
|
||||
var c = configurations[k]
|
||||
var data_configuration = []
|
||||
for e in c:
|
||||
data_configuration.append({ node=e.node.name, widget=e.widget.name, value=e.value })
|
||||
data_configurations[k] = data_configuration
|
||||
data.configurations = data_configurations
|
||||
return data
|
||||
|
||||
func deserialize(data):
|
||||
.deserialize(data)
|
||||
graph_edit = get_parent()
|
||||
while graph_edit != null && !(graph_edit is GraphEdit):
|
||||
graph_edit = graph_edit.get_parent()
|
||||
if graph_edit == null:
|
||||
return
|
||||
var keys = data.configurations.keys()
|
||||
for k in keys:
|
||||
var c = data.configurations[k]
|
||||
var configuration = []
|
||||
for e in c:
|
||||
var node = graph_edit.get_node(e.node)
|
||||
var widget = null
|
||||
for w in node.property_widgets:
|
||||
if w.name == e.widget:
|
||||
widget = w
|
||||
break
|
||||
configuration.append({ node=node, widget=widget, value=e.value })
|
||||
configurations[k] = configuration
|
||||
update_options()
|
||||
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/material_maker/widgets/linked_widgets/config_control.gd" type="Script" id=1]
|
||||
|
||||
[node name="ConfigControl" type="VBoxContainer"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
rect_min_size = Vector2( 70, 0 )
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Rect", "Size Flags" ]
|
||||
|
||||
|
22
addons/material_maker/widgets/linked_widgets/link.gd
Normal file
@ -0,0 +1,22 @@
|
||||
extends Node2D
|
||||
|
||||
var end
|
||||
var source = null
|
||||
var target = null
|
||||
|
||||
func closest(rect, point):
|
||||
return Vector2(max(rect.position.x, min(rect.end.x, point.x)), max(rect.position.y, min(rect.end.y, point.y)))
|
||||
|
||||
func _draw():
|
||||
var start = source.rect_global_position+0.5*source.rect_size*source.get_global_transform().get_scale()
|
||||
var color = Color(1, 0.5, 0.5, 0.5)
|
||||
var rect
|
||||
if target != null:
|
||||
color = Color(0.5, 1, 0.5, 0.5)
|
||||
rect = Rect2(target.rect_global_position, target.rect_size*target.get_global_transform().get_scale())
|
||||
draw_rect(rect, color, false)
|
||||
end = closest(rect, start)
|
||||
rect = Rect2(source.rect_global_position, source.rect_size*source.get_global_transform().get_scale())
|
||||
draw_rect(rect, color, false)
|
||||
start = closest(rect, end)
|
||||
draw_line(start, end, color, 1, true)
|
@ -0,0 +1,52 @@
|
||||
tool
|
||||
extends "res://addons/material_maker/widgets/linked_widgets/linked_control_base.gd"
|
||||
|
||||
func add_linked(node, widget):
|
||||
if linked_widgets.empty():
|
||||
var new_widget = null
|
||||
var type
|
||||
if widget is SpinBox:
|
||||
new_widget = SpinBox.new()
|
||||
type = "SpinBox"
|
||||
elif widget is ColorPickerButton:
|
||||
new_widget = ColorPickerButton.new()
|
||||
type = "ColorPickerButton"
|
||||
elif widget is HSlider:
|
||||
new_widget = HSlider.new()
|
||||
type = "HSlider"
|
||||
elif widget is OptionButton:
|
||||
new_widget = OptionButton.new()
|
||||
type = "OptionButton"
|
||||
for i in range(widget.get_item_count()):
|
||||
new_widget.add_item(widget.get_item_text(i), widget.get_item_id(i))
|
||||
if new_widget != null:
|
||||
add_child(new_widget)
|
||||
mirror(new_widget, widget, type)
|
||||
new_widget.connect("mouse_entered", self, "_on_mouse_entered")
|
||||
new_widget.connect("mouse_exited", self, "_on_mouse_exited")
|
||||
new_widget.connect(WIDGETS[type].sig, self, WIDGETS[type].sig_handler)
|
||||
linked_widgets.append({ node=node, widget=widget })
|
||||
|
||||
func mirror(to, from, type):
|
||||
for a in WIDGETS[type].attrs:
|
||||
to.set(a, from.get(a))
|
||||
|
||||
func _on_value_changed(v):
|
||||
for l in linked_widgets:
|
||||
l.widget.value = v
|
||||
l.node.set(l.widget.name, v)
|
||||
|
||||
func _on_color_changed(c):
|
||||
for l in linked_widgets:
|
||||
l.widget.color = c
|
||||
l.node.set(l.widget.name, c)
|
||||
|
||||
func _on_item_selected(i):
|
||||
for l in linked_widgets:
|
||||
l.widget.selected = i
|
||||
l.node.set(l.widget.name, i)
|
||||
|
||||
func serialize():
|
||||
var data = .serialize()
|
||||
data.type = "linked_control"
|
||||
return data
|
@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/material_maker/widgets/linked_widgets/linked_control.gd" type="Script" id=1]
|
||||
|
||||
[node name="LinkedControl" type="VBoxContainer"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
rect_min_size = Vector2( 70, 0 )
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
script = ExtResource( 1 )
|
||||
_sections_unfolded = [ "Rect", "Size Flags" ]
|
||||
|
||||
|
@ -0,0 +1,134 @@
|
||||
tool
|
||||
extends VBoxContainer
|
||||
|
||||
var label = null
|
||||
var buttons = null
|
||||
|
||||
var linked_widgets = []
|
||||
var links = null
|
||||
|
||||
const Link = preload("res://addons/material_maker/widgets/linked_widgets/link.gd")
|
||||
|
||||
const WIDGETS = {
|
||||
SpinBox={ attrs=[ "min_value", "max_value", "step", "value" ], value_attr="value", sig="value_changed", sig_handler="_on_value_changed" },
|
||||
HSlider={ attrs=[ "min_value", "max_value", "step", "value" ], value_attr="value", sig="value_changed", sig_handler="_on_value_changed" },
|
||||
ColorPickerButton={ attrs=[ "edit_alpha", "color" ], value_attr="color", sig="color_changed", sig_handler="_on_color_changed" },
|
||||
OptionButton={ attrs=[ "selected" ], value_attr="selected", sig="item_selected", sig_handler="_on_item_selected" }
|
||||
}
|
||||
|
||||
func get_widget_type(widget):
|
||||
if widget is SpinBox:
|
||||
return "SpinBox"
|
||||
elif widget is ColorPickerButton:
|
||||
return "ColorPickerButton"
|
||||
elif widget is OptionButton:
|
||||
return "OptionButton"
|
||||
else:
|
||||
return null
|
||||
|
||||
func _ready():
|
||||
set_process_input(false)
|
||||
|
||||
func get_associated_controls():
|
||||
label = Label.new()
|
||||
label.set_text("Unnamed")
|
||||
buttons = preload("res://addons/material_maker/widgets/linked_widgets/linked_control_buttons.tscn").instance()
|
||||
buttons.control = self
|
||||
return { label=label, buttons=buttons }
|
||||
|
||||
func delete():
|
||||
var parent = get_parent()
|
||||
label.queue_free()
|
||||
buttons.queue_free()
|
||||
queue_free()
|
||||
|
||||
func _on_mouse_entered():
|
||||
_on_mouse_exited()
|
||||
links = []
|
||||
var viewport = get_viewport()
|
||||
for w in linked_widgets:
|
||||
var link = Link.new()
|
||||
link.source = self
|
||||
link.target = w.widget
|
||||
viewport.add_child(link)
|
||||
links.append(link)
|
||||
|
||||
func _on_mouse_exited():
|
||||
if links != null:
|
||||
for l in links:
|
||||
l.queue_free()
|
||||
links = null
|
||||
|
||||
# Capture mouse to link to a control
|
||||
|
||||
var link = null
|
||||
var graph_edit = null
|
||||
var pointed_control = null
|
||||
|
||||
const Link = preload("res://addons/material_maker/widgets/linked_widgets/link.gd")
|
||||
|
||||
func find_control(gp):
|
||||
for c in graph_edit.get_children():
|
||||
if c is GraphNode:
|
||||
if c.get("property_widgets") != null:
|
||||
for w in c.property_widgets:
|
||||
if Rect2(w.rect_global_position, w.rect_size*w.get_global_transform().get_scale()).has_point(gp):
|
||||
return { node=c, widget=w }
|
||||
return null
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventKey:
|
||||
if event.scancode == KEY_ESCAPE:
|
||||
set_process_input(false)
|
||||
link.queue_free()
|
||||
link = null
|
||||
elif event is InputEventMouseMotion:
|
||||
var control = find_control(event.global_position)
|
||||
link.end = event.global_position
|
||||
link.target = control.widget if control != null else null
|
||||
link.update()
|
||||
elif event is InputEventMouseButton:
|
||||
if event.pressed:
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
var control = find_control(event.global_position)
|
||||
if control != null:
|
||||
add_linked(control.node, control.widget)
|
||||
set_process_input(false)
|
||||
link.queue_free()
|
||||
link = null
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
func pick_linked():
|
||||
# Verify we are in a graph edit
|
||||
graph_edit = get_parent()
|
||||
while graph_edit != null && !(graph_edit is GraphEdit):
|
||||
graph_edit = graph_edit.get_parent()
|
||||
if graph_edit == null:
|
||||
return
|
||||
# Create line that will be shown when looking for a target
|
||||
var viewport = get_viewport()
|
||||
link = Link.new()
|
||||
link.source = self
|
||||
link.end = rect_global_position+0.5*rect_size*get_global_transform().get_scale()
|
||||
viewport.add_child(link)
|
||||
set_process_input(true)
|
||||
pointed_control = null
|
||||
|
||||
func serialize():
|
||||
var data = { linked_widgets=[] }
|
||||
for w in linked_widgets:
|
||||
data.linked_widgets.append( { node=w.node.name, widget=w.widget.name } )
|
||||
return data
|
||||
|
||||
func deserialize(data):
|
||||
if !data.has("linked_widgets"):
|
||||
return
|
||||
var graph_edit = get_parent()
|
||||
while !(graph_edit is GraphEdit):
|
||||
graph_edit = graph_edit.get_parent()
|
||||
for w in data.linked_widgets:
|
||||
var node = graph_edit.get_node(w.node)
|
||||
if node != null && node.get("property_widgets") != null:
|
||||
for widget in node.property_widgets:
|
||||
if widget.name == w.widget:
|
||||
add_linked(node, widget)
|
@ -0,0 +1,15 @@
|
||||
tool
|
||||
extends HBoxContainer
|
||||
|
||||
var control = null
|
||||
|
||||
func _ready():
|
||||
# Called when the node is added to the scene for the first time.
|
||||
# Initialization here
|
||||
pass
|
||||
|
||||
func _on_Link_pressed():
|
||||
control.pick_linked()
|
||||
|
||||
func _on_Remove_pressed():
|
||||
control.delete()
|
@ -0,0 +1,75 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/material_maker/widgets/linked_widgets/linked_control_buttons.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/material_maker/icons/link.png" type="Texture" id=2]
|
||||
[ext_resource path="res://addons/material_maker/icons/remove.png" type="Texture" id=3]
|
||||
|
||||
[node name="Buttons" type="HBoxContainer"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 60.0
|
||||
margin_bottom = 22.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Link" type="Button" parent="." index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 28.0
|
||||
margin_bottom = 22.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
icon = ExtResource( 2 )
|
||||
flat = false
|
||||
align = 1
|
||||
|
||||
[node name="Remove" type="Button" parent="." index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 32.0
|
||||
margin_right = 60.0
|
||||
margin_bottom = 22.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
icon = ExtResource( 3 )
|
||||
flat = false
|
||||
align = 1
|
||||
|
||||
[connection signal="pressed" from="Link" to="." method="_on_Link_pressed"]
|
||||
|
||||
[connection signal="pressed" from="Remove" to="." method="_on_Remove_pressed"]
|
||||
|
||||
|