From 37eb66149685d33ec28e0af98c8216710f0af32a Mon Sep 17 00:00:00 2001 From: Rodolphe Suescun Date: Tue, 7 Aug 2018 23:21:12 +0200 Subject: [PATCH] Basic library editing + shortcuts Added simple functions to add nodes to the user library and save it. Added keyboard shortcuts for main menu. --- .gitignore | 1 + addons/procedural_material/library.gd | 41 ++++- addons/procedural_material/main_window.gd | 63 +++++-- addons/procedural_material/main_window.tscn | 4 +- .../widgets/line_dialog.gd | 10 ++ .../widgets/line_dialog.tscn | 154 ++++++++++++++++++ examples/crocodile_skin.ptex | 1 + examples/floor2.ptex | 1 + 8 files changed, 258 insertions(+), 17 deletions(-) create mode 100644 addons/procedural_material/widgets/line_dialog.gd create mode 100644 addons/procedural_material/widgets/line_dialog.tscn create mode 100644 examples/crocodile_skin.ptex create mode 100644 examples/floor2.ptex diff --git a/.gitignore b/.gitignore index 29898b9..cbda340 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ examples/input_image.png.import *.import *.import *.import +/addons/procedural_material/nodes/godot_logo.png.import diff --git a/addons/procedural_material/library.gd b/addons/procedural_material/library.gd index 9be5d13..801a66c 100644 --- a/addons/procedural_material/library.gd +++ b/addons/procedural_material/library.gd @@ -24,7 +24,7 @@ func get_drag_data(position): func _ready(): var root = create_item() add_library("res://addons/procedural_material/library/base.json") - add_library("res://addons/procedural_material/library/user.json") + add_library("user://library/user.json") func add_library(filename): var root = get_root() @@ -35,13 +35,24 @@ func add_library(filename): file.close() for m in lib.lib: m.library = filename - add_item(m, m.tree_item, root) + add_item(m, m.tree_item) -func add_item(item, item_name, item_parent): +func add_item(item, item_name, item_parent = null): + if item_parent == null: + item.tree_item = item_name + item_parent = get_root() var slash_position = item_name.find("/") if slash_position == -1: - var new_item = create_item(item_parent) - new_item.set_text(0, item_name) + var new_item = null + var c = item_parent.get_children() + while c != null: + if c.get_text(0) == item_name: + new_item = c + break + c = c.get_next() + if new_item == null: + new_item = create_item(item_parent) + new_item.set_text(0, item_name) new_item.set_metadata(0, item) return new_item else: @@ -58,3 +69,23 @@ func add_item(item, item_name, item_parent): new_parent = create_item(item_parent) new_parent.set_text(0, prefix) return add_item(item, suffix, new_parent) + +func serialize_library(array, library_name, item = null): + if item == null: + item = get_root() + item = item.get_children() + while item != null: + var m = item.get_metadata(0) + if m != null && m.has("library") and m.library == library_name: + array.append(m) + serialize_library(array, library_name, item) + item = item.get_next() + +func save_library(library_name, item = null): + var array = [] + serialize_library(array, library_name) + print("Saving library "+library_name) + var file = File.new() + if file.open(library_name, File.WRITE) == OK: + file.store_string(to_json({lib=array})) + file.close() diff --git a/addons/procedural_material/main_window.gd b/addons/procedural_material/main_window.gd index 6925e69..feb5a6d 100644 --- a/addons/procedural_material/main_window.gd +++ b/addons/procedural_material/main_window.gd @@ -4,17 +4,19 @@ var current_tab = -1 const MENU = [ { menu="File", command="new_material", description="New material" }, - { menu="File", command="load_material", description="Load material" }, + { menu="File", command="load_material", shortcut="Control+O", description="Load material" }, { menu="File" }, - { menu="File", command="save_material", description="Save material" }, - { menu="File", command="save_material_as", description="Save material as..." }, + { menu="File", command="save_material", shortcut="Control+S", description="Save material" }, + { menu="File", command="save_material_as", shortcut="Control+Shift+S", description="Save material as..." }, { menu="File", command="save_all_materials", description="Save all materials..." }, { menu="File" }, - { menu="File", command="export_material", description="Export material" }, + { menu="File", command="export_material", shortcut="Control+E", description="Export material" }, { menu="File" }, { menu="File", command="close_material", description="Close material" }, - { menu="File", command="exit", description="Exit" }, + { menu="File", command="quit", shortcut="Control+Q", description="Quit" }, { menu="Tools", command="save_icons", description="Save icons for selected nodes" }, + { menu="Tools", command="add_to_user_library", description="Add selected node to user library" }, + { menu="Tools", command="save_user_library", description="Save user library" }, { menu="Help", command="about", description="About" } ] @@ -33,7 +35,18 @@ func create_menu(menu, menu_name): menu.add_child(submenu) menu.add_submenu_item(MENU[i].description, submenu.get_name()) elif MENU[i].has("description"): - menu.add_item(MENU[i].description, i) + var shortcut = 0 + if MENU[i].has("shortcut"): + for s in MENU[i].shortcut.split("+"): + if s == "Alt": + shortcut |= KEY_MASK_ALT + elif s == "Control": + shortcut |= KEY_MASK_CTRL + elif s == "Shift": + shortcut |= KEY_MASK_SHIFT + else: + shortcut |= OS.find_scancode_from_string(s) + menu.add_item(MENU[i].description, i, shortcut) else: menu.add_separator() return menu @@ -73,12 +86,40 @@ func close_material(): func save_icons(): var graphedit = $VBoxContainer/HBoxContainer/Projects.get_current_tab_control() - for n in graphedit.get_children(): - if n is GraphNode and n.selected: - graphedit.export_texture(n, "res://addons/procedural_material/library/icons/"+n.name+".png", 64) + if graphedit != null and graphedit is GraphEdit: + for n in graphedit.get_children(): + if n is GraphNode and n.selected: + graphedit.export_texture(n, "res://addons/procedural_material/library/icons/"+n.name+".png", 64) -func exit(): - queue_free() +func add_to_user_library(): + var graphedit = $VBoxContainer/HBoxContainer/Projects.get_current_tab_control() + if graphedit != null and graphedit is GraphEdit: + for n in graphedit.get_children(): + if n is GraphNode and n.selected: + var dialog = preload("res://addons/procedural_material/widgets/line_dialog.tscn").instance() + add_child(dialog) + dialog.connect("ok", self, "do_add_to_user_library", [n]) + dialog.popup_centered() + break + +func do_add_to_user_library(name, node): + var data = node.serialize() + var dir = Directory.new() + dir.make_dir("user://library") + dir.make_dir("user://library/user") + data.erase("node_position") + data.library = "user://library/user.json" + data.icon = name.right(name.rfind("/")+1).to_lower() + $VBoxContainer/HBoxContainer/VBoxContainer/Library.add_item(data, name) + var graphedit = $VBoxContainer/HBoxContainer/Projects.get_current_tab_control() + graphedit.export_texture(node, "user://library/user/"+data.icon+".png", 64) + +func save_user_library(): + print("Saving user library") + $VBoxContainer/HBoxContainer/VBoxContainer/Library.save_library("user://library/user.json") + +func quit(): + get_tree().quit() func _on_PopupMenu_id_pressed(id): var node_type = null diff --git a/addons/procedural_material/main_window.tscn b/addons/procedural_material/main_window.tscn index 30c3013..f3e47ee 100644 --- a/addons/procedural_material/main_window.tscn +++ b/addons/procedural_material/main_window.tscn @@ -4,7 +4,7 @@ [ext_resource path="res://addons/procedural_material/library.gd" type="Script" id=2] [ext_resource path="res://addons/procedural_material/preview.tscn" type="PackedScene" id=3] -[node name="MainWindow" type="Panel"] +[node name="MainWindow" type="Panel" index="0"] anchor_left = 0.0 anchor_top = 0.0 @@ -244,4 +244,6 @@ _sections_unfolded = [ "Size Flags" ] [connection signal="tab_changed" from="VBoxContainer/HBoxContainer/Projects" to="." method="_on_Projects_tab_changed"] +[connection signal="tab_selected" from="VBoxContainer/HBoxContainer/Projects" to="." method="_on_Projects_tab_changed"] + diff --git a/addons/procedural_material/widgets/line_dialog.gd b/addons/procedural_material/widgets/line_dialog.gd new file mode 100644 index 0000000..5dd23ee --- /dev/null +++ b/addons/procedural_material/widgets/line_dialog.gd @@ -0,0 +1,10 @@ +extends WindowDialog + +signal ok + +func _ready(): + pass + +func _on_OK_pressed(): + emit_signal("ok", $VBoxContainer/LineEdit.text) + queue_free() diff --git a/addons/procedural_material/widgets/line_dialog.tscn b/addons/procedural_material/widgets/line_dialog.tscn new file mode 100644 index 0000000..9344b33 --- /dev/null +++ b/addons/procedural_material/widgets/line_dialog.tscn @@ -0,0 +1,154 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/procedural_material/widgets/line_dialog.gd" type="Script" id=1] + +[node name="LineDialog" type="WindowDialog"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 332.0 +margin_bottom = 72.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +popup_exclusive = false +window_title = "New library element" +resizable = false +script = ExtResource( 1 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="." index="1"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 1.0 +anchor_bottom = 1.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="Label" type="Label" parent="VBoxContainer" index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 332.0 +margin_bottom = 14.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "Select a name for the new library element" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="LineEdit" type="LineEdit" parent="VBoxContainer" index="1"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_top = 18.0 +margin_right = 332.0 +margin_bottom = 42.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 1 +size_flags_horizontal = 1 +size_flags_vertical = 1 +focus_mode = 2 +context_menu_enabled = true +placeholder_alpha = 0.6 +caret_blink = false +caret_blink_speed = 0.65 +caret_position = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer" index="2"] + +anchor_left = 0.5 +anchor_top = 0.0 +anchor_right = 0.5 +anchor_bottom = 0.0 +margin_left = -62.0 +margin_top = 49.0 +margin_right = 62.0 +margin_bottom = 69.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 1 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +alignment = 0 +_sections_unfolded = [ "Size Flags" ] + +[node name="OK" type="Button" parent="VBoxContainer/HBoxContainer" index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 60.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 60, 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 +text = "OK" +flat = false +align = 1 +_sections_unfolded = [ "Rect" ] + +[node name="Cancel" type="Button" parent="VBoxContainer/HBoxContainer" index="1"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 64.0 +margin_right = 124.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 60, 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 +text = "Cancel" +flat = false +align = 1 +_sections_unfolded = [ "Rect" ] + +[connection signal="pressed" from="VBoxContainer/HBoxContainer/OK" to="." method="_on_OK_pressed"] + +[connection signal="pressed" from="VBoxContainer/HBoxContainer/Cancel" to="." method="queue_free"] + + diff --git a/examples/crocodile_skin.ptex b/examples/crocodile_skin.ptex new file mode 100644 index 0000000..f721196 --- /dev/null +++ b/examples/crocodile_skin.ptex @@ -0,0 +1 @@ +{"connections":[{"from":"voronoi_0","from_port":0,"to":"colorize_0","to_port":0},{"from":"colorize_0","from_port":0,"to":"normal_map_0","to_port":0},{"from":"normal_map_0","from_port":0,"to":"Material","to_port":4},{"from":"voronoi_0","from_port":0,"to":"colorize_1","to_port":0},{"from":"colorize_1","from_port":0,"to":"Material","to_port":0},{"from":"colorize_2","from_port":0,"to":"Material","to_port":1},{"from":"voronoi_0","from_port":0,"to":"colorize_2","to_port":0},{"from":"voronoi_0","from_port":0,"to":"colorize_3","to_port":0},{"from":"colorize_3","from_port":0,"to":"Material","to_port":2}],"nodes":[{"name":"Material","node_position":{"x":674,"y":164},"type":"material"},{"intensity":0.4,"name":"voronoi_0","node_position":{"x":72,"y":212},"scale_x":16,"scale_y":16,"type":"voronoi"},{"gradient":[{"b":0.010715,"g":0.411458,"pos":0,"r":0.22361},{"b":0,"g":1,"pos":1,"r":0.9375}],"name":"colorize_1","node_position":{"x":384,"y":137},"type":"colorize"},{"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":0,"g":0,"pos":1,"r":0}],"name":"colorize_2","node_position":{"x":384,"y":197},"type":"colorize"},{"gradient":[{"b":0.505208,"g":0.505208,"pos":0,"r":0.505208},{"b":0.78125,"g":0.78125,"pos":1,"r":0.78125}],"name":"colorize_3","node_position":{"x":384,"y":258},"type":"colorize"},{"gradient":[{"b":0,"g":0,"pos":0,"r":0},{"b":0.5,"g":0.5,"pos":0.363636,"r":0.5},{"b":1,"g":1,"pos":0.618182,"r":1}],"name":"colorize_0","node_position":{"x":298,"y":317},"type":"colorize"},{"amount":0.5,"name":"normal_map_0","node_position":{"x":478,"y":319},"type":"normal_map"}]} \ No newline at end of file diff --git a/examples/floor2.ptex b/examples/floor2.ptex new file mode 100644 index 0000000..cec444b --- /dev/null +++ b/examples/floor2.ptex @@ -0,0 +1 @@ +{"connections":[{"from":"perlin_0","from_port":0,"to":"colorize_0","to_port":0},{"from":"colorize_0","from_port":0,"to":"blend_0","to_port":1},{"from":"bricks_0","from_port":0,"to":"blend_0","to_port":0},{"from":"blend_0","from_port":0,"to":"Material","to_port":0},{"from":"colorize_2","from_port":0,"to":"Material","to_port":1},{"from":"bricks_0","from_port":0,"to":"normal_map_0","to_port":0},{"from":"normal_map_0","from_port":0,"to":"Material","to_port":4},{"from":"colorize_1","from_port":0,"to":"Material","to_port":2},{"from":"bricks_0","from_port":0,"to":"colorize_2","to_port":0},{"from":"blend_0","from_port":0,"to":"colorize_1","to_port":0}],"nodes":[{"amount":1,"blend_type":2,"name":"blend_0","node_position":{"x":450,"y":198},"type":"blend"},{"name":"Material","node_position":{"x":773,"y":290},"type":"material"},{"iterations":7,"name":"perlin_0","node_position":{"x":7,"y":263},"persistence":0.85,"scale_x":8,"scale_y":8,"type":"perlin"},{"bevel":0.01,"columns":4,"mortar":0.01,"name":"bricks_0","node_position":{"x":242,"y":382},"row_offset":0,"rows":4,"type":"bricks"},{"amount":0.2,"name":"normal_map_0","node_position":{"x":516,"y":466},"type":"normal_map"},{"gradient":[{"b":1,"g":1,"pos":0,"r":1},{"b":0.484375,"g":0.484375,"pos":1,"r":0.484375}],"name":"colorize_1","node_position":{"x":510,"y":386},"type":"colorize"},{"gradient":[{"b":0.302083,"g":0.302083,"pos":0,"r":0.302083},{"b":0.338542,"g":0.338542,"pos":1,"r":0.338542}],"name":"colorize_2","node_position":{"x":508,"y":315},"type":"colorize"},{"gradient":[{"b":0.588542,"g":0.742839,"pos":0,"r":1},{"b":1,"g":1,"pos":0.672727,"r":1}],"name":"colorize_0","node_position":{"x":232,"y":286},"type":"colorize"}]} \ No newline at end of file