diff --git a/addons/m_terrain/LICENSE b/addons/m_terrain/LICENSE deleted file mode 100644 index e612191..0000000 --- a/addons/m_terrain/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 mohsenph69 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/addons/m_terrain/README.md b/addons/m_terrain/README.md deleted file mode 100644 index 91e3535..0000000 --- a/addons/m_terrain/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# godot M Terrain Plugin - -![Screenshot_20230707_104154](https://github.com/mohsenph69/Godot-MTerrain-plugin/assets/52196206/7e3eb7da-af57-4ae5-8f55-f9fc1c8b26f8) - - -## Please read before using this plugin -Using this plugin require to learn some concept about terrain, This terrain plugin will not work out of the box, so I really suggest to read the [wiki](https://github.com/mohsenph69/Godot-MTerrain-plugin/wiki/) which I add recently added, I will add more stuff to wiki but for now I wrote the main concept that you need to know. - -Also watching this video will be helpful: -https://www.youtube.com/watch?v=PcAkWClET4U - -And then this video shows how to use use height brushes to modifying the terrain: -https://www.youtube.com/watch?v=e7nplXnemGo - -Video about Texture painting: -https://www.youtube.com/watch?v=0zEYzKEMWR8 - -## patreon - -You can support me with patreon [Click here](https://patreon.com/mohsenzare?utm_medium=clipboard_copy&utm_source=copyLink&utm_campaign=creatorshare_creator&utm_content=join_link) - -## Features - -* Tested with terrrain up to size 16km X 16 km -* Supporting grass system Even with collission for things like trees (Grass is paintable) -* Suppoting baking navigation system from terrain (navigation mesh is paintable) -* Terrain sculptur -* Color brush which support different algorithm (splatmapping, bitwise, index mapping ...) - -![Screenshot_20230719_144752](https://github.com/mohsenph69/Godot-MTerrain-plugin/assets/52196206/704c51a8-7554-4345-907b-efc635a67dd0) - - -## download -To downalod the latest release use this link: -https://github.com/mohsenph69/Godot-MTerrain-plugin/releases - -![Screenshot_20230719_144757](https://github.com/mohsenph69/Godot-MTerrain-plugin/assets/52196206/ef78652f-c4cc-4226-948e-9f4e44bb1af8) - -## build by yourself -First clone this repo on your local machine, so you need godot-cpp to exist in GDExtension folder so you can build that, godot-cpp is added as a submodule in this project so to put that inside GDExtension folder only thing you need to do after cloning this repo is runing this code -``` -git submodule update --init --recursive -``` -This will automaticly pull godot-cpp into GDextension folder, After that go inside GDExtension folder and use scons to build this project diff --git a/addons/m_terrain/brush_masks/01.exr b/addons/m_terrain/brush_masks/01.exr deleted file mode 100644 index a218236..0000000 Binary files a/addons/m_terrain/brush_masks/01.exr and /dev/null differ diff --git a/addons/m_terrain/brush_masks/01.exr.import b/addons/m_terrain/brush_masks/01.exr.import deleted file mode 100644 index 8dd0c09..0000000 --- a/addons/m_terrain/brush_masks/01.exr.import +++ /dev/null @@ -1,3 +0,0 @@ -[remap] - -importer="keep" diff --git a/addons/m_terrain/brush_masks/02.exr b/addons/m_terrain/brush_masks/02.exr deleted file mode 100644 index 7c9a5ac..0000000 Binary files a/addons/m_terrain/brush_masks/02.exr and /dev/null differ diff --git a/addons/m_terrain/brush_masks/02.exr.import b/addons/m_terrain/brush_masks/02.exr.import deleted file mode 100644 index 8dd0c09..0000000 --- a/addons/m_terrain/brush_masks/02.exr.import +++ /dev/null @@ -1,3 +0,0 @@ -[remap] - -importer="keep" diff --git a/addons/m_terrain/brush_masks/03.exr b/addons/m_terrain/brush_masks/03.exr deleted file mode 100644 index 7253f6c..0000000 Binary files a/addons/m_terrain/brush_masks/03.exr and /dev/null differ diff --git a/addons/m_terrain/brush_masks/03.exr.import b/addons/m_terrain/brush_masks/03.exr.import deleted file mode 100644 index 8dd0c09..0000000 --- a/addons/m_terrain/brush_masks/03.exr.import +++ /dev/null @@ -1,3 +0,0 @@ -[remap] - -importer="keep" diff --git a/addons/m_terrain/brush_masks/04.exr b/addons/m_terrain/brush_masks/04.exr deleted file mode 100644 index b5cfb3c..0000000 Binary files a/addons/m_terrain/brush_masks/04.exr and /dev/null differ diff --git a/addons/m_terrain/brush_masks/04.exr.import b/addons/m_terrain/brush_masks/04.exr.import deleted file mode 100644 index 8dd0c09..0000000 --- a/addons/m_terrain/brush_masks/04.exr.import +++ /dev/null @@ -1,3 +0,0 @@ -[remap] - -importer="keep" diff --git a/addons/m_terrain/brush_masks/05.exr b/addons/m_terrain/brush_masks/05.exr deleted file mode 100644 index 4596adb..0000000 Binary files a/addons/m_terrain/brush_masks/05.exr and /dev/null differ diff --git a/addons/m_terrain/brush_masks/05.exr.import b/addons/m_terrain/brush_masks/05.exr.import deleted file mode 100644 index 8dd0c09..0000000 --- a/addons/m_terrain/brush_masks/05.exr.import +++ /dev/null @@ -1,3 +0,0 @@ -[remap] - -importer="keep" diff --git a/addons/m_terrain/brush_masks/06.png b/addons/m_terrain/brush_masks/06.png deleted file mode 100644 index f4ffd09..0000000 Binary files a/addons/m_terrain/brush_masks/06.png and /dev/null differ diff --git a/addons/m_terrain/brush_masks/06.png.import b/addons/m_terrain/brush_masks/06.png.import deleted file mode 100644 index 8dd0c09..0000000 --- a/addons/m_terrain/brush_masks/06.png.import +++ /dev/null @@ -1,3 +0,0 @@ -[remap] - -importer="keep" diff --git a/addons/m_terrain/debug_mat/lod0.material b/addons/m_terrain/debug_mat/lod0.material deleted file mode 100644 index aba3212..0000000 Binary files a/addons/m_terrain/debug_mat/lod0.material and /dev/null differ diff --git a/addons/m_terrain/debug_mat/lod1.material b/addons/m_terrain/debug_mat/lod1.material deleted file mode 100644 index 0113787..0000000 Binary files a/addons/m_terrain/debug_mat/lod1.material and /dev/null differ diff --git a/addons/m_terrain/debug_mat/lod2.material b/addons/m_terrain/debug_mat/lod2.material deleted file mode 100644 index 73a25c5..0000000 Binary files a/addons/m_terrain/debug_mat/lod2.material and /dev/null differ diff --git a/addons/m_terrain/debug_mat/lod3.material b/addons/m_terrain/debug_mat/lod3.material deleted file mode 100644 index c840ca4..0000000 Binary files a/addons/m_terrain/debug_mat/lod3.material and /dev/null differ diff --git a/addons/m_terrain/debug_mat/lod4.material b/addons/m_terrain/debug_mat/lod4.material deleted file mode 100644 index ee0343c..0000000 Binary files a/addons/m_terrain/debug_mat/lod4.material and /dev/null differ diff --git a/addons/m_terrain/debug_mat/lod5.material b/addons/m_terrain/debug_mat/lod5.material deleted file mode 100644 index 1a79fac..0000000 Binary files a/addons/m_terrain/debug_mat/lod5.material and /dev/null differ diff --git a/addons/m_terrain/debug_mat/lod_debug.gdshader b/addons/m_terrain/debug_mat/lod_debug.gdshader deleted file mode 100644 index 1f7e4de..0000000 --- a/addons/m_terrain/debug_mat/lod_debug.gdshader +++ /dev/null @@ -1,15 +0,0 @@ -shader_type spatial; -render_mode unshaded; - -uniform sampler2D lod_num_tex; - - -float rand(float seed) -{ - return fract((sin(seed + 78.233)) * 43758.5453); -} - -void fragment() { - ALBEDO = texture(lod_num_tex, UV).rgb; - ALBEDO += vec3(0.3,0.3,0.0); -} diff --git a/addons/m_terrain/debug_tex/lod0.png b/addons/m_terrain/debug_tex/lod0.png deleted file mode 100644 index a48b2c3..0000000 Binary files a/addons/m_terrain/debug_tex/lod0.png and /dev/null differ diff --git a/addons/m_terrain/debug_tex/lod0.png.import b/addons/m_terrain/debug_tex/lod0.png.import deleted file mode 100644 index fe4ff3a..0000000 --- a/addons/m_terrain/debug_tex/lod0.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cfk6j7y80p1r5" -path.s3tc="res://.godot/imported/lod0.png-2880393a436cd3c8931bfde964c1671d.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/debug_tex/lod0.png" -dest_files=["res://.godot/imported/lod0.png-2880393a436cd3c8931bfde964c1671d.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/debug_tex/lod1.png b/addons/m_terrain/debug_tex/lod1.png deleted file mode 100644 index 709df86..0000000 Binary files a/addons/m_terrain/debug_tex/lod1.png and /dev/null differ diff --git a/addons/m_terrain/debug_tex/lod1.png.import b/addons/m_terrain/debug_tex/lod1.png.import deleted file mode 100644 index 1f02ff4..0000000 --- a/addons/m_terrain/debug_tex/lod1.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bluulxv0tx4jb" -path.s3tc="res://.godot/imported/lod1.png-c254a6922d8a9723c9998e75366ea575.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/debug_tex/lod1.png" -dest_files=["res://.godot/imported/lod1.png-c254a6922d8a9723c9998e75366ea575.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/debug_tex/lod2.png b/addons/m_terrain/debug_tex/lod2.png deleted file mode 100644 index 6ca8ffe..0000000 Binary files a/addons/m_terrain/debug_tex/lod2.png and /dev/null differ diff --git a/addons/m_terrain/debug_tex/lod2.png.import b/addons/m_terrain/debug_tex/lod2.png.import deleted file mode 100644 index d0df601..0000000 --- a/addons/m_terrain/debug_tex/lod2.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://qyrkuppxph0m" -path.s3tc="res://.godot/imported/lod2.png-b829479da68243e51b62618555583f20.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/debug_tex/lod2.png" -dest_files=["res://.godot/imported/lod2.png-b829479da68243e51b62618555583f20.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/debug_tex/lod3.png b/addons/m_terrain/debug_tex/lod3.png deleted file mode 100644 index 8450a34..0000000 Binary files a/addons/m_terrain/debug_tex/lod3.png and /dev/null differ diff --git a/addons/m_terrain/debug_tex/lod3.png.import b/addons/m_terrain/debug_tex/lod3.png.import deleted file mode 100644 index 2530088..0000000 --- a/addons/m_terrain/debug_tex/lod3.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b8b55qsiyofsm" -path.s3tc="res://.godot/imported/lod3.png-ac98cf64ed7f0102a59e60cf472d2055.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/debug_tex/lod3.png" -dest_files=["res://.godot/imported/lod3.png-ac98cf64ed7f0102a59e60cf472d2055.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/debug_tex/lod4.png b/addons/m_terrain/debug_tex/lod4.png deleted file mode 100644 index 430fe3d..0000000 Binary files a/addons/m_terrain/debug_tex/lod4.png and /dev/null differ diff --git a/addons/m_terrain/debug_tex/lod4.png.import b/addons/m_terrain/debug_tex/lod4.png.import deleted file mode 100644 index e77374c..0000000 --- a/addons/m_terrain/debug_tex/lod4.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b1gi2dlb8hecg" -path.s3tc="res://.godot/imported/lod4.png-7dff36e303e22a5be9f22591fbb927b6.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/debug_tex/lod4.png" -dest_files=["res://.godot/imported/lod4.png-7dff36e303e22a5be9f22591fbb927b6.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/debug_tex/lod5.png b/addons/m_terrain/debug_tex/lod5.png deleted file mode 100644 index e6222eb..0000000 Binary files a/addons/m_terrain/debug_tex/lod5.png and /dev/null differ diff --git a/addons/m_terrain/debug_tex/lod5.png.import b/addons/m_terrain/debug_tex/lod5.png.import deleted file mode 100644 index 17676f6..0000000 --- a/addons/m_terrain/debug_tex/lod5.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bqhwxkuvy417g" -path.s3tc="res://.godot/imported/lod5.png-b130561880fcd505fffeeaef4ab7d246.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/debug_tex/lod5.png" -dest_files=["res://.godot/imported/lod5.png-b130561880fcd505fffeeaef4ab7d246.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/default_lod_setting.res b/addons/m_terrain/default_lod_setting.res deleted file mode 100644 index 34dbc80..0000000 Binary files a/addons/m_terrain/default_lod_setting.res and /dev/null differ diff --git a/addons/m_terrain/gizmos/mcurve_mesh_gui.gd b/addons/m_terrain/gizmos/mcurve_mesh_gui.gd deleted file mode 100644 index af4451d..0000000 --- a/addons/m_terrain/gizmos/mcurve_mesh_gui.gd +++ /dev/null @@ -1,169 +0,0 @@ -@tool -extends BoxContainer - -@onready var active_btn:=$active -@onready var segment_select_option:=$segment_select -@onready var socket_select_option:=$socket_select -var selection:EditorSelection - -var obj:MCurveMesh - -var instance_rid:RID -var scenario:RID - -var active_root_scene:Node -var sockets_gizmos:Array -var selected_socket:int = -1 - - -func _init(): - instance_rid = RenderingServer.instance_create() - var ed := EditorScript.new() - selection = ed.get_editor_interface().get_selection() - selection.selection_changed.connect(selection_changed) - -func _enter_tree(): - update_scenario() - -func _exit_tree(): - if instance_rid.is_valid(): - RenderingServer.free_rid(instance_rid) - -func set_curve_mesh(input:MCurveMesh): - if not input and is_active(): - return - obj = input - udpate_sockets_gizmos() - socket_select_option.clear() - segment_select_option.clear() - if not obj or not active_btn.button_pressed: - visible = obj != null - set_process(false) - update_mesh() - return - visible = true - set_process(true) - active_root_scene = get_root_scene() - for i in range(0,obj.intersections.size()): - var seg:MIntersection = obj.intersections[i] - segment_select_option.add_item("Seg "+str(i),i) - if obj.intersections.size() >= 1: - _on_segment_select_item_selected(0) - segment_select_option.select(0) - update_scenario() - update_mesh() - -func _on_segment_select_item_selected(index): - udpate_sockets_gizmos() - socket_select_option.clear() - update_mesh() - if index >= obj.intersections.size(): return - var seg:MIntersection = obj.intersections[index] - if not seg: return - var socket = seg.sockets - for i in range(0,socket.size()): - socket_select_option.add_item("Socket "+str(i)) - if socket.size() > 0: - socket_select_option.select(0) - _on_socket_select_item_selected(0) - -func _on_socket_select_item_selected(index): - if index < 0 or index >= sockets_gizmos.size(): - return - selected_socket = index - selection.clear() - selection.add_node(sockets_gizmos[index]) - -func _on_active_toggled(button_pressed): - set_curve_mesh(obj) - segment_select_option.visible = button_pressed - socket_select_option.visible = button_pressed - if not button_pressed and obj: - selection.clear() - selection.add_node(obj) - -func update_mesh(): - RenderingServer.instance_set_base(instance_rid,RID()) - if not obj: return - var seg_index:int = segment_select_option.selected - if seg_index >= obj.intersections.size() or seg_index < 0: return - var seg:MIntersection = obj.intersections[seg_index] - if not seg: return - var mesh_lod:MMeshLod = seg.mesh - if not mesh_lod: return - var mesh:Mesh = null - for m in mesh_lod.meshes: - if m: - mesh = m - break - if not mesh: return - RenderingServer.instance_set_base(instance_rid,mesh.get_rid()) - -func get_root_scene()->Node: - var ed = EditorScript.new() - var scene = ed.get_scene() - return scene - -func update_scenario(): - var scene = get_root_scene() - if not scene:return - if scene is Node3D: - var w3d = scene.get_world_3d() - if w3d: - RenderingServer.instance_set_scenario(instance_rid,w3d.scenario) - -func udpate_sockets_gizmos(): - for s in sockets_gizmos: - s.queue_free() - sockets_gizmos.clear() - if not active_btn.button_pressed: return - if not obj: return - var seg_index:int = segment_select_option.selected - if seg_index >= obj.intersections.size(): return - var seg:MIntersection = obj.intersections[seg_index] - if not seg: return - var ed = EditorScript.new() - var scene = ed.get_scene() - if not scene:return - for socket in seg.sockets: - var marker = Marker3D.new() - scene.add_child(marker) - marker.global_transform = socket - sockets_gizmos.push_back(marker) - -func is_active(): - return active_btn.button_pressed - -func _on_visibility_changed(): - if active_btn and not visible: - active_btn.button_pressed = false - -func selection_changed(): - if not is_active(): return - if selected_socket < 0 or selected_socket >= sockets_gizmos.size(): return - if active_root_scene != get_root_scene(): - active_btn.button_pressed = false - set_curve_mesh(null) - return - var socket_marker = sockets_gizmos[selected_socket] - var sel := selection.get_selected_nodes() - if sel.size() > 1: - selection.clear() - selection.add_node(socket_marker) - return - if sel.size() == 1: - if sel[0] != socket_marker: - selection.clear() - selection.add_node(socket_marker) - if sel.size() == 0: - selection.clear() - selection.add_node(socket_marker) - -func _process(delta): - if not obj: return - var seg_index = segment_select_option.get_selected_id() - var socket_index = socket_select_option.get_selected_id() - if socket_index < 0 or socket_index >= sockets_gizmos.size(): return - var marker = sockets_gizmos[socket_index] - var t:Transform3D = marker.global_transform - obj.intersections[seg_index].sockets[socket_index] = t diff --git a/addons/m_terrain/gizmos/mcurve_mesh_gui.tscn b/addons/m_terrain/gizmos/mcurve_mesh_gui.tscn deleted file mode 100644 index 775eda2..0000000 --- a/addons/m_terrain/gizmos/mcurve_mesh_gui.tscn +++ /dev/null @@ -1,28 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://b76ioum2i7yjy"] - -[ext_resource type="Script" path="res://addons/m_terrain/gizmos/mcurve_mesh_gui.gd" id="1_16uhh"] - -[node name="mcurve_mesh" type="HBoxContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_16uhh") - -[node name="active" type="CheckBox" parent="."] -layout_mode = 2 -text = "Modify" - -[node name="segment_select" type="OptionButton" parent="."] -visible = false -layout_mode = 2 - -[node name="socket_select" type="OptionButton" parent="."] -visible = false -layout_mode = 2 - -[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"] -[connection signal="toggled" from="active" to="." method="_on_active_toggled"] -[connection signal="item_selected" from="segment_select" to="." method="_on_segment_select_item_selected"] -[connection signal="item_selected" from="socket_select" to="." method="_on_socket_select_item_selected"] diff --git a/addons/m_terrain/gizmos/moct_mesh_gizmo.gd b/addons/m_terrain/gizmos/moct_mesh_gizmo.gd deleted file mode 100644 index db18447..0000000 --- a/addons/m_terrain/gizmos/moct_mesh_gizmo.gd +++ /dev/null @@ -1,93 +0,0 @@ -extends EditorNode3DGizmoPlugin - - -var selection:EditorSelection -var sel_line_mat:StandardMaterial3D -var selected_mesh:Array - -func _init(): - var ed = EditorScript.new() - var interface = ed.get_editor_interface() - selection = interface.get_selection() - sel_line_mat = StandardMaterial3D.new() - sel_line_mat.albedo_color = Color(0.2,0.2,0.8) - sel_line_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - selection.selection_changed.connect(on_selection_change) - - -func _redraw(gizmo: EditorNode3DGizmo) -> void: - gizmo.clear() - var node:MOctMesh= gizmo.get_node_3d() - var amesh:Mesh = node.get_active_mesh() - if amesh: - var tm = amesh.generate_triangle_mesh() - gizmo.add_collision_triangles(tm) - if selection.get_selected_nodes().has(node): - var aabb = amesh.get_aabb() - aabb.position -= Vector3(0.02,0.02,0.02) - aabb.size += Vector3(0.04,0.04,0.04) - var s = aabb.position - var e = aabb.size + s - var l:PackedVector3Array - l.resize(24) - l[0] = s - l[1] = Vector3(e.x,s.y,s.z) - l[2] = s - l[3] = Vector3(s.x,e.y,s.z) - l[4] = s - l[5] = Vector3(s.x,s.y,e.z) - l[6] = e - l[7] = Vector3(e.x,s.y,e.z) - l[8] = e - l[9] = Vector3(s.x,e.y,e.z) - l[10] = e - l[11] = Vector3(e.x,e.y,s.z) - l[12] = Vector3(e.x,e.y,s.z) - l[13] = Vector3(e.x,s.y,s.z) - l[14] = Vector3(e.x,s.y,s.z) - l[15] = Vector3(e.x,s.y,e.z) - l[16] = Vector3(s.x,s.y,e.z) - l[17] = Vector3(s.x,e.y,e.z) - l[18] = Vector3(s.x,e.y,e.z) - l[19] = Vector3(s.x,e.y,s.z) - l[20] = Vector3(s.x,e.y,s.z) - l[21] = Vector3(e.x,e.y,s.z) - l[22] = Vector3(e.x,s.y,e.z) - l[23] = Vector3(s.x,s.y,e.z) - gizmo.add_lines(l,sel_line_mat,false) - -func _get_handle_name(gizmo, handle_id, secondary): - return - -func _get_handle_value(gizmo: EditorNode3DGizmo, _id: int, _secondary: bool): - return - -func _set_handle(gizmo, handle_id, secondary, camera, screen_pos): - return - - - -func _get_gizmo_name(): - return "MOctMesh_Gizmo" - -func _get_priority(): - return -1 - -func _has_gizmo(for_node_3d): - return for_node_3d.is_class("MOctMesh") - -func on_selection_change(): - var snodes = selection.get_selected_nodes() - var i = selected_mesh.size() - 1 - while i >= 0: - var find = snodes.find(selected_mesh[i]) - if find == -1: - if is_instance_valid(selected_mesh[i]): - selected_mesh[i].update_gizmos() - selected_mesh.remove_at(i) - i-=1 - for n in snodes: - if n.is_class("MOctMesh") and n.is_inside_tree(): - n.update_gizmos() - if not selected_mesh.has(n): - selected_mesh.push_back(n) diff --git a/addons/m_terrain/gizmos/mpath_gizmo.gd b/addons/m_terrain/gizmos/mpath_gizmo.gd deleted file mode 100644 index eadd08a..0000000 --- a/addons/m_terrain/gizmos/mpath_gizmo.gd +++ /dev/null @@ -1,1194 +0,0 @@ -@tool -extends EditorNode3DGizmoPlugin - -signal selection_changed -signal lock_mode_changed -signal active_point_position_updated - -const value_mode_mouse_sensivity:float = 0.01 -const bake_interval:float = 0.2 - -var handle00_tex = preload("res://addons/m_terrain/icons/handle00.png") -var handle01_tex = preload("res://addons/m_terrain/icons/handle01.png") -#var icon_collapse = preload("res://addons/m_terrain/icons/collapse_normal.svg") -var icon_rotation = preload("res://addons/m_terrain/icons/rotation.svg") - -var tools #mtools.gd -var gui:Control - -### The MCurveTerrain parameter -var curve_terrain:=MCurveTerrain.new() -var is_curve_terrain_panel_open := false -var auto_terrain_deform := false -var auto_terrain_paint := false -var auto_grass_modify := false -### As we can have multiple grass to be modified base on the curve! -### for each grass we store its setting related to curve_modification -### in its medata -### grass loading meta and chaning meta is defined in "res://addons/m_terrain/inspector/gui/curve_terrain.tscn" -### in MPath gizmo we dont care about load or change grass_modify_settings -### WE ONLY USE THAT -var grass_modify_settings:Dictionary - -var selection:EditorSelection -var ur:EditorUndoRedoManager -var selected_mesh:Array - -#### Only one point can be active -#### Active point does not exist in selected_points -var active_point:int = 0 -var selected_points:PackedInt32Array -var selected_connections:PackedInt64Array - -var moving_point = false - -enum LOCK_MODE { - NONE, - X, - Y, - Z, - XZ, - XY, - ZY, - XYZ -} -var lock_mode := LOCK_MODE.NONE -var lock_mode_temporary = false -var lock_mode_original = LOCK_MODE.NONE -var is_handle_setting:= true -var is_handle_init_pos_set:=false -var handle_init_id:=0 -var handle_init_pos:Vector3 -var init_aabb:AABB ## AABB before moving point or handle - - -enum VALUE_MODE { - NONE, - SCALE, - TILT -} - -var value_mode := VALUE_MODE.NONE - -var init_tilt:float -var init_scale:float -var mouse_init_pos:Vector2i -var is_mouse_init_set:=false - -var active_path:MPath - -func _init(): - selection = EditorInterface.get_selection() - - var line_mat = StandardMaterial3D.new() - line_mat.albedo_color = Color(0.3,0.3,1.0) - line_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - line_mat.render_priority = 10 - line_mat.no_depth_test = true - add_material("line_mat",line_mat) - - var control_line_mat = line_mat.duplicate() - control_line_mat.albedo_color = Color(0.5,0.8,1.0) - add_material("control_line_mat",control_line_mat) - - var selected_lines_mat = line_mat.duplicate() - selected_lines_mat.albedo_color = Color(0.2,1.0,0.2) - add_material("selected_lines_mat",selected_lines_mat) - - create_handle_material("points") - var hmat = get_material("points") - hmat.albedo_texture = handle00_tex - hmat.render_priority = 10 - hmat.no_depth_test = true - hmat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - - var controls = hmat.duplicate() - add_material("controls",controls) - controls.albedo_texture = handle01_tex - - var active_p_math = get_material("points").duplicate() - active_p_math.albedo_color = Color(0.9,0.9,0.1) - active_p_math.render_priority = 100 - active_p_math.no_depth_test = true - add_material("active_point",active_p_math) - - var selected_points_math = active_p_math.duplicate() - selected_points_math.albedo_color = Color(1.0,0.2,2) - add_material("selected_points",selected_points_math) - - -func _redraw(gizmo: EditorNode3DGizmo) -> void: - gizmo.clear() - var node:MPath= gizmo.get_node_3d() - var curve:MCurve= node.curve - if not curve: - return - var lines:PackedVector3Array - var selected_lines:PackedVector3Array - var active_points:PackedInt32Array = curve.get_active_points() - if active_points.size() == 0: - return - var active_connections:PackedInt64Array = curve.get_active_conns() - for conn in active_connections: - if selected_connections.has(conn): - selected_lines.append_array(curve.get_conn_baked_line(conn)) - else: - lines.append_array(curve.get_conn_baked_line(conn)) - if lines.size() > 2: - gizmo.add_lines(lines,get_material("line_mat")) - if gui.is_debug_col(): - gizmo.add_collision_segments(lines) - if selected_lines.size() > 2: - gizmo.add_lines(selected_lines,get_material("selected_lines_mat")) - if not gui or not gui.visible: ## In case is not selected no need for handls - return - lines.clear() - ## pointss - ## Main points control point position points_id = point_index - ## point in is secondary=true and points_id = point_index * 2 -> Always even - ## point out is secondary=true and points_id = point_index * 2 + 1 -> Always odd - var main_points:PackedVector3Array - var main_ids:PackedInt32Array - var secondary_pointss:PackedVector3Array - var secondary_ids:PackedInt32Array - var active_pos:PackedVector3Array - var active_id:PackedInt32Array - var selected_pos:PackedVector3Array - var selected_ids:PackedInt32Array - for point in active_points: - var pos:Vector3 = curve.get_point_position(point) - var in_pos:Vector3 = curve.get_point_in(point) - var out_pos:Vector3 = curve.get_point_out(point) - if point == active_point: - active_pos.push_back(pos) - active_id.push_back(point) - elif selected_points.has(point): - selected_pos.push_back(pos) - selected_ids.push_back(point) - else: - main_points.push_back(pos) - main_ids.push_back(point) - secondary_pointss.push_back(in_pos) - secondary_ids.push_back(point * 2) - secondary_pointss.push_back(out_pos) - secondary_ids.push_back(point * 2 + 1) - ## points line - lines.push_back(pos) - lines.push_back(in_pos) - lines.push_back(pos) - lines.push_back(out_pos) - ########## Lock mode line ################## - if lock_mode == LOCK_MODE.X or lock_mode == LOCK_MODE.XY or lock_mode == LOCK_MODE.XZ or lock_mode == LOCK_MODE.XYZ: - lines.push_back(handle_init_pos + Vector3(-100000,0,0)) - lines.push_back(handle_init_pos + Vector3(100000,0,0)) - if lock_mode == LOCK_MODE.Y or lock_mode == LOCK_MODE.XY or lock_mode == LOCK_MODE.ZY or lock_mode == LOCK_MODE.XYZ: - lines.push_back(handle_init_pos + Vector3(0,-100000,0)) - lines.push_back(handle_init_pos + Vector3(0,100000,0)) - if lock_mode == LOCK_MODE.Z or lock_mode == LOCK_MODE.XZ or lock_mode == LOCK_MODE.ZY or lock_mode == LOCK_MODE.XYZ: - lines.push_back(handle_init_pos + Vector3(0,0,-100000)) - lines.push_back(handle_init_pos + Vector3(0,0,100000)) - ################## Setting lines and handles - if main_points.size() > 0: - gizmo.add_handles(main_points,get_material("points",gizmo),main_ids) - if active_pos.size() > 0: - gizmo.add_handles(active_pos,get_material("active_point",gizmo),active_id) - if selected_pos.size() > 0: - gizmo.add_handles(selected_pos,get_material("selected_points",gizmo),selected_ids) - if secondary_pointss.size() > 0: - gizmo.add_handles(secondary_pointss,get_material("controls",gizmo),secondary_ids,false,true) - if lines.size() > 2: - gizmo.add_lines(lines,get_material("control_line_mat")) - -func _get_handle_name(gizmo, handle_id, secondary): - if secondary: - if handle_id%2 == 0: - return "C "+str(handle_id/2) - else: - return "C "+str((handle_id-1)/2) - else: - return "P "+str(handle_id) - -func _is_handle_highlighted(gizmo, handle_id, secondary): - return false - -func _get_handle_value(gizmo, handle_id, secondary): - var curve:MCurve = gizmo.get_node_3d().curve - if not curve: - return null - if not secondary: - active_point_position_updated.emit(str("P", handle_id, ": ", curve.get_point_position(handle_id))) - return curve.get_point_position(handle_id) - else: - if handle_id % 2 == 0: #even - handle_id /=2 - active_point_position_updated.emit(str("C", handle_id, ": ", curve.get_point_in(handle_id))) - return curve.get_point_in(handle_id) - else: - handle_id = (handle_id-1)/2 - active_point_position_updated.emit(str("C", handle_id, ": ", curve.get_point_out(handle_id))) - return curve.get_point_out(handle_id) - -func _set_handle(gizmo, points_id, secondary, camera, screen_pos): - if Input.is_key_pressed(KEY_CTRL): - ### in multi select mode we do not inturput with this - return - var curve:MCurve= gizmo.get_node_3d().curve - if not curve: return - if not is_handle_init_pos_set: - is_handle_setting = true - is_handle_init_pos_set = true - handle_init_id = points_id - handle_init_pos = _get_handle_value(gizmo,points_id,secondary) - var pp:int = points_id - if secondary: - if points_id % 2 == 0: - pp = points_id / 2 - else: - pp = (points_id - 1)/2 - ## AABB - var conns = curve.get_point_conns(pp) - init_aabb = curve.get_conns_aabb(conns) - ################################# - var mode = gui.get_mode() - var from = camera.project_ray_origin(screen_pos) - var to = camera.project_ray_normal(screen_pos) - # is main point - if not secondary: - # for pid in curve.get_active_points(): - var point_pos:Vector3 = curve.get_point_position(points_id) - var drag:Vector3 = from + to * from.distance_to(point_pos) - drag = get_constraint_pos(handle_init_pos,drag) - var active_terrain = gui.get_terrain_for_snap() - if active_terrain and lock_mode == LOCK_MODE.NONE: - if active_terrain and active_terrain.is_grid_created(): - drag.y = active_terrain.get_height(drag) - else: - drag.y = 0.0 - curve.move_point(points_id,drag) - change_active_point(points_id) - else: # is secondary - #if gui.is_xz_handle_lock() and lock_mode == LOCK_MODE.NONE: - # lock_mode = LOCK_MODE.XZ - # lock_mode_changed.emit(lock_mode) - if points_id % 2 == 0: # is even - points_id /= 2; - var in_pos:Vector3 = curve.get_point_in(points_id) - var drag:Vector3 = from + to * from.distance_to(in_pos) - drag = get_constraint_pos(handle_init_pos,drag) - curve.move_point_in(points_id,drag) - if gui.is_mirror(): - var point_pos = curve.get_point_position(points_id) - if gui.is_mirror_lenght(): - var out_pos = point_pos + point_pos - drag - curve.move_point_out(points_id,out_pos) - else: - var out_lenght = point_pos.distance_to(curve.get_point_out(points_id)) - var dir = point_pos - drag - dir = dir.normalized() - var out_pos = point_pos + dir * out_lenght - curve.move_point_out(points_id,out_pos) - change_active_point(points_id) - else: # is odd - points_id = (points_id - 1)/2 - var out_pos:Vector3 = curve.get_point_out(points_id) - var drag:Vector3 = from + to * from.distance_to(out_pos) - drag = get_constraint_pos(handle_init_pos,drag) - curve.move_point_out(points_id,drag) - if gui.is_mirror(): - var point_pos = curve.get_point_position(points_id) - if gui.is_mirror_lenght(): - var in_pos = point_pos + point_pos - drag - curve.move_point_in(points_id,in_pos) - else: - var in_lenght = point_pos.distance_to(curve.get_point_in(points_id)) - var dir = (point_pos - drag).normalized() - dir = dir.normalized() - var in_pos = point_pos + dir * in_lenght - curve.move_point_in(points_id,in_pos) - change_active_point(points_id) - -func get_constraint_pos(init_pos:Vector3,current_pos:Vector3): - if not moving_point or lock_mode == LOCK_MODE.XYZ: - current_pos = init_pos - elif lock_mode == LOCK_MODE.NONE: - return current_pos - elif lock_mode == LOCK_MODE.X: - current_pos.z = init_pos.z - current_pos.y = init_pos.y - elif lock_mode == LOCK_MODE.Y: - current_pos.x = init_pos.x - current_pos.z = init_pos.z - elif lock_mode == LOCK_MODE.Z: - current_pos.x = init_pos.x - current_pos.y = init_pos.y - elif lock_mode == LOCK_MODE.XY: - current_pos.z = init_pos.z - elif lock_mode == LOCK_MODE.XZ: - current_pos.y = init_pos.y - elif lock_mode == LOCK_MODE.ZY: - current_pos.x = init_pos.x - return current_pos - -func update_lock_mode(x,y,z): - if x and y and z: - lock_mode = LOCK_MODE.XYZ - return - if x and y: - lock_mode = LOCK_MODE.XY - return - if x and z: - lock_mode = LOCK_MODE.XZ - return - if y and z: - lock_mode = LOCK_MODE.ZY - return - if x: - lock_mode = LOCK_MODE.X - return - if y: - lock_mode = LOCK_MODE.Y - return - if z: - lock_mode = LOCK_MODE.Z - return - lock_mode = LOCK_MODE.NONE - - -func _begin_handle_action(gizmo, id, is_secondary): - moving_point = true - -func _commit_handle(gizmo, handle_id, secondary, restore, cancel): - moving_point = false - var curve:MCurve = gizmo.get_node_3d().curve - is_handle_init_pos_set = false - is_handle_setting = false - if lock_mode_temporary: - lock_mode = lock_mode_original - lock_mode_temporary = false - lock_mode_original = null - lock_mode_changed.emit(lock_mode) - is_mouse_init_set = false - if not curve: - return - if not ur: - return - if not secondary: - curve.commit_point_update(handle_id) - ur.create_action("move_mcurve") - ur.add_do_method(curve,"move_point",handle_id,curve.get_point_position(handle_id)) - ur.add_do_method(curve,"commit_point_update",handle_id) - ur.add_undo_method(curve,"move_point",handle_id,restore) - ur.add_undo_method(curve,"commit_point_update",handle_id) - else: - if handle_id % 2 == 0: #even - handle_id /=2 - curve.commit_point_update(handle_id) - ur.create_action("move_mcurve_in") - ur.add_do_method(curve,"move_point_in",handle_id,curve.get_point_in(handle_id)) - ur.add_undo_method(curve,"move_point_in",handle_id,restore) - if gui.is_mirror(): - var point_pos:Vector3 = curve.get_point_position(handle_id) - ur.add_do_method(curve,"move_point_out",handle_id,curve.get_point_out(handle_id)) - ur.add_undo_method(curve,"move_point_out",handle_id,point_pos + point_pos - restore) - ur.add_do_method(curve,"commit_point_update",handle_id) - ur.add_undo_method(curve,"commit_point_update",handle_id) - else: - handle_id = (handle_id-1)/2 - curve.commit_point_update(handle_id) - ur.create_action("move_mcurve_out") - ur.add_do_method(curve,"move_point_out",handle_id,curve.get_point_out(handle_id)) - ur.add_undo_method(curve,"move_point_out",handle_id,restore) - if gui.is_mirror(): - var point_pos:Vector3 = curve.get_point_position(handle_id) - ur.add_do_method(curve,"move_point_in",handle_id,curve.get_point_in(handle_id)) - ur.add_undo_method(curve,"move_point_in",handle_id,point_pos + point_pos - restore) - ur.add_do_method(curve,"commit_point_update",handle_id) - ur.add_undo_method(curve,"commit_point_update",handle_id) - gizmo.get_node_3d().update_gizmos() - #### Deforming Terrain - if auto_terrain_deform or auto_terrain_paint or auto_grass_modify: - ### we also deform neighbor points - var undo_aabb = curve.get_conns_aabb(curve.get_point_conns(handle_id)) - var conns:PackedInt64Array = curve.get_point_conns_inc_neighbor_points(handle_id) - if auto_terrain_deform: - curve_terrain.clear_deform_aabb(init_aabb) - curve_terrain.deform_on_conns(conns) - ur.add_undo_method(curve_terrain,"clear_deform_aabb",undo_aabb) - ur.add_undo_method(curve_terrain,"deform_on_conns",conns) - ur.add_do_method(curve_terrain,"clear_deform_aabb",init_aabb) - ur.add_do_method(curve_terrain,"deform_on_conns",conns) - if auto_terrain_paint: - curve_terrain.clear_paint_aabb(init_aabb) - curve_terrain.paint_on_conns(conns) - ur.add_undo_method(curve_terrain,"clear_paint_aabb",undo_aabb) - ur.add_undo_method(curve_terrain,"paint_on_conns",conns) - ur.add_do_method(curve_terrain,"clear_paint_aabb",init_aabb) - ur.add_do_method(curve_terrain,"paint_on_conns",conns) - if auto_grass_modify: - var grass_names:Array= grass_modify_settings.keys() - for gname in grass_names: - var s:Dictionary = grass_modify_settings[gname] - var r:float = s["radius"] ; var o = s["offset"] - if not s["active"] : continue - if not curve_terrain.terrain.has_node(gname): - printerr("can not find grass "+gname+" please reselect MPath node to update grass names") - continue - var g = curve_terrain.terrain.get_node(gname) - if not(g is MGrass): - printerr(gname+" is not a grass node! please reselect MPath node to update grass names") - continue - curve_terrain.clear_grass_aabb(g,init_aabb,r+o) - curve_terrain.modify_grass(conns,g,o,r,s["add"]) - g.update_dirty_chunks() - ur.add_undo_method(curve_terrain,"clear_grass_aabb",g,undo_aabb,r+o) - ur.add_undo_method(curve_terrain,"modify_grass",conns,g,o,r,s["add"]) - ur.add_do_method(curve_terrain,"clear_grass_aabb",g,init_aabb,r+o) - ur.add_do_method(curve_terrain,"modify_grass",conns,g,o,r,s["add"]) - ur.add_undo_method(g,"update_dirty_chunks") - ur.add_do_method(g,"update_dirty_chunks") - curve_terrain.terrain.update_all_dirty_image_texture(false) - curve_terrain.terrain.save_all_dirty_images() - ur.add_do_method(curve_terrain.terrain,"update_all_dirty_image_texture",false) - ur.add_undo_method(curve_terrain.terrain,"update_all_dirty_image_texture",false) - ur.commit_action(false) - - -func move_with_commit(curve:MCurve,handle_id:int, secondary:bool,pos:Vector3): - if not secondary: - curve.move_point(handle_id,pos) - else: - if handle_id % 2 == 0: #even - handle_id /=2 - else: - handle_id = (handle_id-1)/2 - -func _get_gizmo_name(): - return "MPath_Gizmo" - -func _get_priority(): - return 2 - -func _has_gizmo(for_node_3d): - return for_node_3d is MPath - -func _forward_3d_gui_input(camera, event, terrain_col:MCollision): - if moving_point and event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT: - moving_point = false - return EditorPlugin.AFTER_GUI_INPUT_STOP - #Process tilt, scale, and right-click cancel - if event is InputEventMouseButton and event.pressed and value_mode != VALUE_MODE.NONE: - is_mouse_init_set = false - var curve = find_curve() - if not curve or not curve.has_point(active_point): - value_mode = VALUE_MODE.NONE - return - if event.button_index == MOUSE_BUTTON_RIGHT: # Canceling - curve.set_point_scale(active_point,init_scale) - curve.set_point_tilt(active_point,init_tilt) - gui.tilt_num.set_value(init_tilt) - gui.scale_num.set_value(init_scale) - value_mode = VALUE_MODE.NONE - curve.commit_point_update(active_point) - return EditorPlugin.AFTER_GUI_INPUT_STOP - if value_mode == VALUE_MODE.TILT: - ur.create_action("change tilt") - ur.add_do_method(curve,"set_point_tilt",active_point,curve.get_point_tilt(active_point)) - ur.add_do_method(curve,"commit_point_update",active_point) - ur.add_do_method(gui.tilt_num,"set_value",curve.get_point_tilt(active_point)) - ur.add_undo_method(gui.tilt_num,"set_value",init_tilt) - ur.add_undo_method(curve,"set_point_tilt",active_point,init_tilt) - ur.add_undo_method(curve,"commit_point_update",active_point) - ur.commit_action(false) - elif value_mode == VALUE_MODE.SCALE: - ur.create_action("change scale") - ur.add_do_method(curve,"set_point_scale",active_point,curve.get_point_scale(active_point)) - ur.add_do_method(gui.scale_num,"set_value",curve.get_point_scale(active_point)) - ur.add_undo_method(gui.scale_num,"set_value",init_scale) - ur.add_undo_method(curve,"set_point_scale",active_point,init_scale) - ur.add_undo_method(curve,"commit_point_update",active_point) - ur.commit_action(false) - value_mode = VALUE_MODE.NONE - return EditorPlugin.AFTER_GUI_INPUT_STOP - if event is InputEventKey and event.pressed: - if process_keyboard_actions(): - return EditorPlugin.AFTER_GUI_INPUT_STOP - else: - return - if event is InputEventMouseButton and event.button_mask == MOUSE_BUTTON_LEFT and event.pressed: - if process_mouse_left_click(camera, event, terrain_col): - return EditorPlugin.AFTER_GUI_INPUT_STOP - else: - return - if event is InputEventMouseMotion: - if process_mouse_motion(event): - return EditorPlugin.AFTER_GUI_INPUT_STOP - else: - return - if gui.is_select_lock() and event is InputEventMouse and event.button_mask == MOUSE_BUTTON_LEFT: - return EditorPlugin.AFTER_GUI_INPUT_STOP - -func process_mouse_left_click(camera, event, terrain_col): - var mpath = find_mpath() - if not mpath: return - var curve:MCurve = mpath.curve - if not curve: return - #### Handling Selections - var from = camera.project_ray_origin(event.position) - var to = camera.project_ray_normal(event.position) - ### Get collission point id - var pcol = curve.ray_active_point_collision(from,to,0.9999) - if pcol != 0: - if Input.is_key_pressed(KEY_ALT): - change_active_point(pcol) - remove_point() - elif Input.is_key_pressed(KEY_SHIFT): - var last:int= selected_points.find(pcol) - if last != -1: - selected_points.remove_at(last) - else: - selected_points.push_back(pcol) - else: - if pcol == active_point and selected_points.size() == 0: - change_active_point(0) - return - else: - selected_points.clear() - change_active_point(pcol) - var last:int= selected_points.find(pcol) - if last != -1: - selected_points.remove_at(last) - if active_point != 0 and Input.is_key_pressed(KEY_SHIFT) and pcol==0: # Maybe a miss selction - return EditorPlugin.AFTER_GUI_INPUT_STOP - ## selected connections - selected_connections.clear() - var all_pp = selected_points.duplicate() - all_pp.push_back(active_point) - selected_connections = curve.get_conn_ids_exist(all_pp) - if pcol: #### if we have selection then we should stop here and not go into creation stuff - mpath.update_gizmos() - selection_changed.emit() - return - if gui.get_mode() == gui.MODE.CREATE or Input.is_key_pressed(KEY_CTRL): - ### Here should be adjusted later with MTerrain - var new_index:int - var new_pos:Vector3 - var is_new_pos_set = false - var active_mterrain = gui.get_terrain_for_snap() - if active_mterrain: - #To Do: user should be able to select which mterrain is used for snapping - if active_mterrain and active_mterrain.is_grid_created(): - if terrain_col.is_collided(): - new_pos = terrain_col.get_collision_position() - is_new_pos_set = true - else: - var col = MTool.ray_collision_y_zero_plane(camera.global_position,camera.project_ray_normal(event.position)) - if col.is_collided(): - new_pos = col.get_collision_position() - is_new_pos_set = true - var conn_ids:PackedInt64Array - if curve.has_point(active_point): - var creation_distance = curve.get_point_position(active_point).distance_to(from) - if not is_new_pos_set: - new_pos = from + to * creation_distance - new_index = curve.add_point(new_pos,new_pos,new_pos,active_point) - conn_ids.push_back(curve.get_conn_id(new_index,active_point)) - else: - if not is_new_pos_set: - new_pos = from + to * 4.0 - new_index = curve.add_point(new_pos,new_pos,new_pos,0) - if new_index == 0: ### In case for error - return true - ## Undo Redo - ur.create_action("create_point") - ur.add_do_method(self,"change_active_point",new_index) - ur.add_undo_method(self,"change_active_point",active_point) - ur.add_do_method(curve,"add_point",new_pos,new_pos,new_pos,active_point) - if conn_ids.size()!=0: - curve_terrain_modify(conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_do_method(self,"curve_terrain_modify",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_undo_method(self,"curve_terrain_clear",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_undo_method(curve,"remove_point",new_index) - ur.commit_action(false) - change_active_point(new_index) - mpath.update_gizmos() - return true - -#Mouse motion for curve tilt and scale -func process_mouse_motion(event): - if value_mode == VALUE_MODE.NONE: return - var curve = find_curve() - if not curve: return - if not curve.has_point(active_point): return - if not is_mouse_init_set: - mouse_init_pos = event.position - init_scale = curve.get_point_scale(active_point) - init_tilt = curve.get_point_tilt(active_point) - is_mouse_init_set = true - var mouse_diff:float = mouse_init_pos.y - event.position.y - mouse_diff *= value_mode_mouse_sensivity - if value_mode == VALUE_MODE.TILT: - var new_tilt:= init_tilt + mouse_diff - curve.set_point_tilt(active_point,new_tilt) - gui.tilt_num.set_value(new_tilt) - elif value_mode == VALUE_MODE.SCALE: - var new_scale:= init_scale + mouse_diff - curve.set_point_scale(active_point,new_scale) - gui.scale_num.set_value(new_scale) - curve.commit_point_update(active_point) - return true - -func process_keyboard_actions(): #returns true to return AFTER_GUI_INPUT_STOP - #if event.keycode == KEY_P: - if Input.is_action_just_pressed("mpath_validate"): - var curve:MCurve = find_curve() - #for c in selected_connections: - # curve.validate_conn(c) - return true - #if event.keycode == KEY_L: - if Input.is_action_just_pressed("mpath_select_linked"): - var path:MPath = find_mpath() - if path: - var curve:MCurve = path.curve - if curve and curve.has_point(active_point): - var pp = curve.get_point_conn_points_recursive(active_point) - selected_points = pp - pp.push_back(active_point) - selected_connections = curve.get_conn_ids_exist(pp) - path.update_gizmos() - return true - #if event.keycode == KEY_T and Input.is_key_pressed(KEY_SHIFT): - if Input.is_action_just_pressed("mpath_swap_points"): - swap_points() - return true - #if event.keycode == KEY_T and not Input.is_key_pressed(KEY_SHIFT): - if Input.is_action_just_pressed("mpath_toggle_connection"): - if toggle_connection(): - return true - #elif event.keycode == KEY_BACKSPACE: - if Input.is_action_just_pressed("mpath_remove_point"): - if remove_point(): - return true - #elif event.keycode == KEY_X: - if Input.is_action_just_pressed("mpath_disconnect_point"): - if disconnect_points(): - return true - #elif event.keycode == KEY_C: - if Input.is_action_just_pressed("mpath_connect_point"): - if connect_points(): - return true - #if event.keycode == KEY_R: - if Input.is_action_just_pressed("mpath_tilt_mode"): - var curve = find_curve() - if curve and curve.has_point(active_point): - init_tilt = curve.get_point_tilt(active_point) - value_mode = VALUE_MODE.TILT - return true - #if event.keycode == KEY_K: - if Input.is_action_just_pressed("mpath_scale_mode"): - var curve = find_curve() - if curve and curve.has_point(active_point): - init_scale = curve.get_point_scale(active_point) - value_mode = VALUE_MODE.SCALE - return true - if is_handle_setting: - var path:MPath = find_mpath() - #shift x - if Input.is_action_just_pressed("mpath_lock_zy"): - if not lock_mode_temporary: - lock_mode_temporary = true - lock_mode_original = lock_mode - lock_mode = LOCK_MODE.ZY if lock_mode != LOCK_MODE.ZY else LOCK_MODE.NONE - lock_mode_changed.emit(lock_mode) - if path: path.update_gizmos() - return true - #shift y - if Input.is_action_just_pressed("mpath_lock_xz"): - if not lock_mode_temporary: - lock_mode_temporary = true - lock_mode_original = lock_mode - lock_mode = LOCK_MODE.XZ if lock_mode != LOCK_MODE.XZ else LOCK_MODE.NONE - lock_mode_changed.emit(lock_mode) - if path: path.update_gizmos() - return true - #shift z - if Input.is_action_just_pressed("mpath_lock_xy"): - if not lock_mode_temporary: - lock_mode_temporary = true - lock_mode_original = lock_mode - lock_mode = LOCK_MODE.XY if lock_mode != LOCK_MODE.XY else LOCK_MODE.NONE - lock_mode_changed.emit(lock_mode) - if path: path.update_gizmos() - return true - #x - if Input.is_action_just_pressed("mpath_lock_x"): - if not lock_mode_temporary: - lock_mode_temporary = true - lock_mode_original = lock_mode - lock_mode = LOCK_MODE.X if lock_mode != LOCK_MODE.X else LOCK_MODE.NONE - lock_mode_changed.emit(lock_mode) - if path: path.update_gizmos() - return true - #y - if Input.is_action_just_pressed("mpath_lock_y"): - if not lock_mode_temporary: - lock_mode_temporary = true - lock_mode_original = lock_mode - lock_mode = LOCK_MODE.Y if lock_mode != LOCK_MODE.Y else LOCK_MODE.NONE - lock_mode_changed.emit(lock_mode) - if path: path.update_gizmos() - return true - #z - if Input.is_action_just_pressed("mpath_lock_z"): - if not lock_mode_temporary: - lock_mode_temporary = true - lock_mode_original = lock_mode - lock_mode_original = lock_mode - lock_mode = LOCK_MODE.Z if lock_mode != LOCK_MODE.Z else LOCK_MODE.NONE - lock_mode_changed.emit(lock_mode) - if path: path.update_gizmos() - return true - -func find_mpath()->MPath: - if active_path: - return active_path - var snodes = selection.get_selected_nodes() - for n in snodes: - if n is MPath: - active_path = n - return n - return null - -func find_curve()->MCurve: - var node = find_mpath() - if not node: return null - var curve:MCurve = node.curve - return curve - -func on_collapse(): - var node = find_mpath() - if not node: - return - var curve:MCurve = node.curve - if not curve: - return - if not curve.has_point(active_point): - return - var p_pos = curve.get_point_position(active_point) - var in_pos = curve.get_point_in(active_point) - var out_pos = curve.get_point_out(active_point) - curve.commit_point_update(active_point) - ur.create_action("collapse point") - ur.add_do_method(curve,"move_point_in",active_point,p_pos) - ur.add_do_method(curve,"move_point_out",active_point,p_pos) - ur.add_undo_method(curve,"move_point_in",active_point,in_pos) - ur.add_undo_method(curve,"move_point_out",active_point,out_pos) - ur.commit_action(true) - -func set_gui(input:Control): - gui = input - - gui.visibility_changed.connect(gui_visibility_changed) - gui.toggle_connection_btn.pressed.connect(toggle_connection) - gui.collapse_btn.pressed.connect(on_collapse) - gui.connect_btn.pressed.connect(connect_points) - gui.disconnect_btn.pressed.connect(disconnect_points) - gui.remove_btn.pressed.connect(remove_point) - gui.swap_points_btn.pressed.connect(swap_points) - gui.depth_test_checkbox.toggled.connect(toggle_depth_test) - gui.tilt_num.prop_changed.connect(on_point_val_changed) - gui.scale_num.prop_changed.connect(on_point_val_changed) - gui.tilt_num.commit_value.connect(on_point_val_commit) - gui.scale_num.commit_value.connect(on_point_val_commit) - gui.tilt_num.set_editable(false) - gui.scale_num.set_editable(false) - gui.tilt_num.set_soft_min(-1) - gui.tilt_num.set_soft_max(1) - gui.scale_num.set_soft_min(-4) - gui.scale_num.set_soft_max(4) - gui.sort_increasing_btn.pressed.connect(sort.bind(true)) - gui.sort_decreasing_btn.pressed.connect(sort.bind(false)) - gui.gizmo = self - -func change_active_point(new_active_point:int): - active_point = new_active_point - var curve = find_curve() - if not curve or not curve.has_point(active_point): - gui.tilt_num.set_editable(false) - gui.scale_num.set_editable(false) - return - gui.tilt_num.set_editable(true) - gui.scale_num.set_editable(true) - gui.tilt_num.set_value_no_signal(curve.get_point_tilt(active_point)) - gui.scale_num.set_value_no_signal(curve.get_point_scale(active_point)) - -func toggle_connection()->bool: - var path = find_mpath() - if not path: return false - var curve:MCurve = path.curve - if not curve: return false - if not curve.has_point(active_point): return false - var tconn = curve.growed_conn(selected_connections) - ur.create_action("toggle connection") - ## Terrain clear befor - ur.add_do_method(self,"curve_terrain_clear",tconn,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_undo_method(self,"curve_terrain_clear",tconn,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - # toggle - ur.add_do_method(self,"_toggle_connection",curve,active_point,selected_connections) - ur.add_undo_method(self,"_toggle_connection",curve,active_point,selected_connections) - ## Terrain modify after - ur.add_do_method(self,"curve_terrain_modify",tconn,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_undo_method(self,"curve_terrain_modify",tconn,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.commit_action(true) - return true - -func connect_points()->bool: - var path = find_mpath() - if not path: return false - var curve:MCurve = path.curve - if not curve: return false - if not curve.has_point(active_point): return false - if selected_points.size() == 0: return false - if selected_points.size() > 1: - push_error("More than two points is selected") - return false - var other_point:int = selected_points[0] - var res:bool = curve.connect_points(active_point,other_point,MCurve.CONN_NONE) - if res: - var conn_ids:PackedInt64Array - conn_ids.push_back(curve.get_conn_id(active_point,other_point)) - ur.create_action("disconnect points") - ur.add_do_method(curve,"connect_points",active_point,other_point,MCurve.CONN_NONE) - ##Terrain - curve_terrain_modify(conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_do_method(self,"curve_terrain_modify",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_undo_method(self,"curve_terrain_clear",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ## end Terrain - ur.add_undo_method(curve,"disconnect_points",active_point,other_point) - ur.commit_action(false) - path.update_gizmos() - return true - return false - -func disconnect_points(): - var path = find_mpath() - if not path: return false - var curve:MCurve = path.curve - if not curve: return false - if not curve.has_point(active_point): return false - if selected_points.size() == 0: return false - if selected_points.size() > 1: - push_error("More than two points is selected") - return false - var other_point:int = selected_points[0] - var conn_ids:PackedInt64Array - conn_ids.push_back(curve.get_conn_id(active_point,other_point)) - if not curve.has_conn(conn_ids[0]): return - var conn_type = curve.get_conn_type(curve.get_conn_id(active_point,other_point)) - curve_terrain_clear(conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.create_action("disconnect_points") - ur.add_do_method(self,"curve_terrain_clear",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - curve.disconnect_points(active_point,other_point) - ur.add_do_method(curve,"disconnect_points",active_point,other_point) - ur.add_undo_method(curve,"connect_points",active_point,other_point,conn_type) - ur.add_undo_method(self,"curve_terrain_modify",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.commit_action(false) - path.update_gizmos() - return false - -func _toggle_connection(curve:MCurve,toggle_point,toggle_conn): - for conn in selected_connections: - curve.toggle_conn_type(active_point,conn) - if curve.has_point(active_point): - curve.commit_point_update(active_point) - var mpath = find_mpath() - if mpath: mpath.call_deferred("update_gizmos") - return true - -func remove_point()->bool: - var path = find_mpath() - if not path: return false - var curve:MCurve = path.curve - if not curve: return false - if not curve.has_point(active_point): return false - var p_pos = curve.get_point_position(active_point) - var p_in = curve.get_point_in(active_point) - var p_out = curve.get_point_out(active_point) - var conn_points = curve.get_point_conn_points(active_point) - var conn_types = curve.get_point_conn_types(active_point) - var conn_ids:PackedInt64Array = curve.get_point_conns(active_point) - ur.create_action("Remove Point") - if conn_ids.size()!=0: - curve_terrain_modify(conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_do_method(self,"curve_terrain_clear",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.add_do_method(curve,"remove_point",active_point) - #curve.add_point_conn_point(p_pos,p_in,p_out,conn_types,conn_points) - ur.add_undo_method(curve,"add_point_conn_point",p_pos,p_in,p_out,conn_types,conn_points) - if conn_ids.size()!=0: - ur.add_undo_method(self,"curve_terrain_modify",conn_ids,auto_terrain_deform,auto_terrain_paint,auto_grass_modify,grass_modify_settings) - ur.commit_action(true) - return true - -func swap_points(): - var curve:MCurve = find_curve() - if not curve: return - if not curve.has_point(active_point): return - if selected_points.size() != 1: - printerr("For swaping point you should select only two points") - return - curve.swap_points_with_validation(active_point,selected_points[0]) - ur.create_action("swap_points") - ur.add_do_method(curve,"swap_points_with_validation",active_point,selected_points[0]) - ur.add_undo_method(curve,"swap_points_with_validation",active_point,selected_points[0]) - ur.commit_action(false) - -func gui_visibility_changed(): - if not gui.visible: - change_active_point(0) - selected_connections.clear() - selected_points.clear() - if active_path: - active_path.update_gizmos() - active_path = null - -func on_tilt_changed(value:float): - var path = find_mpath() - if not path: return false - var curve:MCurve = path.curve - if not curve: return false - if not curve.has_point(active_point): return false - curve.set_point_tilt(active_point,value) - path.update_gizmos() - -func on_point_val_changed(prop_name,val): - var path = find_mpath() - if not path: return false - var curve:MCurve = path.curve - if not curve: return false - if not curve.has_point(active_point): return false - if prop_name == "tilt": - curve.set_point_tilt(active_point,val) - elif prop_name == "scale": - curve.set_point_scale(active_point,val) - path.update_gizmos() - -func on_point_val_commit(prop_name,old_val,new_val): - var curve = find_curve() - if not curve or not curve.has_point(active_point): return - if prop_name == "tilt": - ur.create_action("change tilt") - ur.add_undo_method(curve,"set_point_tilt",active_point,old_val) - ur.add_do_method(curve,"set_point_tilt",active_point,new_val) - ur.add_undo_method(gui.tilt_num,"set_value",old_val) - ur.add_do_method(gui.tilt_num,"set_value",new_val) - ur.add_do_method(curve,"commit_point_update",active_point) - ur.add_undo_method(curve,"commit_point_update",active_point) - ur.commit_action(false) - elif prop_name == "scale": - ur.create_action("change scale") - ur.add_undo_method(curve,"set_point_scale",active_point,old_val) - ur.add_do_method(curve,"set_point_scale",active_point,new_val) - ur.add_undo_method(gui.scale_num,"set_value",old_val) - ur.add_do_method(gui.scale_num,"set_value",new_val) - ur.add_do_method(curve,"commit_point_update",active_point) - ur.add_undo_method(curve,"commit_point_update",active_point) - ur.commit_action(false) - curve.commit_point_update(active_point) - -func toggle_depth_test(input:bool): - get_material("line_mat").no_depth_test = not input - get_material("selected_lines_mat").no_depth_test = not input - -func get_selected_connections()->PackedInt64Array: - return selected_connections - -func get_selected_points64()->PackedInt64Array: - var out:PackedInt64Array - if active_point != 0: out.push_back(active_point) - for p in selected_points: - out.push_back(p) - return out - -func get_selected_points32()->PackedInt32Array: - var out:PackedInt32Array - if active_point != 0: out.push_back(active_point) - out.append_array(selected_points) - return out - -func sort(increasing:bool): - var path = find_mpath() - if not path or not path.curve: return - var curve = path.curve - active_point = curve.sort_from(active_point,increasing) - var cuid = ur.get_object_history_id(curve) - var suid = ur.get_object_history_id(self) - var cu = ur.get_history_undo_redo(cuid) - var su = ur.get_history_undo_redo(suid) - cu.clear_history() - su.clear_history() - path.update_gizmos() - -### if selection is empty will get connection around active point -func get_conns_list(only_selected:bool)->PackedInt64Array: - var curve = find_curve() - if not curve: return PackedInt64Array() - if(only_selected): - if selected_connections.size() !=0: - return selected_connections - else: - return curve.get_point_conns(active_point) - return curve.get_active_conns() - -func deform(only_selected:bool): - curve_terrain.deform_on_conns(get_conns_list(only_selected)) - curve_terrain.terrain.update_all_dirty_image_texture(false) - -func clear_deform(only_selected:bool): - curve_terrain.clear_deform(get_conns_list(only_selected)) - curve_terrain.terrain.update_all_dirty_image_texture(false) - -func clear_deform_large(only_selected:bool): - #print("Clear large ") - var curve = find_curve() - if not curve: return - var aabb = curve.get_conns_aabb(get_conns_list(only_selected)) - aabb = aabb.grow(10) - curve_terrain.clear_deform_aabb(aabb) - curve_terrain.terrain.update_all_dirty_image_texture(false) - -func paint(only_selected:bool): - curve_terrain.paint_on_conns(get_conns_list(only_selected)) - curve_terrain.terrain.update_all_dirty_image_texture(false) - -func clear_paint(only_selected:bool): - curve_terrain.clear_paint(get_conns_list(only_selected)) - curve_terrain.terrain.update_all_dirty_image_texture(false) - -func clear_paint_large(only_selected:bool): - var curve = find_curve() - if not curve: return - var aabb = curve.get_conns_aabb(get_conns_list(only_selected)) - aabb = aabb.grow(10) - curve_terrain.clear_paint_aabb(aabb) - curve_terrain.terrain.update_all_dirty_image_texture(false) - -func modify_grass(only_selected:bool): - var conns = get_conns_list(only_selected) - if conns.size() == 0: return - var g_names = grass_modify_settings.keys() - for gname in g_names: - var setting:Dictionary = grass_modify_settings[gname] - if not setting["active"] : return - if not curve_terrain.terrain.has_node(gname): - printerr("can not find grass "+gname+" please reselect MPath node to update grass names") - continue - var g = curve_terrain.terrain.get_node(gname) - if not(g is MGrass): - printerr(gname+" is not a grass node! please reselect MPath node to update grass names") - continue - curve_terrain.modify_grass(conns,g,setting["offset"],setting["radius"],setting["add"]) - g.update_dirty_chunks() - - -func clear_grass(only_selected:bool): - var conns = get_conns_list(only_selected) - if conns.size() == 0: return - var g_names = grass_modify_settings.keys() - for gname in g_names: - var setting:Dictionary = grass_modify_settings[gname] - if not setting["active"] : return - if not curve_terrain.terrain.has_node(gname): - printerr("can not find grass "+gname+" please reselect MPath node to update grass names") - continue - var g = curve_terrain.terrain.get_node(gname) - if not(g is MGrass): - printerr(gname+" is not a grass node! please reselect MPath node to update grass names") - continue - curve_terrain.clear_grass(conns,g,setting["offset"]+setting["radius"]) - g.update_dirty_chunks() - -func clear_grass_large(only_selected:bool): - var curve = find_curve() - if not curve: return - var aabb = curve.get_conns_aabb(get_conns_list(only_selected)) - aabb = aabb.grow(10) - var g_names = grass_modify_settings.keys() - for gname in g_names: - var setting:Dictionary = grass_modify_settings[gname] - if not setting["active"] : return - if not curve_terrain.terrain.has_node(gname): - printerr("can not find grass "+gname+" please reselect MPath node to update grass names") - continue - var g = curve_terrain.terrain.get_node(gname) - if not(g is MGrass): - printerr(gname+" is not a grass node! please reselect MPath node to update grass names") - continue - curve_terrain.clear_grass_aabb(g,aabb,setting["offset"]+setting["radius"]) - g.update_dirty_chunks() - - -## Usefull when points are not moving like for connect or discconect -func curve_terrain_modify(conns:PackedInt64Array,_terrain:bool,_paint:bool,_grass:bool,_gsettings): - if auto_terrain_deform or auto_terrain_paint or auto_grass_modify: - if _terrain: - curve_terrain.deform_on_conns(conns) - if _paint: - curve_terrain.paint_on_conns(conns) - if _grass: - var grass_names:Array= _gsettings.keys() - for gname in grass_names: - var s:Dictionary = _gsettings[gname] - var r:float = s["radius"] ; var o = s["offset"] - if not s["active"] : continue - if not curve_terrain.terrain.has_node(gname): - printerr("can not find grass "+gname+" please reselect MPath node to update grass names") - continue - var g = curve_terrain.terrain.get_node(gname) - if not(g is MGrass): - printerr(gname+" is not a grass node! please reselect MPath node to update grass names") - continue - curve_terrain.modify_grass(conns,g,o,r,s["add"]) - g.update_dirty_chunks() - curve_terrain.terrain.update_all_dirty_image_texture(false) - curve_terrain.terrain.save_all_dirty_images() - -## Usefull when points are not moving like for connect or discconect -func curve_terrain_clear(conns:PackedInt64Array,_terrain:bool,_paint:bool,_grass:bool,_gsettings): - if auto_terrain_deform or auto_terrain_paint or auto_grass_modify: - if _terrain: - curve_terrain.clear_deform(conns) - if _paint: - curve_terrain.clear_paint(conns) - if _grass: - var grass_names:Array= _gsettings.keys() - for gname in grass_names: - var s:Dictionary = _gsettings[gname] - var r:float = s["radius"] ; var o = s["offset"] - if not s["active"] : continue - if not curve_terrain.terrain.has_node(gname): - printerr("can not find grass "+gname+" please reselect MPath node to update grass names") - continue - var g = curve_terrain.terrain.get_node(gname) - if not(g is MGrass): - printerr(gname+" is not a grass node! please reselect MPath node to update grass names") - continue - curve_terrain.clear_grass(conns,g,o+r) - g.update_dirty_chunks() - curve_terrain.terrain.update_all_dirty_image_texture(false) - curve_terrain.terrain.save_all_dirty_images() - - - - - - - - - - - - - - - - - diff --git a/addons/m_terrain/gizmos/mpath_gizmo_gui.gd b/addons/m_terrain/gizmos/mpath_gizmo_gui.gd deleted file mode 100644 index 2188751..0000000 --- a/addons/m_terrain/gizmos/mpath_gizmo_gui.gd +++ /dev/null @@ -1,134 +0,0 @@ -@tool -extends Control - - -@onready var mirror_checkbox = find_child("mirror_checkbox") -@onready var mirror_lenght_checkbox = find_child("mirror_l_checkbox") -@onready var snap_checkbox = find_child("snap") -@onready var mode_option = find_child("mode") -@onready var collapse_btn = find_child("collapse") -@onready var toggle_connection_btn = find_child("toggle_connection") -@onready var connect_btn = find_child("Connect") -@onready var swap_points_btn = find_child("swap_points") -@onready var disconnect_btn = find_child("Disconnect") -@onready var remove_btn = find_child("remove") -@onready var tilt_num = find_child("tilt") -@onready var scale_num = find_child("scale") -@onready var depth_test_checkbox = find_child("depth_test") -#@onready var xz_handle_lock = find_child("xz_handle_lock") -@onready var select_lock = find_child("select_lock") -@onready var debug_col = find_child("debug_col") -@onready var sort_increasing_btn = find_child("sort_increasing") -@onready var sort_decreasing_btn = find_child("sort_decreasing") - -@onready var show_rest_btn = find_child("show_rest") -@onready var settings_panel = find_child("settings_panel") - -@onready var x_lock = find_child("x_lock") -@onready var y_lock = find_child("y_lock") -@onready var z_lock = find_child("z_lock") - -@onready var active_point_label = find_child("active_point_label") - -var mterrain_for_snap = null - -var gizmo: - set(value): - gizmo = value - gizmo.lock_mode_changed.connect(update_axis_lock) - gizmo.active_point_position_updated.connect(update_active_point_label) - - if is_instance_valid(x_lock): - connect_lock_mode_signals() - -func connect_lock_mode_signals(): - x_lock.pressed.connect(func(): gizmo.update_lock_mode(x_lock.button_pressed, y_lock.button_pressed,z_lock.button_pressed)) - y_lock.pressed.connect(func(): gizmo.update_lock_mode(x_lock.button_pressed, y_lock.button_pressed,z_lock.button_pressed)) - z_lock.pressed.connect(func(): gizmo.update_lock_mode(x_lock.button_pressed, y_lock.button_pressed,z_lock.button_pressed)) - - -enum MODE { - EDIT = 0, - CREATE = 1, -} -func update_active_point_label(new_text): - active_point_label.text = new_text - -func is_mirror()->bool: - return mirror_checkbox.button_pressed - -func is_mirror_lenght()->bool: - return mirror_lenght_checkbox.button_pressed - -func is_xz_handle_lock()->bool: - return y_lock.button_pressed - -func get_terrain_for_snap(): - if mterrain_for_snap and snap_checkbox.button_pressed: - return mterrain_for_snap - else: - return null - -func get_mode(): - return mode_option.selected - - -func _input(event): - if not visible: - return - if Input.is_action_just_pressed( "mpath_toggle_mode" ): - toggle_mode() - if Input.is_action_just_pressed( "mpath_toggle_mirror" ): - mirror_checkbox.button_pressed = not mirror_checkbox.button_pressed - if Input.is_action_just_pressed( "mpath_toggle_mirror_length" ): - mirror_lenght_checkbox.button_pressed = not mirror_lenght_checkbox.button_pressed - -func _ready(): - tilt_num.__set_name("tilt") - scale_num.__set_name("scale") - tilt_num.set_value(0.0) - scale_num.set_value(1.0) - tilt_num.set_tooltip_text("Change Tilt\nHotkey: R") - scale_num.set_tooltip_text("Change Tilt\nHotkey: E") - settings_panel.visible = false - -func update_axis_lock(lock_mode): - x_lock.button_pressed = true if lock_mode in [1,4,5,7] else false #x, xz, xy, xyz - y_lock.button_pressed = true if lock_mode in [2,5,6,7] else false #y, xy, zy, xyz - z_lock.button_pressed = true if lock_mode in [3,4,6,7] else false #z, xz, zy, xyz - -func toggle_mode(): - if mode_option.selected == 0: - mode_option.selected = 1 - else: - mode_option.selected = 0 - -func is_select_lock()->bool: - return select_lock.button_pressed - -func is_debug_col()->bool: - return debug_col.button_pressed - -func _on_show_rest_toggled(toggle_on): - settings_panel.visible = toggle_on - settings_panel.position.x = -settings_panel.size.x + show_rest_btn.size.x - settings_panel.position.y = -settings_panel.size.y # - show_rest_btn.size.y - -func set_terrain_snap(mterrain): - if mterrain == null: - snap_checkbox.button_pressed = false - snap_checkbox.visible = false - mterrain_for_snap = null - else: - mterrain_for_snap = mterrain - snap_checkbox.button_pressed = true - snap_checkbox.visible = true - -func show_mpath_help_window(): - var help_window = preload("res://addons/m_terrain/gui/mpath_help_popup.tscn").instantiate() - add_child(help_window) - help_window.size.x = 25 * theme.default_font_size - help_window.size.y = 24 * theme.default_font_size - -func _on_show_rest_minimum_size_changed(): - _on_show_rest_toggled(settings_panel.visible) diff --git a/addons/m_terrain/gizmos/mpath_gizmo_gui.tscn b/addons/m_terrain/gizmos/mpath_gizmo_gui.tscn deleted file mode 100644 index 8016e37..0000000 --- a/addons/m_terrain/gizmos/mpath_gizmo_gui.tscn +++ /dev/null @@ -1,261 +0,0 @@ -[gd_scene load_steps=14 format=3 uid="uid://btfhp7mnhc5nj"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_byb3a"] -[ext_resource type="Script" path="res://addons/m_terrain/gizmos/mpath_gizmo_gui.gd" id="1_y34ur"] -[ext_resource type="Texture2D" uid="uid://c64direekaeap" path="res://addons/m_terrain/icons/mirror_icon.svg" id="2_tic3q"] -[ext_resource type="Texture2D" uid="uid://ckbvdmvbcxfb6" path="res://addons/m_terrain/icons/magnet_icon.svg" id="3_yoi5b"] -[ext_resource type="Texture2D" uid="uid://30e6iyx7q1y7" path="res://addons/m_terrain/icons/mpath_collapse_point_icon.svg" id="4_38e8d"] -[ext_resource type="Texture2D" uid="uid://t8tdan3853oy" path="res://addons/m_terrain/icons/icon_close.svg" id="5_8fq58"] -[ext_resource type="Texture2D" uid="uid://ckrq26s3bkih3" path="res://addons/m_terrain/icons/switch_direction_icon.svg" id="5_xw4f1"] -[ext_resource type="PackedScene" uid="uid://cjjqtr6xhktp4" path="res://addons/m_terrain/gui/control_prop_element/float_range.tscn" id="6_bsspt"] -[ext_resource type="Texture2D" uid="uid://jw6maiih4qf8" path="res://addons/m_terrain/icons/lock.svg" id="7_0ucgh"] -[ext_resource type="Texture2D" uid="uid://cylua0xddvmx7" path="res://addons/m_terrain/icons/connect_icon.svg" id="7_mbnvb"] -[ext_resource type="Texture2D" uid="uid://bnafvu7s1g7dn" path="res://addons/m_terrain/icons/disconnect_icon.svg" id="8_777vd"] -[ext_resource type="Texture2D" uid="uid://b4ylxie43lan2" path="res://addons/m_terrain/icons/more_options_icon.svg" id="10_01bp8"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7loo7"] -content_margin_left = 6.0 -bg_color = Color(0, 0.419608, 0, 0.188235) - -[node name="PanelContainer" type="PanelContainer"] -offset_right = 40.0 -offset_bottom = 40.0 -theme = ExtResource("1_byb3a") -script = ExtResource("1_y34ur") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="mode" type="OptionButton" parent="HBoxContainer"] -visible = false -layout_mode = 2 -tooltip_text = "Change Mode -Hot-keys: grave accent(`)" -theme_override_styles/normal = SubResource("StyleBoxFlat_7loo7") -item_count = 2 -selected = 0 -popup/item_0/text = "Edit" -popup/item_0/id = 0 -popup/item_1/text = "Create" -popup/item_1/id = 1 - -[node name="mirror_checkbox" type="CheckBox" parent="HBoxContainer"] -custom_minimum_size = Vector2(5, 0) -layout_mode = 2 -tooltip_text = "Mirror-Controls -Hot-key: M" -theme_type_variation = &"button_icon_only" -button_pressed = true -icon = ExtResource("2_tic3q") -alignment = 1 -icon_alignment = 2 - -[node name="mirror_l_checkbox" type="CheckBox" parent="HBoxContainer"] -custom_minimum_size = Vector2(60, 0) -layout_mode = 2 -tooltip_text = "Mirror-Controls-Lenght -Hot-key: L" -theme_type_variation = &"button_icon_only" -button_pressed = true -text = "ML" -alignment = 1 -icon_alignment = 1 - -[node name="snap" type="CheckBox" parent="HBoxContainer"] -custom_minimum_size = Vector2(60, 0) -layout_mode = 2 -tooltip_text = "Snap to Terrain" -theme_type_variation = &"button_icon_only" -button_pressed = true -icon = ExtResource("3_yoi5b") -icon_alignment = 2 - -[node name="collapse" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 -tooltip_text = "Collapse point: move point handles to center of point" -theme_type_variation = &"button_icon_only" -icon = ExtResource("4_38e8d") -expand_icon = true - -[node name="toggle_connection" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(40, 0) -layout_mode = 2 -tooltip_text = "Switch Connection Direction -Hot-key: T" -theme_type_variation = &"button_icon_only" -theme_override_font_sizes/font_size = 18 -icon = ExtResource("5_xw4f1") -expand_icon = true - -[node name="Connect" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(40, 0) -layout_mode = 2 -tooltip_text = "Connect points -Hot-key: C" -theme_type_variation = &"button_icon_only" -theme_override_colors/font_color = Color(0.14902, 1, 0.25098, 1) -theme_override_font_sizes/font_size = 18 -icon = ExtResource("7_mbnvb") -expand_icon = true - -[node name="Disconnect" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(40, 0) -layout_mode = 2 -tooltip_text = "Disconnect points -Hot-key: B" -theme_type_variation = &"button_icon_only" -theme_override_colors/font_color = Color(0.717647, 0.952941, 0, 1) -theme_override_font_sizes/font_size = 18 -icon = ExtResource("8_777vd") -expand_icon = true - -[node name="remove" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(40, 0) -layout_mode = 2 -tooltip_text = "Remove point -Hot-key: Backspace" -theme_type_variation = &"button_icon_only" -theme_override_colors/font_color = Color(1, 0.2, 0.2, 1) -theme_override_font_sizes/font_size = 18 -icon = ExtResource("5_8fq58") -expand_icon = true - -[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] -layout_mode = 2 -theme_override_constants/separation = 0 - -[node name="VSeparator" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] -layout_mode = 2 -theme_override_constants/margin_left = 12 - -[node name="Label4" type="Label" parent="HBoxContainer/HBoxContainer"] -visible = false -layout_mode = 2 -text = "axis lock: " - -[node name="TextureRect" type="TextureRect" parent="HBoxContainer/HBoxContainer"] -layout_mode = 2 -texture = ExtResource("7_0ucgh") -stretch_mode = 5 - -[node name="x_lock" type="CheckBox" parent="HBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "lock point's x position" -theme_type_variation = &"button_icon_only" -text = " X " - -[node name="y_lock" type="CheckBox" parent="HBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "lock point's y position" -theme_type_variation = &"button_icon_only" -text = " Y " - -[node name="z_lock" type="CheckBox" parent="HBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "lock point's z position" -theme_type_variation = &"button_icon_only" -text = " Z " - -[node name="Button" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 -tooltip_text = "show MPath help window" -theme_type_variation = &"button_icon_only" -theme_override_font_sizes/font_size = 21 -text = "?" - -[node name="show_rest" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -tooltip_text = "More settings" -theme_type_variation = &"button_icon_only" -toggle_mode = true -icon = ExtResource("10_01bp8") -icon_alignment = 1 -expand_icon = true - -[node name="settings_panel" type="PanelContainer" parent="HBoxContainer/show_rest"] -visible = false -layout_mode = 1 -offset_left = -558.0 -offset_top = -309.0 -offset_right = 32.0 - -[node name="HBoxContainer2" type="HBoxContainer" parent="HBoxContainer/show_rest/settings_panel"] -layout_mode = 2 - -[node name="tilt" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2" instance=ExtResource("6_bsspt")] -layout_mode = 2 -size_flags_horizontal = 4 -tooltip_text = "Change Tilt -Hotkey: R" - -[node name="scale" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2" instance=ExtResource("6_bsspt")] -layout_mode = 2 -size_flags_horizontal = 4 -tooltip_text = "Change Tilt -Hotkey: E" - -[node name="ScrollContainer" type="ScrollContainer" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="FlowContainer" type="VBoxContainer" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2/ScrollContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="depth_test" type="CheckBox" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2/ScrollContainer/FlowContainer"] -visible = false -layout_mode = 2 -tooltip_text = "gizmo line depth test" -text = "Depth Test Connection Lines" -expand_icon = true - -[node name="select_lock" type="CheckBox" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2/ScrollContainer/FlowContainer"] -layout_mode = 2 -tooltip_text = "Keep the Path node selected!" -button_pressed = true -text = " lock selection " -expand_icon = true - -[node name="debug_col" type="CheckBox" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2/ScrollContainer/FlowContainer"] -layout_mode = 2 -tooltip_text = "Collission for debug line in editor! -If activated by clicking on line it will select path node -but it will take more processing power, -So if you have a huge path deactive this!" -button_pressed = true -text = " debug collision" - -[node name="swap_points" type="Button" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2/ScrollContainer/FlowContainer"] -layout_mode = 2 -tooltip_text = "Toggle Connection -Hot-key: shift+T" -text = "Swap" - -[node name="sort_increasing" type="Button" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2/ScrollContainer/FlowContainer"] -layout_mode = 2 -tooltip_text = "sort increasing" -text = "sort" - -[node name="sort_decreasing" type="Button" parent="HBoxContainer/show_rest/settings_panel/HBoxContainer2/ScrollContainer/FlowContainer"] -layout_mode = 2 -tooltip_text = "Toggle Connection -sort decreasing" -text = "sort rev" - -[node name="MarginContainer" type="MarginContainer" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="active_point_label" type="Label" parent="HBoxContainer"] -layout_mode = 2 - -[node name="MarginContainer2" type="MarginContainer" parent="HBoxContainer"] -layout_mode = 2 -theme_override_constants/margin_right = 12 - -[connection signal="pressed" from="HBoxContainer/Button" to="." method="show_mpath_help_window"] -[connection signal="minimum_size_changed" from="HBoxContainer/show_rest" to="." method="_on_show_rest_minimum_size_changed"] -[connection signal="toggled" from="HBoxContainer/show_rest" to="." method="_on_show_rest_toggled"] diff --git a/addons/m_terrain/gui/Save config.gd b/addons/m_terrain/gui/Save config.gd deleted file mode 100644 index 1cf5f0d..0000000 --- a/addons/m_terrain/gui/Save config.gd +++ /dev/null @@ -1,240 +0,0 @@ -@tool -extends TabBar - -@onready var main_window:=$"../../.." -@onready var error = $scroll/VBoxContainer/Error - -@onready var compress_qtq:=$scroll/VBoxContainer/HBoxContainer/compress_qtq -@onready var accuracy:=$scroll/VBoxContainer/HBoxContainer2/LineEdit -@onready var hfile_compress:=$scroll/VBoxContainer/hfilecomrpess/file_compress -@onready var data_compress:=$scroll/VBoxContainer/hb2/data_compress_option -@onready var dfile_compress:=$scroll/VBoxContainer/hb3/file_compress -@onready var data_name_option:=$scroll/VBoxContainer/hb/data_name_option -@onready var is_force_apply_checkbox:=$scroll/VBoxContainer/force_apply_all - - -const default_accuracy:=0.02 -const config_file_name:=".save_config.ini" - -var is_init = false - -var data_state_init:Dictionary -var data_state_final:Dictionary - -var terrain:MTerrain - -func init_save_config(_t:MTerrain): - terrain = _t - if not _t: - error.text = "No Active terrain" - return - if _t.is_grid_created(): - error.text = "Destroy Terrain to be able apply changes" - return - - data_name_option.clear() - var data_dir = _t.dataDir - var first_region_path = data_dir.path_join("x0_y0.res") - if( not ResourceLoader.exists(first_region_path)): - printerr("Can not find "+first_region_path) - error.text = "Can not find "+first_region_path - return - var mres:MResource - mres = ResourceLoader.load(first_region_path) - if not mres: - printerr("Can not load "+first_region_path) - error.text = "Can not load "+first_region_path - return - error.text = "" - error.visible = false - var data_names = mres.compressed_data.keys() - var config_file:=ConfigFile.new() - var config_file_path = data_dir.path_join(config_file_name) - if FileAccess.file_exists(config_file_path): - var err = config_file.load(config_file_path) - if err != OK: - printerr("Can not Load config file with err ",err) - var first_data_name:String="" - for dname in data_names: - var state:Dictionary - var res_file_compress = mres.get_file_compress(dname) - var format = mres.get_data_format(dname) - state["format"] = format - if dname == &"heightmap": - if config_file.has_section_key("heightmap","accuracy"): - state["accuracy"]=float(config_file.get_value("heightmap","accuracy")) - else: - state["accuracy"]=default_accuracy - if config_file.has_section_key("heightmap","compress_qtq"): - state["compress_qtq"]=bool(config_file.get_value("heightmap","compress_qtq")) - else: - state["compress_qtq"]= mres.is_compress_qtq() - if config_file.has_section_key("heightmap","file_compress"): - state["file_compress"]=int(config_file.get_value("heightmap","file_compress")) - else: - state["file_compress"]=res_file_compress - else: - var res_compress = mres.get_compress(dname) - if config_file.has_section_key(dname,"file_compress"): - state["file_compress"]=int(config_file.get_value(dname,"file_compress")) - else: - state["file_compress"] = res_file_compress - if config_file.has_section_key(dname,"compress"): - state["compress"]=int(config_file.get_value(dname,"compress")) - else: - state["compress"] = res_compress - if dname == &"heightmap": - compress_qtq.button_pressed = state["compress_qtq"] - accuracy.text = str(state["accuracy"]) - hfile_compress.select(state["file_compress"]) - else: - data_name_option.add_item(dname) - if first_data_name.is_empty(): - first_data_name = dname - dfile_compress.select(state["file_compress"]) - data_compress.select(state["compress"]) - data_state_init[dname]=state - if not first_data_name.is_empty(): - data_name_option.select(0) - data_state_final = data_state_init.duplicate(true) - is_init = true - -func _on_data_name_option_item_selected(index): - var dname = data_name_option.get_item_text(index) - if(not data_state_final.has(dname)): - printerr("Can not find ",dname) - return - var state:Dictionary = data_state_final[dname] - var keys := state.keys() - for key in keys: - if key == "file_compress": - dfile_compress.select(state["file_compress"]) - elif key == "compress": - data_compress.select(state["compress"]) - - -func _on_data_compress_option_item_selected(index): - var dname = data_name_option.get_item_text(data_name_option.selected) - if(not data_state_final.has(dname)): - printerr("Can not find ",dname) - return - var state:Dictionary = data_state_final[dname] - state["compress"] = index - data_state_final[dname] = state - - -func _on_file_compress_item_selected(index): - var dname = data_name_option.get_item_text(data_name_option.selected) - if(not data_state_final.has(dname)): - printerr("Can not find ",dname) - return - var state:Dictionary = data_state_final[dname] - state["file_compress"] = index - data_state_final[dname] = state - - -func is_changed_image_state(dname:StringName): - if dname!=&"heightmap": - return data_state_final[dname]!=data_state_init[dname] - var state_init = data_state_init[&"heightmap"] - if state_init["compress_qtq"] != compress_qtq.button_pressed: - return true - if abs(state_init["accuracy"] - float(accuracy.text)) > 0.0001: - return true - if state_init["file_compress"] != hfile_compress.selected: - return true - return false - - -func _on_apply_button_up(): - var ac = float(accuracy.text) - if ac < 0.0000001: - printerr("Accuracy can not be less than 0.0000001") - return - if not terrain: - printerr("No Valid Terrain") - return - if not is_init: - printerr("No init") - return - if terrain.is_grid_created(): - printerr("destroy Terrain first") - return - var keys = data_state_init.keys() - var is_force_apply = is_force_apply_checkbox.button_pressed - var has_change = false - for key in keys: - if is_force_apply or is_changed_image_state(key): - has_change = true - break - if not has_change: - print("Nothing to change") - return - var dir = DirAccess.open(terrain.dataDir) - if not dir: - printerr("Can not open ",terrain.dataDir) - return - dir.list_dir_begin() - var file_name :String= dir.get_next() - var res_names:PackedStringArray - while file_name != "": - if file_name.get_extension() == "res": - res_names.append(file_name) - file_name = dir.get_next() - - save_config_file() - for res_name in res_names: - var res_path = terrain.dataDir.path_join(res_name) - var mres = load(res_path) - if not (mres is MResource): - print("Not MResource") - continue - for key in keys: - if not mres.compressed_data.has(key): - printerr("Resource "+res_path+" does not have data "+key) - continue - if key == &"heightmap": - if is_force_apply or is_changed_image_state(&"heightmap"): - apply_update_heightmap(mres) - elif is_force_apply or is_changed_image_state(key): - apply_update_data(key,mres) - ResourceSaver.save(mres,res_path) - main_window.queue_free() - - -func apply_update_heightmap(mres:MResource): - var ac = float(accuracy.text) - var qtq = compress_qtq.button_pressed - var fcompress = hfile_compress.selected - var data = mres.get_heightmap_rf(false) - mres.insert_heightmap_rf(data,ac,qtq,fcompress) - -func apply_update_data(dname:StringName,mres:MResource): - var state = data_state_final[dname] - var fcompress = state["file_compress"] - var compress = state["compress"] - var format = state["format"] - var data = mres.get_data(dname,false) - mres.insert_data(data,dname,format,compress,fcompress) - - -func save_config_file(): - var ac = float(accuracy.text) - var qtq = compress_qtq.button_pressed - var hfcompress = hfile_compress.selected - - - var path = terrain.dataDir.path_join(config_file_name) - var conf := ConfigFile.new() - conf.set_value("heightmap","accuracy",ac) - conf.set_value("heightmap","compress_qtq",qtq) - conf.set_value("heightmap","file_compress",hfcompress) - - var keys = data_state_final.keys() - for key in keys: - if key==&"heightmap": - continue - var state:Dictionary = data_state_final[key] - conf.set_value(key,"file_compress",state["file_compress"]) - conf.set_value(key,"compress",state["compress"]) - conf.save(path) diff --git a/addons/m_terrain/gui/brush_decal.gd b/addons/m_terrain/gui/brush_decal.gd deleted file mode 100644 index 3d4654f..0000000 --- a/addons/m_terrain/gui/brush_decal.gd +++ /dev/null @@ -1,16 +0,0 @@ -@tool -extends Decal -class_name MBrushDecal - -var radius:float=5.0 - -func set_brush_size(input:float): - size.x = input - size.z = input - radius = input/2 - -func get_brush_size()->float: - return size.x - -func change_brush_color(input:Color): - modulate = input diff --git a/addons/m_terrain/gui/brush_decal.tscn b/addons/m_terrain/gui/brush_decal.tscn deleted file mode 100644 index 9cb5be4..0000000 --- a/addons/m_terrain/gui/brush_decal.tscn +++ /dev/null @@ -1,12 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cgvj582ftey6e"] - -[ext_resource type="Texture2D" uid="uid://b5cmhvvnwshvc" path="res://addons/m_terrain/icons/brush.png" id="1_tnwak"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/brush_decal.gd" id="2_ws2n5"] - -[node name="brush_decal" type="Decal"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 41.7598, 0, 20.5917) -sorting_offset = 1.0 -size = Vector3(10, 1000, 10) -texture_albedo = ExtResource("1_tnwak") -modulate = Color(0, 0.435294, 0.027451, 1) -script = ExtResource("2_ws2n5") diff --git a/addons/m_terrain/gui/brush_layers.gd b/addons/m_terrain/gui/brush_layers.gd deleted file mode 100644 index 72b36a9..0000000 --- a/addons/m_terrain/gui/brush_layers.gd +++ /dev/null @@ -1,23 +0,0 @@ -@tool -extends ItemList - - -var no_image = preload("res://addons/m_terrain/icons/no_images.png") - -var index:int -var uniform:String -var brush_name:String - -func create_layers(input:Array): - print("sss input ",input) - var index = -1 - for i in input: - index +=1 - var iname:String= i["name"] - if iname.is_empty(): - iname = "layer "+str(index) - var icon:Texture = i["icon"] - if not icon: - icon = no_image - var id = add_item(iname,icon) - set_item_custom_bg_color(index,i["icon-color"]) diff --git a/addons/m_terrain/gui/brush_layers.tscn b/addons/m_terrain/gui/brush_layers.tscn deleted file mode 100644 index d4f85ca..0000000 --- a/addons/m_terrain/gui/brush_layers.tscn +++ /dev/null @@ -1,11 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://bacapwqdybi81"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/brush_layers.gd" id="1_3au4w"] - -[node name="brush_layers" type="ItemList"] -custom_minimum_size = Vector2(300, 250) -anchors_preset = 10 -anchor_right = 1.0 -grow_horizontal = 2 -max_columns = 4 -script = ExtResource("1_3au4w") diff --git a/addons/m_terrain/gui/channel_brush_control.gd b/addons/m_terrain/gui/channel_brush_control.gd deleted file mode 100644 index 179e225..0000000 --- a/addons/m_terrain/gui/channel_brush_control.gd +++ /dev/null @@ -1,52 +0,0 @@ -@tool -extends HBoxContainer - -@export var is_bit = false -@export var force_int = false -var slider:Slider -var button:CheckBox -var text:LineEdit -func _ready(): - slider = find_child("HSlider") - button = find_child("CheckBox") - text = find_child("LineEdit") - - if not is_bit: - button.toggled.connect(toggle) - slider.editable = false - text.editable = false - - slider.value_changed.connect(value_changed) - text.text = "0" - text.text_changed.connect(text_changed) - - -func value_changed(new_value): - text.text = str(new_value) - if slider.value != new_value: - slider.value = new_value - -func text_changed(new_text): - var caret_position = text.caret_column - if not force_int: - if new_text.to_float() > slider.min_value and new_text.to_float() < slider.max_value: - slider.value = new_text.to_float() - if text.text != str(slider.value): - text.text = str(slider.value) - else: - slider.value = clamp(new_text.to_float(), slider.min_value, slider.max_value) - text.text = str(slider.value) - - else: - if text.text.to_int() == new_text.to_int() and slider.value == new_text.to_int(): return - slider.value = new_text.to_int() - text.text = new_text.to_int() - text.caret_column = caret_position - -func toggle(toggle_on): - slider.editable = toggle_on - text.editable = toggle_on - if not toggle_on: - text.text = "0" - slider.value = 0 - diff --git a/addons/m_terrain/gui/color_layer_creator_panel.tscn b/addons/m_terrain/gui/color_layer_creator_panel.tscn deleted file mode 100644 index 97313f4..0000000 --- a/addons/m_terrain/gui/color_layer_creator_panel.tscn +++ /dev/null @@ -1,198 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://dptq8ffglb0du"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_g0rx7"] -[ext_resource type="PackedScene" uid="uid://c2pjojed3ox4q" path="res://addons/m_terrain/gui/gui_part/data_compress_option.tscn" id="2_rkshc"] -[ext_resource type="PackedScene" uid="uid://bt4wolcb7b55e" path="res://addons/m_terrain/gui/gui_part/file_compress.tscn" id="3_kynmw"] - -[sub_resource type="LabelSettings" id="LabelSettings_50mff"] -font_size = 32 - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bk6nk"] -content_margin_left = 5.0 - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_h7iju"] -content_margin_left = 5.0 - -[node name="PanelContainer" type="PanelContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -theme = ExtResource("1_g0rx7") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 2 - -[node name="Create Color Layer" type="ScrollContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/Create Color Layer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -text = "Create New Color Layer" -label_settings = SubResource("LabelSettings_50mff") -horizontal_alignment = 1 - -[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 - -[node name="layer_name_hbox" type="HBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer/layer_name_hbox"] -layout_mode = 2 -text = "Layer Name:" - -[node name="layer_name" type="LineEdit" parent="VBoxContainer/Create Color Layer/VBoxContainer/layer_name_hbox"] -layout_mode = 2 -placeholder_text = "New Layer Name" -expand_to_text_length = true - -[node name="layer_type" type="HBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer/layer_type"] -layout_mode = 2 -text = "Layer Type" - -[node name="layer_types" type="OptionButton" parent="VBoxContainer/Create Color Layer/VBoxContainer/layer_type"] -layout_mode = 2 -item_count = 5 -selected = 0 -popup/item_0/text = "Color Paint" -popup/item_0/id = 0 -popup/item_1/text = "Channel Painter" -popup/item_1/id = 1 -popup/item_2/text = "Bitwise Brush" -popup/item_2/id = 2 -popup/item_3/text = "Paint 256" -popup/item_3/id = 3 -popup/item_4/text = "Paint 16" -popup/item_4/id = 4 - -[node name="uniform_name_hbox" type="HBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer/uniform_name_hbox"] -layout_mode = 2 -text = "Uniform Name:" - -[node name="uniform_name" type="LineEdit" parent="VBoxContainer/Create Color Layer/VBoxContainer/uniform_name_hbox"] -layout_mode = 2 -expand_to_text_length = true - -[node name="def_color" type="HBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer/def_color"] -layout_mode = 2 -text = "Background Color" - -[node name="ColorPickerButton" type="ColorPickerButton" parent="VBoxContainer/Create Color Layer/VBoxContainer/def_color"] -layout_mode = 2 -text = "-------------" - -[node name="HSeparator" type="HSeparator" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 - -[node name="advanced_settings_button" type="Button" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 4 -text = "Advanced Settings" - -[node name="advanced_settings" type="VBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -visible = false -layout_mode = 2 - -[node name="image_format_vbox" type="HBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings"] -layout_mode = 2 -alignment = 1 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings/image_format_vbox"] -layout_mode = 2 -text = "Image Format" - -[node name="image_format" type="OptionButton" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings/image_format_vbox"] -layout_mode = 2 -item_count = 12 -selected = 5 -popup/item_0/text = "FORMAT_L8" -popup/item_0/id = 0 -popup/item_1/text = "FORMAT_LA8" -popup/item_1/id = 1 -popup/item_2/text = "FORMAT_R8" -popup/item_2/id = 2 -popup/item_3/text = "FORMAT_RG8" -popup/item_3/id = 3 -popup/item_4/text = "FORMAT_RGB8" -popup/item_4/id = 4 -popup/item_5/text = "FORMAT_RGBA8" -popup/item_5/id = 5 -popup/item_6/text = "FORMAT_RGBA4444" -popup/item_6/id = 6 -popup/item_7/text = "FORMAT_RGB565" -popup/item_7/id = 7 -popup/item_8/text = "FORMAT_RF" -popup/item_8/id = 8 -popup/item_9/text = "FORMAT_RGF" -popup/item_9/id = 9 -popup/item_10/text = "FORMAT_RGBF" -popup/item_10/id = 10 -popup/item_11/text = "FORMAT_RGBAF" -popup/item_11/id = 11 - -[node name="data_compress_settings" type="HBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings"] -layout_mode = 2 -alignment = 1 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings/data_compress_settings"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_bk6nk") -text = "Compress" - -[node name="data_compress_option" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings/data_compress_settings" instance=ExtResource("2_rkshc")] -layout_mode = 2 - -[node name="hb3" type="HBoxContainer" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings"] -layout_mode = 2 -alignment = 1 - -[node name="Label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings/hb3"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_h7iju") -text = "File Compress" - -[node name="file_compress" parent="VBoxContainer/Create Color Layer/VBoxContainer/advanced_settings/hb3" instance=ExtResource("3_kynmw")] -layout_mode = 2 -selected = 4 - -[node name="HSeparator3" type="HSeparator" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 - -[node name="instructions_label" type="Label" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -horizontal_alignment = 1 -autowrap_mode = 3 - -[node name="create" type="Button" parent="VBoxContainer/Create Color Layer/VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 4 -text = "Create" - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="close_button" type="Button" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Close" diff --git a/addons/m_terrain/gui/color_layer_creator_window.gd b/addons/m_terrain/gui/color_layer_creator_window.gd deleted file mode 100644 index fcb2221..0000000 --- a/addons/m_terrain/gui/color_layer_creator_window.gd +++ /dev/null @@ -1,185 +0,0 @@ -@tool -extends Window - -signal layer_created - -@onready var layer_name_input:LineEdit = find_child("layer_name") -@onready var uniform_name_input:LineEdit = find_child("uniform_name") -@onready var format_option:OptionButton = find_child("image_format") -@onready var def_color_picker = find_child("ColorPickerButton") -@onready var layer_types:OptionButton = find_child("layer_types") -@onready var file_compress_option = find_child("file_compress") -@onready var compress_option: OptionButton = find_child("data_compress_option") -@onready var instructions_label: Label = find_child("instructions_label") -@onready var create_button:Button = find_child("create") - -@onready var advanced_settings_button:Button = find_child("advanced_settings_button") -@onready var advanced_settings_control:Control = find_child("advanced_settings") - - -const config_file_name:=".save_config.ini" - -var region_grid_size:Vector2i -var image_width:int=0 -var data_dir:="" -var is_init = false - -var active_terrain: MTerrain - -var advanced_settings = false -var uniform_exists = false - -func _ready(): - layer_name_input.text_changed.connect(func(new_text): - validate_settings() - ) - uniform_name_input.text_changed.connect(func(new_text): - validate_settings() - ) - layer_types.item_selected.connect(func(id): - find_child("def_color").visible = id == 0 #color paint - var allowed_formats = [] - format_option.select(Image.FORMAT_RGBA8) - if layer_types.get_item_text(id) == "Paint 16": - format_option.select(Image.FORMAT_RGBA4444) - allowed_formats = [Image.FORMAT_RGBA4444] - if layer_types.get_item_text(id) == "Paint 256": - format_option.select(Image.FORMAT_R8) - allowed_formats = [Image.FORMAT_R8, Image.FORMAT_RG8,Image.FORMAT_RGB8,Image.FORMAT_RGBA8] - - for i in format_option.item_count: - if allowed_formats == []: - format_option.set_item_disabled(i, false) - else: - format_option.set_item_disabled(i, not i in allowed_formats) - - validate_settings() - ) - format_option.item_selected.connect(func(id): - find_child("data_compress_settings").visible = id in [Image.FORMAT_L8, Image.FORMAT_RGB8, Image.FORMAT_RGBA8] - compress_option.set_item_disabled(1, not id in [Image.FORMAT_RGB8, Image.FORMAT_RGBA8]) - compress_option.set_item_disabled(2, not id in [Image.FORMAT_L8, Image.FORMAT_RGB8, Image.FORMAT_RGBA8]) - validate_settings() - ) - find_child("close_button").pressed.connect(_on_close_requested) - create_button.button_up.connect(_on_create_button_up) - - advanced_settings_button.pressed.connect(func(): - advanced_settings_button.visible = false - advanced_settings_control.visible = true - advanced_settings = true - ) - -func validate_settings(): - var instructions = "" - var warnings = "" - var existing_layers = active_terrain.brush_layers.map(func(a):return a.layers_title) - advanced_settings_button.visible = true - advanced_settings_control.visible = false - if layer_name_input.text.strip_edges() == "": - instructions += "Please enter a Layer Name\n" - elif layer_name_input.text == "" or layer_name_input.text in existing_layers: - instructions += "Layer name aleady exists.\n" - if uniform_name_input.text == "": - instructions += "Please enter a Uniform Name\n" - elif uniform_name_input.text in active_terrain.brush_layers.map(func(a): return a.uniform_name): - var others_mode = active_terrain.brush_layers.filter(func(a): return a.uniform_name == uniform_name_input.text).map(func(a): return a.brush_name) - if "Color Paint" in others_mode or layer_types.selected == 0: - instructions += "Uniform already exists. Cannot share uniform in Color Paint mode" - warnings += "This layer is about to share a Uniform with another layer. Please be careful with how you combine brushes" - advanced_settings_button.visible = false - advanced_settings_control.visible = false - uniform_exists = true - elif uniform_name_input.text in active_terrain.get_image_list(): - warnings += "This layer is about to connect with an existing uniform image" - uniform_exists = true - else: - uniform_exists = false - warnings += str("Creating new image uniform. \nTo use in shader you need to add \n`uniform sampler2d mterrain_",uniform_name_input.text, "` to your shader \nthen restart the terrain") - - instructions_label.text = warnings if instructions == "" else instructions - create_button.disabled = instructions != "" - - -func set_terrain(input:MTerrain): - active_terrain = input - active_terrain.save_all_dirty_images() - validate_settings.call_deferred() - if input.terrain_size.x % input.region_size !=0: - printerr("Terrain size.x is not divisible by its region size") - return - if input.terrain_size.x % input.region_size !=0: - printerr("Terrain size.y is not divisible by its region size") - return - region_grid_size.x = input.terrain_size.x/input.region_size - region_grid_size.y = input.terrain_size.x/input.region_size - image_width = ((input.region_size*input.get_base_size())/input.get_h_scale()) - data_dir = input.dataDir - is_init = true - ## Setting image list - var first_path = data_dir.path_join("x0_y0.res") - if not ResourceLoader.exists(first_path): - return - var mres = ResourceLoader.load(first_path) - if not (mres is MResource): - return - var data_names:Array= mres.compressed_data.keys() - #for dname in data_names: - # remove_uniform_list.add_item(dname) - #remove_uniform_list.select(-1) - -func _on_close_requested(): - queue_free() - -func _on_create_button_up(): - if not is_init: - printerr("Image create/remove is not init") - return - var format:int = format_option.get_selected_id() - var uniform_name:String = uniform_name_input.text - var def_color:Color=def_color_picker.color - var file_compress = file_compress_option.selected - var compress = compress_option.selected - if not uniform_exists: - var dir = DirAccess.open(data_dir) - if not dir: - printerr("Can not open ",data_dir) - return - for j in range(region_grid_size.y): - for i in range(region_grid_size.x): - var path = data_dir.path_join("x"+str(i)+"_y"+str(j)+".res") - var mres:MResource - if ResourceLoader.exists(path): - mres = ResourceLoader.load(path) - else: - mres = MResource.new() - if not (mres is MResource): - continue - var img:Image = Image.create(image_width,image_width,false,format) - img.fill(def_color) - mres.insert_data(img.get_data(),uniform_name,format,compress,file_compress) - ResourceSaver.save(mres,path) - else: - pass - #print("uniform exists") - - init_new_color_layer(layer_name_input.text, uniform_name, def_color) - queue_free() - - -func init_new_color_layer(layer_name, uniform_name, color = null): - active_terrain.brush_layers_groups_num += 1 - var id = active_terrain.brush_layers_groups_num-1 - active_terrain.brush_layers[id] = MBrushLayers.new() - active_terrain.brush_layers[id].layers_title = layer_name - active_terrain.brush_layers[id].uniform_name = uniform_name - active_terrain.brush_layers[id].brush_name = layer_types.get_item_text(layer_types.selected) - active_terrain.brush_layers[id].layers_num = 1 - active_terrain.brush_layers[id].layers[0].NAME = "background" - if layer_types.selected == 0: - active_terrain.brush_layers[id].layers[0].color = color - layer_created.emit(active_terrain.brush_layers[id]) - if active_terrain.is_grid_created(): - active_terrain.restart_grid() - else: - active_terrain.create_grid() diff --git a/addons/m_terrain/gui/color_layer_creator_window.tscn b/addons/m_terrain/gui/color_layer_creator_window.tscn deleted file mode 100644 index 8913405..0000000 --- a/addons/m_terrain/gui/color_layer_creator_window.tscn +++ /dev/null @@ -1,17 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://gsibulkr5nt"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_f6oq8"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/color_layer_creator_window.gd" id="1_ietn6"] -[ext_resource type="PackedScene" uid="uid://dptq8ffglb0du" path="res://addons/m_terrain/gui/color_layer_creator_panel.tscn" id="3_ep3fc"] - -[node name="image_creator_window" type="Window"] -initial_position = 1 -size = Vector2i(550, 600) -wrap_controls = true -popup_window = true -theme = ExtResource("1_f6oq8") -script = ExtResource("1_ietn6") - -[node name="PanelContainer" parent="." instance=ExtResource("3_ep3fc")] - -[connection signal="close_requested" from="." to="." method="_on_close_requested"] diff --git a/addons/m_terrain/gui/control_prop_element/bool.gd b/addons/m_terrain/gui/control_prop_element/bool.gd deleted file mode 100644 index 0ab0279..0000000 --- a/addons/m_terrain/gui/control_prop_element/bool.gd +++ /dev/null @@ -1,21 +0,0 @@ -@tool -extends BoxContainer - -signal prop_changed - -var prop_name:String -var value:bool - - -func set_name(input:String): - prop_name = input - $label.text = input - -func set_value(input:bool): - value = input - $Control/CheckButton.button_pressed = input - - -func _on_check_button_toggled(button_pressed): - value = button_pressed - emit_signal("prop_changed",prop_name,value) diff --git a/addons/m_terrain/gui/control_prop_element/bool.tscn b/addons/m_terrain/gui/control_prop_element/bool.tscn deleted file mode 100644 index f1ac2ff..0000000 --- a/addons/m_terrain/gui/control_prop_element/bool.tscn +++ /dev/null @@ -1,40 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://drpc7g4qxdu8p"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/control_prop_element/bool.gd" id="1_j602s"] - -[node name="bool" type="VBoxContainer"] -offset_right = 55.0 -offset_bottom = 115.0 -script = ExtResource("1_j602s") - -[node name="Control" type="Control" parent="."] -custom_minimum_size = Vector2(24, 88) -layout_mode = 2 -size_flags_vertical = 3 -mouse_filter = 1 - -[node name="CheckButton" type="CheckButton" parent="Control"] -layout_mode = 1 -anchors_preset = 7 -anchor_left = 0.5 -anchor_top = 1.0 -anchor_right = 0.5 -anchor_bottom = 1.0 -offset_left = -24.0 -offset_top = -1.0 -offset_right = 20.0 -offset_bottom = 23.0 -grow_horizontal = 2 -grow_vertical = 0 -rotation = -1.5708 -mouse_filter = 1 -theme_type_variation = &"button_icon_only" - -[node name="label" type="Label" parent="."] -layout_mode = 2 -size_flags_horizontal = 4 -text = "bool var " -horizontal_alignment = 1 -uppercase = true - -[connection signal="toggled" from="Control/CheckButton" to="." method="_on_check_button_toggled"] diff --git a/addons/m_terrain/gui/control_prop_element/float.gd b/addons/m_terrain/gui/control_prop_element/float.gd deleted file mode 100644 index 9d50a72..0000000 --- a/addons/m_terrain/gui/control_prop_element/float.gd +++ /dev/null @@ -1,39 +0,0 @@ -@tool -extends BoxContainer - -signal prop_changed - -var prop_name:String -var value:float -var max:float = 1000000000000000000 -var min:float = -100000000000000000 - -func set_max(input): - max=input - -func set_min(input): - max=input - - -func set_name(input:String): - prop_name = input - $label.text = input - -func set_value(input:float): - value = input - $value.text = str(input) - -func _on_value_text_submitted(new_text:String): - if new_text.is_valid_float(): - value = new_text.to_float() - if value>max: - value = max - if valuemax: - new_value = max - if new_valueint: - path = path.to_lower() - var reg = RegEx.new() - reg.compile(prefix+"(\\d+)") - var result := reg.search(path) - if not result: - return -1 - return result.strings[1].to_int() - -func _on_import_pressed(): - err.visible = false - file_path= select_file_line.text - ext = select_file_line.text.get_extension() - save_path= save_folder_line.text - region_size = region_size_line.text.to_int() - unifrom_name = unform_name_line.text - width = width_line.text.to_int() - height = height_line.text.to_int() - min_height = min_height_line.text.to_float() - max_height = max_height_line.text.to_float() - image_format = image_format_option.get_selected_id() - flip_x = flip_x_checkbox.button_pressed - flip_y = flip_y_checkbox.button_pressed - compress_qtq = compress_qtq_checkbox.button_pressed - file_compress = file_compress_option.selected - compress = data_compress_option.selected - accuracy = float(accuracy_line.text) - if is_heightmap and accuracy < 0.000001: - perr("Accuracy can not be less than 0.000001") - return - if unifrom_name == "": - perr("Uniform name is empty") - return - var x = get_integer_inside_string("x",file_path) - var y = get_integer_inside_string("y",file_path) - #In this case there is no tile and we should tile that - if(x==-1 or y==-1): - import_no_tile() - else: #And in this case there is tiled already and regions size will ignored - import_tile() - -func is_valid_2n_plus_one(input:int): - if input<3: - return false - input -= 1 - while true: - if input == 1: - return true - if input%2!=0: - return false - input /=2 - -func is_power_of_two(input:int): - while true: - if input == 1: - return true - if input%2!=0: - return false - input /=2 - -func import_no_tile(): - if(region_size<32): - perr("Region size can not be smaller than 32") - return - if(not is_power_of_two(region_size)): - perr("Region size must be 2^n, like 16, 32, 256 ...") - return - if(save_path.is_empty()): - perr("Save path is empty") - return - var img:Image - if ext=="r16": - img=MTool.get_r16_image(file_path,width,height,min_height,max_height,false) - else: - img = Image.load_from_file(file_path) - if not img: - perr("Can not load image") - return - var img_size = img.get_size() - if ext!="r16" and is_heightmap: - img.convert(Image.FORMAT_RF) - var data = img.get_data().to_float32_array() - for i in range(0,data.size()): - data[i] *= (max_height - min_height) - data[i] += min_height - img = Image.create_from_data(img_size.x,img_size.y,false,Image.FORMAT_RF, data.to_byte_array()) - var region_grid_size:= Vector2i() - - region_grid_size.x = ceil(float(img_size.x)/(region_size)) - region_grid_size.y = ceil(float(img_size.y)/(region_size)) - var total_regions = region_grid_size.x*region_grid_size.y - if(total_regions>9000000): - perr("make region size bigger, too many regions, region count: "+str(total_regions)) - return - if is_heightmap: - update_config_file_for_heightmap() - else: - update_config_file_for_data() - for y in range(0, region_grid_size.x): - for x in range(0, region_grid_size.y): - var r_save_name:String = "x"+str(x)+"_y"+str(y)+".res" - var r_path:String = save_path.path_join(r_save_name) - var pos:=Vector2i(x,y) - pos *= (region_size) - if abs(pos.x - img_size.x) < 2 or abs(pos.y - img_size.y) < 2: - continue - var rect = Rect2i(pos, Vector2i(region_size,region_size)); - var region_img:= img.get_region(rect) - if(image_format>=0 and not is_heightmap): - region_img.convert(image_format) - var mres:MResource - if ResourceLoader.exists(r_path): - var mres_loaded = ResourceLoader.load(r_path) - if mres_loaded: - if mres_loaded is MResource: - mres = mres_loaded - if not mres: - mres = MResource.new() - if is_heightmap: - mres.insert_heightmap_rf(region_img.get_data(),accuracy,compress_qtq,file_compress) - else: - mres.insert_data(region_img.get_data(),unifrom_name,region_img.get_format(),compress,file_compress) - ResourceSaver.save(mres,r_path) - queue_free() - -func get_file_path(x:int,y:int,path_pattern:String)->String: - var regx = RegEx.new() - var regy = RegEx.new() - var patternx = "(?i)(x)(\\d+)" - var paterrny = "(?i)(y)(\\d+)" - regx.compile(patternx) - regy.compile(paterrny) - var resx = regx.search(path_pattern) - var resy = regy.search(path_pattern) - ## This is because in some cases we have x1 in other cases we have x01 - for i in range(1,4): - var digit_pattern = "%0"+str(i)+"d" - var xstr = digit_pattern % x - var ystr = digit_pattern % y - var sub = regx.sub(path_pattern, resx.strings[1]+xstr) - sub = regy.sub(sub, resy.strings[1]+ystr) - if FileAccess.file_exists(sub): - return sub - return "" - -func import_tile(): - var tiled_files:Dictionary - var x:int=0 - var y:int=0 - var x_size = 0 - var y_size = 0 - while true: - var r_path = get_file_path(x,y,file_path) - if(r_path == ""): - x = 0 - y += 1 - r_path = get_file_path(x,y,file_path) - if(r_path == ""): - if tiled_files.is_empty(): - perr("Can't find first tile x=0 and y=0") - return - break - tiled_files[Vector2i(x,y)] = r_path - if x > x_size: x_size = x - if y > y_size: y_size = y - x+=1 - if flip_y: - var tmp:Dictionary - var j = y_size - var oj = 0 - while j>= 0: - for i in range(0,x_size+1): - tmp[Vector2i(i,oj)] = tiled_files[Vector2i(i,j)] - j-=1 - oj+=1 - tiled_files = tmp - if flip_x: - var tmp:Dictionary - var i = y_size - var oi = 0 - while i>= 0: - for j in range(0,y_size+1): - tmp[Vector2i(oi,j)] = tiled_files[Vector2i(i,j)] - i-=1 - oi+=1 - tiled_files = tmp - for i in range(0,x_size+1): - for j in range(0,y_size+1): - var r_path = tiled_files[Vector2i(i,j)] - var r_save_name:String = "x"+str(i)+"_y"+str(j)+".res" - var r_save_path:String = save_path.path_join(r_save_name) - var img:Image - if ext == "r16": - img=MTool.get_r16_image(r_path,0,0,min_height,max_height,false) - else: - img = Image.load_from_file(r_path) - if not img: - perr("Can not load image") - return - if img.get_size().x != img.get_size().y: - perr("In tiled mode image width and height should be equal") - return - if not is_power_of_two(img.get_size().x): - perr("In tiled mode image height and width should be in power of two") - return - var img_size = img.get_size().x - if ext!="r16" and is_heightmap: - img.convert(Image.FORMAT_RF) - var data = img.get_data().to_float32_array() - for d in range(0,data.size()): - data[d] *= (max_height - min_height) - data[d] += min_height - img = Image.create_from_data(img_size,img_size,false,Image.FORMAT_RF, data.to_byte_array()) - if(image_format>=0 and not is_heightmap): - img.convert(image_format) - print("path ", img.get_path()) - var mres:MResource - if ResourceLoader.exists(r_save_path): - var mres_loaded = ResourceLoader.load(r_save_path) - if mres_loaded: - if mres_loaded is MResource: - mres = mres_loaded - if not mres: - mres = MResource.new() - if is_heightmap: - mres.insert_heightmap_rf(img.get_data(),accuracy,compress_qtq,file_compress) - else: - mres.insert_data(img.get_data(),unifrom_name,img.get_format(),compress,file_compress) - ResourceSaver.save(mres, r_save_path) - ### Now Correcting the edges - #correct_edges(unifrom_name, tmp_path) - queue_free() - - -func get_img_or_black(x:int,y:int,u_name:String,dir:String,size:Vector2i,format:int)->Image: - var file_name = u_name + "_x"+str(x)+"_y"+str(y)+".res" - var path = dir.path_join(file_name) - if ResourceLoader.exists(path): - return load(path) - else: - var img:= Image.create(size.x,size.y,false,format) - img.fill(Color(-10000000000, 0,0)) - return img - -func correct_edges(u_name:String, dir:String): - var x:int =0 - var y:int =0 - while true: - var file_name = u_name + "_x"+str(x)+"_y"+str(y)+".res" - var path = dir.path_join(file_name) - if !ResourceLoader.exists(path): - x = 0 - y+=1 - file_name = u_name + "_x"+str(x)+"_y"+str(y)+".res" - path = dir.path_join(file_name) - if !ResourceLoader.exists(path): - break - var img:Image = load(path) - var size = img.get_size() - var right_img:Image = get_img_or_black(x+1,y,u_name,dir,size,img.get_format()) - var bottom_img:Image = get_img_or_black(x,y+1,u_name,dir,size,img.get_format()) - var right_bottom_img:Image = get_img_or_black(x+1,y+1,u_name,dir,size,img.get_format()) - img = img.get_region(Rect2i(0,0,size.x+1,size.y+1)) - ##Correct right side - for j in range(0,size.y): - var col = right_img.get_pixel(0, j) - img.set_pixel(size.x, j, col) - ##Correct bottom side - for i in range(0,size.x): - var col = bottom_img.get_pixel(i, 0) - img.set_pixel(i , size.y, col) - ##Correct right bottom corner - var col = right_bottom_img.get_pixel(0,0) - img.set_pixel(size.x , size.y, col) - var save_name = u_name + "_x"+str(x)+"_y"+str(y)+".res" - var r_save_path = save_path.path_join(save_name) - ResourceSaver.save(img, r_save_path) - print("save ", r_save_path) - x+=1 - - -func perr(msg:String): - err.visible = true - err.text = msg - printerr(msg) - - -func update_config_file_for_heightmap(): - var path = save_path.path_join(config_file_name) - var conf := ConfigFile.new() - if FileAccess.file_exists(path): - var err = conf.load(path) - if err != OK: - printerr("Can not load conf file") - conf.set_value("heightmap","accuracy",accuracy) - conf.set_value("heightmap","file_compress",file_compress) - conf.set_value("heightmap","compress_qtq",compress_qtq) - conf.save(path) - -func update_config_file_for_data(): - var path = save_path.path_join(config_file_name) - var conf := ConfigFile.new() - if FileAccess.file_exists(path): - var err = conf.load(path) - if err != OK: - printerr("Can not load conf file") - conf.set_value(unifrom_name,"compress",compress) - conf.set_value(unifrom_name,"file_compress",file_compress) - conf.save(path) - - -###################### Export -@onready var export_err := $tab/export/export_err -@onready var einfo := $tab/export/einfo -@onready var edata_name_option := $tab/export/edata_name_option -@onready var eformat_option := $tab/export/eformat_option -@onready var export_hc := $tab/export/export_hc -@onready var emin_line := $tab/export/export_hc/min -@onready var emax_line := $tab/export/export_hc/max -@onready var export_path_line := $tab/export/HBoxContainer/LineEdit -@onready var file_dialog_export := $FileDialog_export - -var active_terrain:MTerrain -const format_for_heightmap := ["OpenEXR","raw16","Godot res"] -const format_for_data := ["PNG","Godot res"] -const format_for_all := ["Godot res"] - -var ednames:PackedStringArray - -func init_export(_t:MTerrain): - edata_name_option.clear() - eformat_option.clear() - export_err.visible = false - einfo.visible = false - var first_path = _t.dataDir.path_join("x0_y0.res") - if not ResourceLoader.exists(first_path): - print_export_err("Can not find Data "+first_path) - return - var mres:MResource - var mres_load = ResourceLoader.load(first_path) - if not mres_load: - print_export_err("Can not load "+first_path) - return - if not(mres_load is MResource): - print_export_err(first_path+" is not a MResource type") - return - mres = mres_load - var data_names = mres.compressed_data.keys() - for dname in data_names: - edata_name_option.add_item(dname) - ednames.push_back(dname) - edata_name_option.add_item("all") - edata_name_option.select(-1) - active_terrain = _t - - - -func _on_edata_name_option_item_selected(index): - if index < 0: return - var dname = edata_name_option.get_item_text(index) - eformat_option.clear() - var is_h = dname == "heightmap" - export_hc.visible = is_h - einfo.visible = true - if is_h: - einfo.text="Min and Max height are used for normalizing heightmap before export, Godot res format does need this, Auto detect can take a while" - elif dname != "all": - einfo.text="PNG only support: L8,RGB8,RGBA8 using other format will automatically converted to these" - else: - einfo.visible = false - if is_h: - for o in format_for_heightmap: - eformat_option.add_item(o) - elif dname == "all": - einfo.visible - for o in format_for_all: - eformat_option.add_item(o) - else: - for o in format_for_data: - eformat_option.add_item(o) - eformat_option.select(-1) - -func _on_auto_min_max_detect_button_up(): - if not active_terrain: - print_export_err("No active Terrain") - return - var first_path = active_terrain.dataDir.path_join("x0_y0.res") - if not ResourceLoader.exists(first_path): - print_export_err("Can not find Data "+first_path) - return - var mres:MResource - var mres_load = ResourceLoader.load(first_path) - if not mres_load: - print_export_err("Can not load "+first_path) - return - if not(mres_load is MResource): - print_export_err(first_path+" is not a MResource type") - return - mres = mres_load - var min_height:float=mres.get_min_height() - var max_height:float=mres.get_max_height() - var x:int=1 - var y:int=0 - while true: - var path = active_terrain.dataDir.path_join("x"+str(x)+"_y"+str(y)+".res") - if not ResourceLoader.exists(path): - y+=1 - x=0 - path = active_terrain.dataDir.path_join("x"+str(x)+"_y"+str(y)+".res") - if not ResourceLoader.exists(path): - break - x+=1 - mres_load = ResourceLoader.load(path) - if not mres_load: - continue - if not (mres_load is MResource): - continue - mres = mres_load - if min_height > mres.get_min_height(): - min_height = mres.get_min_height() - if max_height < mres.get_max_height(): - max_height = mres.get_max_height() - emin_line.text = str(min_height) - emax_line.text = str(max_height) - -func _on_export_path_btn_button_up(): - file_dialog_export.visible = true - -func _on_file_dialog_export_dir_selected(dir): - export_path_line.text = dir - -func _on_export_btn_button_up(): - if edata_name_option.selected < 0: - print_export_err("No data name selected") - return - var selected_dname = edata_name_option.get_item_text(edata_name_option.selected) - if selected_dname.is_empty(): - print_export_err("data name is empty") - return - if eformat_option.selected < 0: - print_export_err("No export format selected") - return - var export_format = eformat_option.get_item_text(eformat_option.selected) - if export_format.is_empty(): - print_export_err("Format name is empty") - return - if not active_terrain: - print_export_err("No active Terrain") - return - if selected_dname == "all": - for ee in ednames: - export_data(ee,export_format) - else: - export_data(selected_dname,export_format) - queue_free() - -func export_data(dname:String,eformat:String): - var export_path :String = export_path_line.text - var min_height:float = float(emin_line.text) - var max_height:float = float(emax_line.text) - if (max_height - min_height <=0.000001) and dname == "heightmap" and eformat != "Godot res": - print_export_err("Min and Max height are not set") - return - if export_path.is_empty(): - print_export_err("Export path is empty") - return - if not export_path.is_absolute_path(): - print_export_err("Export path is not a valid absoulute path") - return - var mres_load - var mres:MResource - var x:int=0 - var y:int=0 - while true: - var path = active_terrain.dataDir.path_join("x"+str(x)+"_y"+str(y)+".res") - if not ResourceLoader.exists(path): - y+=1 - x=0 - path = active_terrain.dataDir.path_join("x"+str(x)+"_y"+str(y)+".res") - if not ResourceLoader.exists(path): - break - mres_load = ResourceLoader.load(path) - if not mres_load: - print_export_err("Can not load "+path) - continue - if not (mres_load is MResource): - print_export_err(path+" is not MResource type") - continue - mres = mres_load - var data:PackedByteArray - var img_format:int=-1 - var width:int - if dname == "heightmap": - data = mres.get_heightmap_rf(false) - img_format = Image.FORMAT_RF - else: - data = mres.get_data(dname,false) - if data.size() == 0: - print_export_err("Something wrong can not save "+path) - continue - width = mres.get_data_width(dname) - if dname != "heightmap": - img_format = mres.get_data_format(dname) - var path_no_ext = export_path.path_join(dname+"_x"+str(x)+"_y"+str(y)) - if eformat == "raw16": - var final_epath = path_no_ext + ".r16" - MTool.write_r16(final_epath,data,min_height,max_height) - elif eformat == "OpenEXR": - var final_epath = path_no_ext + ".exr" - if dname == "heightmap": - data = MTool.normalize_rf_data(data,min_height,max_height) - var img:=Image.create_from_data(width,width,false,img_format,data) - if dname == "heightmap": - img.save_exr(final_epath,true) - else: - img.save_exr(final_epath) - elif eformat == "PNG": - var final_epath = path_no_ext + ".png" - var img:=Image.create_from_data(width,width,false,img_format,data) - img.save_png(final_epath) - elif eformat == "Godot res": - var final_epath = path_no_ext + ".res" - var img:=Image.create_from_data(width,width,false,img_format,data) - ResourceSaver.save(img,final_epath) - else: - print_export_err("Unknow export format") - return - x+=1 - - -func print_export_err(msg:String): - export_err.visible = true - export_err.text = msg - printerr(msg) diff --git a/addons/m_terrain/gui/import_window.tscn b/addons/m_terrain/gui/import_window.tscn deleted file mode 100644 index 577be39..0000000 --- a/addons/m_terrain/gui/import_window.tscn +++ /dev/null @@ -1,495 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://bi64wdm5e26po"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/import_window.gd" id="1_1yy7h"] -[ext_resource type="PackedScene" uid="uid://c2pjojed3ox4q" path="res://addons/m_terrain/gui/gui_part/data_compress_option.tscn" id="2_7c003"] -[ext_resource type="PackedScene" uid="uid://bt4wolcb7b55e" path="res://addons/m_terrain/gui/gui_part/file_compress.tscn" id="3_6huwx"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/import Godot res.gd" id="4_wj43a"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cs33g"] -content_margin_left = 5.0 -bg_color = Color(0.337255, 0.372549, 0.266667, 1) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_unhvj"] -bg_color = Color(0.152941, 0.360784, 0.32549, 0.482353) - -[node name="import_window" type="Window"] -title = "MTerrain Import/export" -initial_position = 1 -size = Vector2i(560, 560) -script = ExtResource("1_1yy7h") - -[node name="tab" type="TabContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="import" type="VBoxContainer" parent="tab"] -layout_mode = 2 - -[node name="err" type="Label" parent="tab/import"] -visible = false -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.580392, 0.580392, 1) -theme_override_styles/normal = SubResource("StyleBoxFlat_cs33g") -autowrap_mode = 2 - -[node name="title" type="Label" parent="tab/import"] -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.65098, 0.423529, 1) -theme_override_font_sizes/font_size = 30 -theme_override_styles/normal = SubResource("StyleBoxFlat_unhvj") -text = "Import" -horizontal_alignment = 1 -vertical_alignment = 1 -autowrap_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="tab/import"] -layout_mode = 2 - -[node name="Button" type="Button" parent="tab/import/HBoxContainer"] -layout_mode = 2 -text = "select" - -[node name="filepath_line" type="LineEdit" parent="tab/import/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "File Path" - -[node name="image_dimension" type="HBoxContainer" parent="tab/import"] -visible = false -layout_mode = 2 - -[node name="Button" type="Label" parent="tab/import/image_dimension"] -layout_mode = 2 -text = "Image Dimension " - -[node name="width" type="LineEdit" parent="tab/import/image_dimension"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "width" - -[node name="height" type="LineEdit" parent="tab/import/image_dimension"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "height" - -[node name="flips" type="HBoxContainer" parent="tab/import"] -visible = false -layout_mode = 2 - -[node name="flip_x" type="CheckBox" parent="tab/import/flips"] -layout_mode = 2 -text = "Flip X" - -[node name="flip_y" type="CheckBox" parent="tab/import/flips"] -layout_mode = 2 -button_pressed = true -text = "Flip Y" - -[node name="Label" type="Label" parent="tab/import/flips"] -layout_mode = 2 -theme_override_colors/font_color = Color(0.878431, 0.596078, 0.172549, 1) -theme_override_font_sizes/font_size = 14 -text = "Deactive flip if this exported from MTerrain" - -[node name="HBoxContainer2" type="HBoxContainer" parent="tab/import"] -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/import/HBoxContainer2"] -layout_mode = 2 -text = "Region Size in pixel:" - -[node name="region_size_line" type="LineEdit" parent="tab/import/HBoxContainer2"] -layout_mode = 2 -text = "0" - -[node name="is_heightmap_checkbox" type="CheckButton" parent="tab/import"] -layout_mode = 2 -text = "Is Heightmap" - -[node name="min_height" type="HBoxContainer" parent="tab/import"] -visible = false -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/import/min_height"] -layout_mode = 2 -text = "min height:" - -[node name="min_height_line" type="LineEdit" parent="tab/import/min_height"] -layout_mode = 2 -text = "0" - -[node name="max_height" type="HBoxContainer" parent="tab/import"] -visible = false -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/import/max_height"] -layout_mode = 2 -text = "max height:" - -[node name="max_height_line" type="LineEdit" parent="tab/import/max_height"] -layout_mode = 2 -text = "1" - -[node name="uniform_name" type="HBoxContainer" parent="tab/import"] -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/import/uniform_name"] -layout_mode = 2 -text = "Uniform name:" - -[node name="uniform_name_line" type="LineEdit" parent="tab/import/uniform_name"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="uniform_name2" type="HBoxContainer" parent="tab/import"] -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/import/uniform_name2"] -layout_mode = 2 -text = "Format Enum number" - -[node name="image_format_option" type="OptionButton" parent="tab/import/uniform_name2"] -layout_mode = 2 -item_count = 12 -popup/item_0/text = "FORMAT_L8" -popup/item_0/id = 0 -popup/item_1/text = "FORMAT_LA8" -popup/item_1/id = 1 -popup/item_2/text = "FORMAT_R8" -popup/item_2/id = 2 -popup/item_3/text = "FORMAT_RG8" -popup/item_3/id = 3 -popup/item_4/text = "FORMAT_RGB8" -popup/item_4/id = 4 -popup/item_5/text = "FORMAT_RGBA8" -popup/item_5/id = 5 -popup/item_6/text = "FORMAT_RGBA4444" -popup/item_6/id = 6 -popup/item_7/text = "FORMAT_RGB565" -popup/item_7/id = 7 -popup/item_8/text = "FORMAT_RF" -popup/item_8/id = 8 -popup/item_9/text = "FORMAT_RGF" -popup/item_9/id = 9 -popup/item_10/text = "FORMAT_RGBF" -popup/item_10/id = 10 -popup/item_11/text = "FORMAT_RGBAF" -popup/item_11/id = 11 - -[node name="compress_qtq" type="CheckBox" parent="tab/import"] -visible = false -layout_mode = 2 -button_pressed = true -text = "compress_qtq" - -[node name="uniform_name3" type="HBoxContainer" parent="tab/import"] -visible = false -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/import/uniform_name3"] -layout_mode = 2 -text = "Accuracy" - -[node name="accuracy" type="LineEdit" parent="tab/import/uniform_name3"] -layout_mode = 2 -text = "0.02" - -[node name="data_compress_option" parent="tab/import" instance=ExtResource("2_7c003")] -layout_mode = 2 - -[node name="file_compress" parent="tab/import" instance=ExtResource("3_6huwx")] -layout_mode = 2 - -[node name="save" type="HBoxContainer" parent="tab/import"] -layout_mode = 2 - -[node name="save_folder_button" type="Button" parent="tab/import/save"] -layout_mode = 2 -text = "select" - -[node name="save_folder_line" type="LineEdit" parent="tab/import/save"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "Save folder" - -[node name="import" type="Button" parent="tab/import"] -layout_mode = 2 -text = "Import" - -[node name="export" type="VBoxContainer" parent="tab"] -visible = false -layout_mode = 2 - -[node name="title2" type="Label" parent="tab/export"] -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.65098, 0.423529, 1) -theme_override_font_sizes/font_size = 30 -theme_override_styles/normal = SubResource("StyleBoxFlat_unhvj") -text = "Export" -horizontal_alignment = 1 -vertical_alignment = 1 -autowrap_mode = 2 - -[node name="export_err" type="Label" parent="tab/export"] -visible = false -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.580392, 0.580392, 1) -theme_override_styles/normal = SubResource("StyleBoxFlat_cs33g") -text = "No Valid Terrain, First select terrain and then reopen this" -autowrap_mode = 2 - -[node name="edata_name_option" type="OptionButton" parent="tab/export"] -layout_mode = 2 -item_count = 3 -popup/item_0/text = "heightmap" -popup/item_0/id = 0 -popup/item_1/text = "splatmap" -popup/item_1/id = 1 -popup/item_2/text = "all" -popup/item_2/id = 2 - -[node name="eformat_option" type="OptionButton" parent="tab/export"] -layout_mode = 2 - -[node name="einfo" type="Label" parent="tab/export"] -visible = false -layout_mode = 2 -autowrap_mode = 2 - -[node name="export_hc" type="HBoxContainer" parent="tab/export"] -visible = false -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/export/export_hc"] -layout_mode = 2 -text = "min" - -[node name="min" type="LineEdit" parent="tab/export/export_hc"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -text = "0" - -[node name="Label2" type="Label" parent="tab/export/export_hc"] -layout_mode = 2 -text = "max" - -[node name="max" type="LineEdit" parent="tab/export/export_hc"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -text = "0" - -[node name="auto_min_max_detect" type="Button" parent="tab/export/export_hc"] -layout_mode = 2 -text = "Auto" - -[node name="HBoxContainer" type="HBoxContainer" parent="tab/export"] -layout_mode = 2 - -[node name="export_path_btn" type="Button" parent="tab/export/HBoxContainer"] -layout_mode = 2 -text = "Path" - -[node name="LineEdit" type="LineEdit" parent="tab/export/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "Export Folder" - -[node name="HSeparator" type="HSeparator" parent="tab/export"] -layout_mode = 2 - -[node name="export_btn" type="Button" parent="tab/export"] -layout_mode = 2 -text = "Export" - -[node name="import Godot res" type="VBoxContainer" parent="tab"] -visible = false -layout_mode = 2 -script = ExtResource("4_wj43a") - -[node name="title2" type="Label" parent="tab/import Godot res"] -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.65098, 0.423529, 1) -theme_override_font_sizes/font_size = 30 -theme_override_styles/normal = SubResource("StyleBoxFlat_unhvj") -text = "Import Godot res" -horizontal_alignment = 1 -vertical_alignment = 1 -autowrap_mode = 2 - -[node name="import_err" type="Label" parent="tab/import Godot res"] -visible = false -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.580392, 0.580392, 1) -theme_override_styles/normal = SubResource("StyleBoxFlat_cs33g") -autowrap_mode = 2 - -[node name="einfo" type="Label" parent="tab/import Godot res"] -visible = false -layout_mode = 2 -autowrap_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="tab/import Godot res"] -layout_mode = 2 - -[node name="source_dir" type="Button" parent="tab/import Godot res/HBoxContainer"] -layout_mode = 2 -text = "Source Dir" - -[node name="source_line" type="LineEdit" parent="tab/import Godot res/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "Godot res Directory" - -[node name="hcontainer" type="VBoxContainer" parent="tab/import Godot res"] -visible = false -layout_mode = 2 - -[node name="HSeparator2" type="HSeparator" parent="tab/import Godot res/hcontainer"] -layout_mode = 2 - -[node name="HLabel" type="Label" parent="tab/import Godot res/hcontainer"] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 0 -theme_override_colors/font_color = Color(1, 1, 0.219608, 1) -theme_override_font_sizes/font_size = 22 -text = "Heightmap" - -[node name="HSeparator5" type="HSeparator" parent="tab/import Godot res/hcontainer"] -layout_mode = 2 - -[node name="compress_qtq_checkbox" type="CheckBox" parent="tab/import Godot res/hcontainer"] -layout_mode = 2 -button_pressed = true -text = "Compress_qtq" - -[node name="HBoxContainer3" type="HBoxContainer" parent="tab/import Godot res/hcontainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="tab/import Godot res/hcontainer/HBoxContainer3"] -layout_mode = 2 -text = " accuracy" - -[node name="accuracy_line" type="LineEdit" parent="tab/import Godot res/hcontainer/HBoxContainer3"] -layout_mode = 2 -size_flags_horizontal = 0 -text = "0.02" - -[node name="file_compress" parent="tab/import Godot res/hcontainer" instance=ExtResource("3_6huwx")] -layout_mode = 2 - -[node name="dcontainer" type="VBoxContainer" parent="tab/import Godot res"] -visible = false -layout_mode = 2 - -[node name="HSeparator6" type="HSeparator" parent="tab/import Godot res/dcontainer"] -layout_mode = 2 - -[node name="Dlable3" type="Label" parent="tab/import Godot res/dcontainer"] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 0 -theme_override_colors/font_color = Color(1, 1, 0.219608, 1) -theme_override_font_sizes/font_size = 22 -text = "Data" - -[node name="dnames_option" type="OptionButton" parent="tab/import Godot res/dcontainer"] -layout_mode = 2 - -[node name="HSeparator3" type="HSeparator" parent="tab/import Godot res/dcontainer"] -layout_mode = 2 - -[node name="data_compress_option" parent="tab/import Godot res/dcontainer" instance=ExtResource("2_7c003")] -layout_mode = 2 - -[node name="dfile_compress" parent="tab/import Godot res/dcontainer" instance=ExtResource("3_6huwx")] -layout_mode = 2 - -[node name="HSeparator4" type="HSeparator" parent="tab/import Godot res/dcontainer"] -layout_mode = 2 - -[node name="HBoxContainer2" type="HBoxContainer" parent="tab/import Godot res"] -layout_mode = 2 - -[node name="save_dir" type="Button" parent="tab/import Godot res/HBoxContainer2"] -layout_mode = 2 -text = "save" - -[node name="LineEdit" type="LineEdit" parent="tab/import Godot res/HBoxContainer2"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "Save Directory" - -[node name="HSeparator" type="HSeparator" parent="tab/import Godot res"] -layout_mode = 2 - -[node name="import_res_btn" type="Button" parent="tab/import Godot res"] -layout_mode = 2 -text = "Import" - -[node name="FileDialog" type="FileDialog" parent="."] -title = "Open File(s)" -initial_position = 1 -size = Vector2i(508, 450) -ok_button_text = "Open" -file_mode = 1 -access = 2 -filters = PackedStringArray("*.r16", "*.exr", "*.png", "*.bmp", "*.webp", "*.jpg", "*.jpeg") - -[node name="FileDialog_save" type="FileDialog" parent="."] -title = "Open a Directory" -initial_position = 1 -size = Vector2i(508, 450) -ok_button_text = "Select Current Folder" -file_mode = 2 - -[node name="FileDialog_export" type="FileDialog" parent="."] -title = "Open a Directory" -initial_position = 1 -size = Vector2i(508, 450) -ok_button_text = "Select Current Folder" -file_mode = 2 -access = 2 - -[node name="FileDialog_res_source" type="FileDialog" parent="."] -title = "Open a Directory" -initial_position = 1 -size = Vector2i(508, 450) -ok_button_text = "Select Current Folder" -file_mode = 2 -access = 2 - -[node name="FileDialog_res_save" type="FileDialog" parent="."] -title = "Open a Directory" -initial_position = 1 -size = Vector2i(508, 450) -ok_button_text = "Select Current Folder" -file_mode = 2 -access = 2 - -[connection signal="close_requested" from="." to="." method="_on_close_requested"] -[connection signal="button_down" from="tab/import/HBoxContainer/Button" to="." method="_on_button_button_down"] -[connection signal="text_changed" from="tab/import/HBoxContainer/filepath_line" to="." method="_on_filepath_line_text_changed"] -[connection signal="toggled" from="tab/import/is_heightmap_checkbox" to="." method="_on_check_button_toggled"] -[connection signal="pressed" from="tab/import/save/save_folder_button" to="." method="_on_save_folder_button_pressed"] -[connection signal="text_changed" from="tab/import/save/save_folder_line" to="." method="_on_filepath_line_text_changed"] -[connection signal="pressed" from="tab/import/import" to="." method="_on_import_pressed"] -[connection signal="item_selected" from="tab/export/edata_name_option" to="." method="_on_edata_name_option_item_selected"] -[connection signal="button_up" from="tab/export/export_hc/auto_min_max_detect" to="." method="_on_auto_min_max_detect_button_up"] -[connection signal="button_up" from="tab/export/HBoxContainer/export_path_btn" to="." method="_on_export_path_btn_button_up"] -[connection signal="button_up" from="tab/export/export_btn" to="." method="_on_export_btn_button_up"] -[connection signal="button_up" from="tab/import Godot res/HBoxContainer/source_dir" to="tab/import Godot res" method="_on_source_dir_button_up"] -[connection signal="text_changed" from="tab/import Godot res/HBoxContainer/source_line" to="tab/import Godot res" method="_on_source_line_text_changed"] -[connection signal="item_selected" from="tab/import Godot res/dcontainer/dnames_option" to="tab/import Godot res" method="_on_dnames_option_item_selected"] -[connection signal="item_selected" from="tab/import Godot res/dcontainer/data_compress_option" to="tab/import Godot res" method="_on_data_compress_option_item_selected"] -[connection signal="item_selected" from="tab/import Godot res/dcontainer/dfile_compress" to="tab/import Godot res" method="_on_dfile_compress_item_selected"] -[connection signal="button_up" from="tab/import Godot res/HBoxContainer2/save_dir" to="tab/import Godot res" method="_on_save_dir_button_up"] -[connection signal="button_up" from="tab/import Godot res/import_res_btn" to="tab/import Godot res" method="_on_import_res_btn_button_up"] -[connection signal="files_selected" from="FileDialog" to="." method="_on_file_dialog_files_selected"] -[connection signal="dir_selected" from="FileDialog_save" to="." method="_on_file_dialog_save_dir_selected"] -[connection signal="dir_selected" from="FileDialog_export" to="." method="_on_file_dialog_export_dir_selected"] -[connection signal="dir_selected" from="FileDialog_res_source" to="tab/import Godot res" method="_on_file_dialog_res_source_dir_selected"] -[connection signal="dir_selected" from="FileDialog_res_save" to="tab/import Godot res" method="_on_file_dialog_res_save_dir_selected"] diff --git a/addons/m_terrain/gui/layers_title.tscn b/addons/m_terrain/gui/layers_title.tscn deleted file mode 100644 index 5191d94..0000000 --- a/addons/m_terrain/gui/layers_title.tscn +++ /dev/null @@ -1,26 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dm30obl3srq6t"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_46wdk"] -bg_color = Color(0.329412, 0.329412, 0.329412, 1) -border_width_left = 2 -border_width_top = 2 -border_width_right = 2 -border_width_bottom = 2 -border_color = Color(0, 0, 0, 1) - -[node name="layers_title" type="Label"] -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 30.0 -grow_horizontal = 2 -theme_override_colors/font_color = Color(0.882353, 0.905882, 0.529412, 1) -theme_override_colors/font_shadow_color = Color(0.160784, 0.305882, 0, 1) -theme_override_colors/font_outline_color = Color(0.0705882, 0.0627451, 0.0196078, 1) -theme_override_constants/shadow_offset_x = 1 -theme_override_constants/shadow_offset_y = 3 -theme_override_constants/outline_size = 5 -theme_override_constants/shadow_outline_size = 5 -theme_override_font_sizes/font_size = 16 -theme_override_styles/normal = SubResource("StyleBoxFlat_46wdk") -text = "Splatmap" -horizontal_alignment = 1 diff --git a/addons/m_terrain/gui/mask_decal.gd b/addons/m_terrain/gui/mask_decal.gd deleted file mode 100644 index 1dbb69d..0000000 --- a/addons/m_terrain/gui/mask_decal.gd +++ /dev/null @@ -1,152 +0,0 @@ -@tool -extends Decal - -var active_terrain:MTerrain=null - -var is_fix:=false -## Initial current size must be in power of two -var current_size:float = 8 -var angle_offset:Vector3 -var desire_position:Vector3 - -var original_tex:Texture2D -var active_tex:Texture2D -var orignal_image:Image -var active_image:Image - -var is_dirty:=true - -var image_rotation:int=0 - -var wpx:Texture2D - -var is_being_edited = false - -func _ready(): - size.x = current_size - size.z = current_size - angle_offset = Vector3(size.x/2,0,size.z/2) - var img = Image.create(1,1,false,Image.FORMAT_R8) - img.fill(Color(1,1,1,1)) - wpx = ImageTexture.create_from_image(img) - - -func set_absolute_terrain_pos(pos:Vector3, force =false): - if is_dirty: - update_active_image() - if orignal_image: - active_terrain.set_brush_mask(active_image) - else: - active_terrain.disable_brush_mask() - if is_being_edited or force: - var angle_pos = pos - angle_offset - angle_pos -= active_terrain.offset - angle_pos = angle_pos/active_terrain.get_h_scale() - angle_pos = Vector3(round(angle_pos.x),pos.y,round(angle_pos.z)) - var px_pos = Vector2i(angle_pos.x,angle_pos.z) - angle_pos.x *= active_terrain.get_h_scale() - angle_pos.z *= active_terrain.get_h_scale() - angle_pos += active_terrain.offset - desire_position = angle_pos + angle_offset - active_terrain.set_brush_mask_px_pos(px_pos) - set_process(true) - -func increase_size(amount:int=1): - if active_terrain is MTerrain: - change_size(amount) - else: - push_error("trying to set mterrain mask size, but mask has no active_terrain") - -func change_size(amount:float): - if is_fix: return - if current_size < active_terrain.get_h_scale(): - current_size = active_terrain.min_h_scale - current_size += amount * active_terrain.get_h_scale() - if current_size < active_terrain.get_h_scale(): - current_size = active_terrain.get_h_scale() - size.x = current_size - size.z = current_size - var last_pos = position - angle_offset = Vector3(size.x/2,0,size.z/2) - is_dirty = true - set_absolute_terrain_pos(position) - -func set_size(value): - if current_size < active_terrain.get_h_scale(): - current_size = active_terrain.min_h_scale - current_size = value * active_terrain.get_h_scale() - if current_size < active_terrain.get_h_scale(): - current_size = active_terrain.get_h_scale() - size.x = current_size - size.z = current_size - var last_pos = position - angle_offset = Vector3(size.x/2,0,size.z/2) - is_dirty = true - update_active_image() - is_being_edited = true - -func _process(delta): - if (desire_position - position).length() < 0.01: - set_process(false) - position = position.lerp(desire_position,0.15) - - -func set_mask(img:Image,tex:Texture2D): - #image_rotation = 0 - active_tex = tex - orignal_image = img - original_tex = tex - is_dirty = true - if tex: - texture_albedo = tex - albedo_mix = 0.8 - else: - texture_albedo = wpx - albedo_mix = 0.0 - if active_terrain: - update_active_image() - if orignal_image: - active_terrain.set_brush_mask(active_image) - else: - active_terrain.disable_brush_mask() - -func reset_image_rotation(): - image_rotation = 0 - is_dirty = true - update_active_image() - -func rotate_image(amount:int): - image_rotation += amount - image_rotation = image_rotation % 4 - is_dirty = true - update_active_image() - -func set_image_rotation(value:int): - image_rotation = value % 4 - is_dirty = true - update_active_image() - is_being_edited = true - -func update_active_image(): - if not active_terrain:return - is_dirty = false - if orignal_image == null: - return - active_image = orignal_image.duplicate() - if image_rotation != 0: - if image_rotation == 1 or image_rotation == -3: - active_image.rotate_90(CLOCKWISE) - rotation_degrees.y = -90 - if image_rotation == 3 or image_rotation == -1: - active_image.rotate_90(COUNTERCLOCKWISE) - rotation_degrees.y = 90 - elif image_rotation == 2 or image_rotation == -2: - active_image.rotate_180() - rotation_degrees.y = 180 - active_tex = ImageTexture.create_from_image(active_image) - else: - rotation_degrees.y = 0 - - var new_size = current_size/active_terrain.get_h_scale() - active_image.resize(new_size,new_size) - diff --git a/addons/m_terrain/gui/mask_decal.tscn b/addons/m_terrain/gui/mask_decal.tscn deleted file mode 100644 index 6195bb8..0000000 --- a/addons/m_terrain/gui/mask_decal.tscn +++ /dev/null @@ -1,15 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://cu3koya88juu"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/mask_decal.gd" id="1_8ow5o"] - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_ejyee"] - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_cuo2h"] -noise = SubResource("FastNoiseLite_ejyee") - -[node name="stencil_decal" type="Decal"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.87774e-05, 0, 6.1725e-05) -size = Vector3(8, 20000, 8) -texture_albedo = SubResource("NoiseTexture2D_cuo2h") -albedo_mix = 0.8 -script = ExtResource("1_8ow5o") diff --git a/addons/m_terrain/gui/mpath_help_popup.tscn b/addons/m_terrain/gui/mpath_help_popup.tscn deleted file mode 100644 index 0bbbac2..0000000 --- a/addons/m_terrain/gui/mpath_help_popup.tscn +++ /dev/null @@ -1,94 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://dpd66ybtq65sa"] - -[sub_resource type="GDScript" id="GDScript_xqplk"] -script/source = "@tool -extends Window - -func _on_button_pressed(): - queue_free() -" - -[sub_resource type="LabelSettings" id="LabelSettings_cjcwk"] -font_size = 32 - -[node name="Window" type="Window"] -initial_position = 2 -size = Vector2i(600, 450) -exclusive = true -popup_window = true -script = SubResource("GDScript_xqplk") - -[node name="Panel" type="PanelContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="ScrollContainer" type="ScrollContainer" parent="Panel"] -layout_mode = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="Panel/ScrollContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Panel" type="PanelContainer" parent="Panel/ScrollContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VBoxContainer" type="VBoxContainer" parent="Panel/ScrollContainer/VBoxContainer/Panel"] -layout_mode = 2 - -[node name="MarginContainer" type="MarginContainer" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -custom_minimum_size = Vector2(0, 12) -layout_mode = 2 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 - -[node name="Label" type="Label" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -layout_mode = 2 -text = "MPath Help" -label_settings = SubResource("LabelSettings_cjcwk") -horizontal_alignment = 1 - -[node name="Label2" type="Label" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -layout_mode = 2 -horizontal_alignment = 1 - -[node name="Label3" type="Label" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -layout_mode = 2 -text = "Click : Select Point" -horizontal_alignment = 1 - -[node name="Label4" type="Label" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -layout_mode = 2 -text = " Shift + Click : Select multiple points" -horizontal_alignment = 1 - -[node name="Label5" type="Label" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -layout_mode = 2 -text = "Ctrl + Click : Add Point " -horizontal_alignment = 1 - -[node name="Label6" type="Label" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -layout_mode = 2 -text = " Alt + Click : Remove Point " -horizontal_alignment = 1 - -[node name="Label7" type="Label" parent="Panel/ScrollContainer/VBoxContainer/Panel/VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -text = " -For more keyboard shortcuts, please see: -settings / more settings" -horizontal_alignment = 1 - -[node name="Button" type="Button" parent="Panel/ScrollContainer/VBoxContainer"] -layout_mode = 2 -text = "OK" - -[connection signal="pressed" from="Panel/ScrollContainer/VBoxContainer/Button" to="." method="_on_button_pressed"] diff --git a/addons/m_terrain/gui/mtools.gd b/addons/m_terrain/gui/mtools.gd deleted file mode 100644 index 3f9d980..0000000 --- a/addons/m_terrain/gui/mtools.gd +++ /dev/null @@ -1,760 +0,0 @@ -@tool -extends Control - -############################################################## -# MTools -# 1. m_terrain.gd sets mask, decal, and human on enter_tree() -# 2. User selects a node -# This calls edit_mode_button.init_edit_mode_options() -# This populates the list of possible edit modes. -# 3. User selectes edit mode by clicking on edit_mode_button, -# This calls mtools.set_edit_mode() -# This sets the active_object and current_mode -# 4. This sets appropriate "layers" (heightmap or paint) -# This sets appropriate "brushes" (height, color, grass, nav) -# If mpath, show mpath menu -# If mcurve_mesh, show mcurve_mesh menu -# 5. m_terrain.gd _forward_gui_input() calls the draw() when needed -# -# NOTE: "popup" panels are just panels. -# They appear on button click and we use mouse_exit to hide them. -# We use timer to add a delay to prevent accidents -# -# The popup buttons are also the main scripts for that function -# e.g. layers_popup_button has all the code to do with layers -# e.g. brush_popup_button has all the code to do with brushes -# -############################################################### - -# fix icon-only button margins -# fix brush bool-property button -# added ctrl mouse wheel to increase brush size -# fixed xyz lock not working from buttons... -# right click cancel drag for mpath -# grass auto make active when entering paint mode -# has_sublayer merge sublayer - -# terrain walk mode - -#region Signals -signal request_save -signal request_info_window -signal request_import_window -signal request_image_creator -signal edit_mode_changed -#endregion - -#region UI Controls -@onready var status_bar: Control = find_child("status_bar") -#@onready var save_button: Control = find_child("save_button") #TO DELETE -@onready var paint_panel: Control = find_child("paint_panel") - -@onready var options_popup_button: Button = find_child("options_button") - -@onready var edit_mode_button: Button = find_child("edit_mode_button") -@onready var layers_popup_button: Button = find_child("layers_button") -@onready var brush_popup_button: Button = find_child("brush_button") -@onready var mask_popup_button: Button = find_child("mask_button") - -var active_snap_object:Node3D = null - -var collision_ray_step=0.2 -var ray_col:MCollision -var col_dis:float - -var undo_redo: EditorUndoRedoManager -@onready var mpath_gizmo_gui = find_child("mpath_gizmo_gui") -@onready var mcurve_mesh_gui = find_child("mcurve_mesh") -@onready var brush_size_control: Control = find_child("brush_size") - -@onready var mtools_root = find_child("mtools_root") - -@onready var popup_buttons = [ - edit_mode_button, - options_popup_button, - layers_popup_button, - brush_popup_button, - mask_popup_button, -] - -var current_popup_button: Button = null -var timer -#endregion - -var current_edit_mode = &"" # &"", &"sculpt", &"paint" -var active_object = null - - - -var brush_manager:MBrushManager = MBrushManager.new() -var brush_decal # set by m_terrain.gd on enter_tree() -var mask_decal # set by m_terrain.gd on enter_tree() -var human_male # set by m_terrain.gd on enter_tree() -var edit_human_position = false -@onready var human_button = find_child("human_male") -@onready var grass_merge_sublayer_button = find_child("grass_merge_sublayer") -@onready var walk_terrain_button = find_child("walk_terrain") -var walking_terrain = false -var editor_camera: Camera3D = null #this is set by forward_gui_input -var walk_speed = 5 #in meters per seccond - -#region Initialisations -func _ready(): - timer = Timer.new() - timer.timeout.connect(func(): current_popup_button.button_pressed = false) - add_child(timer) - update_theme() - for button in popup_buttons: - init_popup_button_signals(button) - - edit_mode_button.edit_mode_changed.connect(set_edit_mode) - - theme_changed.connect(update_theme) - visibility_changed.connect(_on_resized) - - MTool.enable_editor_plugin() - -func set_brush_decal(new_brush_decal): - brush_decal = new_brush_decal - brush_decal.visible = false - brush_size_control.value_changed.connect(brush_decal.set_brush_size) - -func set_mask_decal(new_mask): - mask_decal = new_mask - mask_decal.visible = false - mask_popup_button.init_masks(mask_decal, find_child("mask_size"), find_child("mask_rotation"),find_child("mask_cutoff"), find_child("invert_mask_button")) - -func on_node_modified(node): - if node is MTerrain or node is MGrass or node is MNavigationRegion3D or node is MPath or node is MCurveMesh: - update_edit_mode_options() - -func update_edit_mode_options(): - var all_mterrain = get_all_mterrain() - edit_mode_button.init_edit_mode_options(all_mterrain) - -func clear_current_popup_button(): - if current_popup_button: - current_popup_button.button_pressed = false - -func init_popup_button_signals(popup_button:Button): - popup_button.button_pressed = false - popup_button.toggled.connect( - func(toggled_on): - if toggled_on: - clear_current_popup_button() - popup_button.get_child(0).visible = true - current_popup_button = popup_button - if not popup_button.mouse_entered.is_connected(_on_mouse_entered_popup): - popup_button.mouse_entered.connect(_on_mouse_entered_popup) - else: - popup_button.get_child(0).visible = false - current_popup_button = null - if not popup_button.mouse_exited.is_connected(_on_mouse_exited_popup): - popup_button.mouse_exited.connect(_on_mouse_exited_popup) - ) - -func _on_mouse_exited_popup() -> void: - if current_popup_button: - timer.one_shot = true - timer.start(0.35) - -func _on_mouse_entered_popup() -> void: - if is_instance_valid(timer): - timer.stop() - -#endregion - -#region getters -func get_active_mterrain(): - var object = active_object - if not object: - var selection = EditorInterface.get_selection().get_selected_nodes() - if selection.size() == 1: - object = selection[0] - if object is MTerrain: - return object - if object is MGrass or object is MNavigationRegion3D or object: - if object.get_parent() is MTerrain: - return object.get_parent() - #This is only used for snapping to MTerrain in MPath: - if object is MPath or object is MCurveMesh: - var all_mterrain = get_all_mterrain() - if all_mterrain.size()>0: - return all_mterrain[0] - -func get_all_mterrain(parent=EditorInterface.get_edited_scene_root()): - var result = [] - if parent == null: - push_warning("trying to get all mterrain, but root is null") - return [] - for child in parent.get_children(): - if child is MTerrain: - result.push_back(child) - for grandchild in child.get_children(): - result.append_array(get_all_mterrain(child)) - return result - -func get_all_mgrass(root): - var result = [] - for terrain in get_all_mterrain(root): - for child in terrain.get_children(): - if child is MGrass: - result.push_back(child) - return result - -func get_all_mnavigation(root): - var result = [] - for terrain in get_all_mterrain(root): - for child in terrain.get_children(): - if child is MNavigationRegion3D: - result.push_back(child) - return result - -func get_all_mpath(root): - var result = [] - for terrain in get_all_mterrain(root): - for child in terrain.get_children(): - if child is MPath: - result.push_back(child) - return result - -#endregion - -func set_active_object(object): - if active_object == object: return - - #Cleanup active object stuff before setting new active object - if active_object is MNavigationRegion3D: - active_object.set_npoints_visible(false) - - edit_mode_button.change_active_object(object) - #Automatically enter edit mode for mpath - if object is MPath: - edit_mode_button.edit_selected(object) - -#region EditorPlugin functions -func process_input(event): - if current_edit_mode in [&"sculpt", &"paint"]: - if event is InputEventMouseButton and Input.is_key_pressed(KEY_CTRL): - if event.button_index == MOUSE_BUTTON_WHEEL_UP: - brush_decal.set_brush_size(brush_decal.get_brush_size() *1.05) - brush_size_control.update_value(brush_decal.get_brush_size()) - return true - elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: - brush_decal.set_brush_size(brush_decal.get_brush_size() /1.05) - brush_size_control.update_value(brush_decal.get_brush_size()) - return true - if event is InputEventKey: - brush_popup_button.process_input(event) - var paint_brush_resize_speed:float=1.0 - var paint_mask_resize_speed:float=1.0 - const max_paint_brush_resize_speed:float=8.0 - const max_mask_brush_resize_speed:float=16.0 - - if Input.is_action_just_released("mterrain_mask_size_increase") or Input.is_action_just_released("mterrain_mask_size_decrease"): - paint_mask_resize_speed=1 - if Input.is_action_just_released("mterrain_brush_size_increase") or Input.is_action_just_released("mterrain_brush_size_decrease"): - paint_brush_resize_speed=1 - - #if event.keycode == KEY_BRACKETLEFT or event.keycode == KEY_BRACKETRIGHT: - if Input.is_action_pressed("mterrain_brush_size_increase"): - paint_brush_resize_speed = min(paint_brush_resize_speed+0.1,max_paint_brush_resize_speed) - brush_decal.set_brush_size(brush_decal.get_brush_size() + floor(paint_brush_resize_speed)) - brush_size_control.update_value(brush_decal.get_brush_size()) - return true - #elif event.keycode == KEY_MINUS: - elif Input.is_action_pressed("mterrain_brush_size_decrease"): - paint_brush_resize_speed = min(paint_brush_resize_speed+0.1,max_paint_brush_resize_speed) - brush_decal.set_brush_size(brush_decal.get_brush_size() - floor(paint_brush_resize_speed)) - brush_size_control.update_value(brush_decal.get_brush_size()) - return true - #elif event.keycode == KEY_PERIOD: - elif Input.is_action_pressed("mterrain_mask_size_increase"): - paint_mask_resize_speed = min(paint_mask_resize_speed+0.2,max_mask_brush_resize_speed) - mask_decal.increase_size(paint_mask_resize_speed) - #elif event.keycode == KEY_COMMA: - elif Input.is_action_just_pressed("mterrain_mask_size_decrease"): - if event.is_pressed(): - paint_mask_resize_speed = min(paint_mask_resize_speed+0.2,max_mask_brush_resize_speed) - mask_decal.increase_size(-paint_mask_resize_speed) - #elif event.keycode == KEY_L and event.pressed: - elif Input.is_action_just_pressed("mterrain_mask_rotate_clockwise"): - mask_decal.rotate_image(1) - #elif event.keycode == KEY_K and event.pressed: - elif Input.is_action_just_pressed("mterrain_mask_rotate_counter_clockwise"): - mask_decal.rotate_image(-1) - #elif event.keycode == KEY_SEMICOLON and event.pressed: - elif Input.is_action_just_pressed("mterrain_mask_rotation_reset"): - mask_decal.reset_image_rotation() - if active_object is MGrass: - status_bar.set_grass_label(active_object.get_count()) - else: - status_bar.disable_grass_label() - -#func update_brushes_based_on_heightmap_layer(new_layer): - #if new_layer == "holes": - #brush_list_option.select(hole_brush_id) - #elif brush_id == hole_brush_id: - #brush_list_option.select(raise_brush_id) - -func process_input_terrain_walk(cam:Camera3D, event:InputEvent): - if event is InputEventMouseButton: - if event.button_index in [MOUSE_BUTTON_MASK_RIGHT, MOUSE_BUTTON_MASK_LEFT]: - walk_terrain_button.button_pressed = false - return true - if event.button_index == MOUSE_BUTTON_WHEEL_UP: - walk_speed *= 1.03 - return true - if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: - walk_speed /= 1.03 - return true - if event is InputEventKey and event.keycode == KEY_ESCAPE: - walk_terrain_button.button_pressed = false - return true - if event is InputEventMouseMotion: - cam.rotation.y += -event.relative.x/100 - cam.rotation.x = clamp(cam.rotation.x -event.relative.y/100, -PI*0.3, PI*0.35) - return true - -func _process(delta): - if walking_terrain and editor_camera: - var multiplier = 1 - if Input.is_key_pressed(KEY_SHIFT): - multiplier = 2 - editor_camera.position += editor_camera.basis.z * Input.get_axis("mterrain_walk_forward", "mterrain_walk_backward") * walk_speed * delta * multiplier - editor_camera.position += editor_camera.basis.x * Input.get_axis("mterrain_walk_left", "mterrain_walk_right") * walk_speed * delta * multiplier - editor_camera.position.y = get_active_mterrain().get_height(editor_camera.global_position) + 1.6 - -func on_selection_changed(obj): - if obj is MTerrain: - request_show() - return - if obj.get_parent() is MTerrain: - if obj is MGrass or obj is MNavigationRegion3D: - request_show() - return - if obj is MPath or obj is MCurveMesh: - request_show() - return - - if mcurve_mesh_gui.obj and mcurve_mesh_gui.is_active(): - request_show() - return - request_hide() - -func on_handles(object): - active_snap_object = null - if mcurve_mesh_gui and mcurve_mesh_gui.obj and mcurve_mesh_gui.is_active(): - return false - if mpath_gizmo_gui and not object is MPath: - mpath_gizmo_gui.visible = false - if not object is MCurveMesh: - mcurve_mesh_gui.set_curve_mesh(null) - - if object is MPath or (object is MCurveMesh and object.get_parent() is MPath) or object is MTerrain or (object is MGrass and object.get_parent() is MTerrain) or (object is MNavigationRegion3D and object.get_parent() is MTerrain): - set_active_object(object) - request_show() - return true - #for some reason these get selected when switching from grass paint mode to terrain sculpt/paint mode: - if object is MTerrainMaterial or object is MBrushLayers: - return false - request_hide() - if object is Node3D: - for mterrain:MTerrain in get_all_mterrain(EditorInterface.get_edited_scene_root()): - if mterrain.is_grid_created(): - active_snap_object = object - return false - -func forward_3d_gui_input(viewport_camera, event): - var active_terrain = get_active_mterrain() - if not active_terrain is MTerrain: - ray_col = null - elif event is InputEventMouse: - var ray:Vector3 = viewport_camera.project_ray_normal(event.position) - var pos:Vector3 = viewport_camera.global_position - ray_col = active_terrain.get_ray_collision_point(pos,ray,collision_ray_step,1000) - - if walking_terrain: - editor_camera = viewport_camera - if process_input_terrain_walk(viewport_camera, event): - return true - - - for terrain in get_all_mterrain(): - terrain.set_editor_camera(viewport_camera) - ######################## HANDLE CURVE GIZMO ############################## - if mpath_gizmo_gui.visible: - return mpath_gizmo_gui.gizmo._forward_3d_gui_input(viewport_camera, event, ray_col) - ######################## HANDLE CURVE GIZMO FINSH ######################## - var a: MTerrain - if active_terrain is MTerrain and event is InputEventMouse: - - if ray_col.is_collided(): - col_dis = ray_col.get_collision_position().distance_to(viewport_camera.global_position) - status_bar.set_height_label(ray_col.get_collision_position().y) - status_bar.set_distance_label(col_dis) - status_bar.set_region_label(active_terrain.get_region_id_by_world_pos(ray_col.get_collision_position())) - if current_edit_mode in [&"sculpt", &"paint"]: - if paint_mode_handle(event): - return true - if human_male.visible: - if edit_human_position: - human_male.global_position = ray_col.get_collision_position() - if event is InputEventMouseButton: - if event.button_index == MOUSE_BUTTON_LEFT: - edit_human_position = false - if event.button_index == MOUSE_BUTTON_RIGHT and edit_human_position: - _on_human_male_toggled(false) - if event.button_index == MOUSE_BUTTON_MIDDLE: - edit_human_position = true - - else: - col_dis=1000000 - status_bar.disable_height_label() - status_bar.disable_distance_label() - status_bar.disable_region_label() - if col_dis<1000: - collision_ray_step = (col_dis + 50)/100 - else: - collision_ray_step = 3 - #set_save_button_disabled(not active_terrain.has_unsave_image()) - if process_input(event): - return true - ## Fail paint attempt - ## returning the stop so terrain will not be unselected - #if current_edit_mode == &"paint": - # if event is InputEventMouseButton: - # if event.button_mask == MOUSE_BUTTON_LEFT: - # return AFTER_GUI_INPUT_STOP - - - -var last_draw_time:int=0 - -func validate_brush(): - if active_object is MTerrain and current_edit_mode == &"paint": - if not brush_popup_button.visible: return false - return true - -func paint_mode_handle(event:InputEvent): - if ray_col.is_collided() and validate_brush(): - brush_decal.visible = true - brush_decal.set_position(ray_col.get_collision_position()) - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: - if event.pressed: - if active_object is MGrass: - active_object.check_undo() - undo_redo.create_action("GrassPaint") - undo_redo.add_undo_method(active_object,"undo") - undo_redo.commit_action(false) - elif active_object is MNavigationRegion3D: - pass - elif active_object is MTerrain: ## Start of painting - active_object.set_brush_start_point(ray_col.get_collision_position(),brush_decal.radius) - #set_active_layer() - active_object.images_add_undo_stage() - undo_redo.create_action("Sculpting") - undo_redo.add_undo_method(active_object,"images_undo") - undo_redo.commit_action(false) - else: - if mask_decal.is_being_edited: - mask_decal.is_being_edited = false - elif active_object is MGrass: - active_object.save_grass_data() - elif active_object is MNavigationRegion3D: - active_object.save_nav_data() - elif active_object is MTerrain: - active_object.save_all_dirty_images() - if event.button_mask == MOUSE_BUTTON_LEFT: - var t = Time.get_ticks_msec() - var dt = t - last_draw_time - last_draw_time = t - if mask_decal.is_being_edited: - return true - if draw(ray_col.get_collision_position()): - return true - if mask_decal.is_being_edited: - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT: - mask_decal.is_being_edited = false - mask_popup_button.clear_mask() - mask_decal.set_absolute_terrain_pos(ray_col.get_collision_position()) - elif event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_MIDDLE: - mask_decal.is_being_edited = true - return true - else: - brush_decal.visible = false - mask_decal.visible = false - return false - - - - -func on_scene_changed(_root): - set_edit_mode(null) - -func request_hide(): - set_edit_mode(null, null) - visible = false - mpath_gizmo_gui.visible = false - mcurve_mesh_gui.set_curve_mesh(null) - -func request_show(): - visible = true - _on_resized() - update_edit_mode_options() - -func deactivate_editing(): - if is_instance_valid(edit_mode_button): - edit_mode_button.text = "" - edit_mode_button.theme_type_variation = "button_icon_only" - _on_human_male_toggled(false) - edit_mode_button.exit_edit_mode_button.visible = false - brush_decal.visible = false - mask_decal.visible = false - mask_popup_button.clear_mask() - for mterrain in get_all_mterrain(): - mterrain.disable_brush_mask() - paint_panel.visible = false - mpath_gizmo_gui.visible = false - mcurve_mesh_gui.visible = false - brush_popup_button.clear_brushes() - active_object = null - current_edit_mode = &"" - -func set_edit_mode(object = active_object, mode=current_edit_mode): - if object == active_object and current_edit_mode == mode: - return - - if object==null or mode ==&"": - deactivate_editing() - return - if not is_instance_valid(object): - push_error("Instance is not valid") - return - active_object = object - current_edit_mode = mode - brush_popup_button.visible = true - mask_popup_button.visible = true - if object is MPath: - #deactivate_editing() - mpath_gizmo_gui.visible = true - var active_mterrain = get_active_mterrain() - if active_mterrain and active_mterrain.is_grid_created(): - mpath_gizmo_gui.set_terrain_snap(active_mterrain) - else: - mpath_gizmo_gui.set_terrain_snap(null) - object.update_gizmos() - elif object is MCurveMesh: - mcurve_mesh_gui.set_curve_mesh(object) - mcurve_mesh_gui.visible = true - edit_mode_changed.emit(object, mode) - var active_mterrain = get_active_mterrain() - if not active_mterrain: return - active_mterrain.set_brush_manager(brush_manager) - mask_popup_button.mterrain = active_mterrain - mask_popup_button.toggle_grass_settings(false) - if object is MTerrain: - paint_panel.visible = true - layers_popup_button.visible = true - grass_merge_sublayer_button.visible = false - #to do: clean up previous edit mode: grass, nav, and path stuff?, then: - for connection in layers_popup_button.get_signal_connection_list("layer_changed"): - connection.signal.disconnect(connection.callable) - if mode == &"sculpt": - layers_popup_button.init_height_layers(object) - brush_popup_button.init_height_brushes(brush_manager) - elif mode == &"paint": - layers_popup_button.layer_changed.connect(func(id): - brush_popup_button.visible = id > -1 - mask_popup_button.visible = id > -1 - ) - layers_popup_button.init_color_layers(object, brush_popup_button) - #Colol layers will init there own brushes - mask_decal.active_terrain = object - if not get_active_mterrain().is_grid_created(): - get_active_mterrain().create_grid() - elif object is MGrass: - paint_panel.visible = true - #clean up previous edit mode: grass, nav, and path stuff, then: - layers_popup_button.visible = false - #init_height_layers(object.get_parent()) - brush_popup_button.init_grass_brushes() - mask_popup_button.toggle_grass_settings(true) - mask_decal.active_terrain = active_mterrain - if not object.active or not object.is_init(): - object.active = true - object.visible = true - get_active_mterrain().remove_grid() - if not get_active_mterrain().is_grid_created(): - get_active_mterrain().create_grid() - grass_merge_sublayer_button.visible = object.has_sublayer() - elif object is MNavigationRegion3D: - grass_merge_sublayer_button.visible = false - paint_panel.visible = true - layers_popup_button.visible = false - brush_popup_button.init_mnavigation_brushes() - object.set_npoints_visible(true) - mask_decal.active_terrain = active_mterrain - if not object.active: - object.active = true - object.visible = true - get_active_mterrain().remove_grid() - if not get_active_mterrain().is_grid_created(): - get_active_mterrain().create_grid() - - - -func draw(brush_position): - if active_object is MGrass: - active_object.draw_grass(brush_position,brush_decal.radius,brush_popup_button.is_grass_add) - return true - elif active_object is MNavigationRegion3D: - active_object.draw_npoints(brush_position,brush_decal.radius, brush_popup_button.is_grass_add) - return true - elif active_object is MTerrain: - if current_edit_mode == &"sculpt": - active_object.draw_height(brush_position,brush_decal.radius,brush_popup_button.height_brush_id) - return true - elif current_edit_mode == &"paint": - active_object.draw_color(brush_position,brush_decal.radius,brush_popup_button.color_brush_name,brush_popup_button.color_brush_uniform) - return true - else: - push_warning("trying to 'draw' on mterrain, but not in sculpt or paint mode") - else: - print("draw mterrain fail: active object is ", active_object.name) - - -func remove_image(active_terrain, dname): - var is_grid_created = active_terrain.is_grid_created() - if is_grid_created: - active_terrain.remove_grid() - var dir = DirAccess.open(active_terrain.dataDir) - if not dir: - printerr("Can not open ",active_terrain.dataDir) - return - dir.list_dir_begin() - var file_name :String= dir.get_next() - var res_names:PackedStringArray = [] - while file_name != "": - if file_name.get_extension() == "res": - res_names.append(file_name) - file_name = dir.get_next() - #remove config file: - var config_path = active_terrain.dataDir.path_join(".save_config.ini") - var config = ConfigFile.new() - if FileAccess.file_exists(config_path): - var err = config.load(config_path) - if err != OK: - printerr("Can not load config with err ",err) - config.erase_section(dname) - config.save(config_path) - - #remove data - for res_name in res_names: - var path = active_terrain.dataDir.path_join(res_name) - var mres = load(path) - if not mres is MResource: - continue - mres.remove_data(dname) - ResourceSaver.save(mres,path) - #remove layers - var id = 0 - var remove_count = 0 - var layers = active_terrain.brush_layers - for i in layers.size(): - if layers[i].uniform_name != dname: - active_terrain.brush_layers[id] = layers[i] - id += 1 - else: - remove_count += 1 - active_terrain.brush_layers_groups_num -= remove_count - - - if is_grid_created: - active_terrain.create_grid() - set_edit_mode(null,null) - #todo: dont' exit edit mode, just change layer selection to 0 or -1 - - - -#region responding to signals -func _on_human_male_toggled(button_pressed): - edit_human_position = true - human_male.visible = button_pressed - if not human_button.button_pressed == button_pressed: - human_button.button_pressed = button_pressed - -func _on_info_btn_pressed(): - request_info_window.emit() - request_info_window - -func _on_reload_pressed() -> void: - get_active_mterrain().create_grid() - -func _on_heightmap_import_button_pressed() -> void: - request_import_window.emit() - -func _on_image_creator_button_pressed(): - request_image_creator.emit() -#endregion - -#region theme: sizes and colors etc -func _on_resized(): - if not has_node("VSplitContainer") or not mtools_root: - call_deferred( "_on_resized" ) - return - var vsplit = $VSplitContainer - var max_size = get_viewport_rect().size.y / 16 + 2 - var min_size = get_viewport_rect().size.y / 32 - vsplit.size.y = max_size - vsplit.position.y = -vsplit.size.y - #print(vsplit.split_offset, " and minsize: ", min_size, " and max: ", max_size) - vsplit.split_offset = clamp(vsplit.split_offset, -max_size,-min_size) - resize_children_recursive(mtools_root, clamp(mtools_root.size.y, min_size, max_size )) - theme.default_font_size = clamp( clamp(mtools_root.size.y, min_size, max_size) /2 , 12,32) - -func resize_children_recursive(parent, new_size): - for child in parent.get_children(): - if child is Control and not child is ItemList and not child is LineEdit and not child is Label: - child.custom_minimum_size.x = new_size - child.custom_minimum_size.y = new_size - resize_children_recursive(child, new_size) - -func update_theme(): - var base_color = EditorInterface.get_editor_settings().get_setting("interface/theme/base_color") - var stylebox = preload("res://addons/m_terrain/gui/styles/popup_panel_stylebox.tres") - if stylebox.bg_color != base_color: - stylebox.set("bg_color", base_color) - -func _on_v_split_container_dragged(offset): - _on_resized() -#endregion - - -func _on_grass_merge_sublayer_pressed(): - if not active_object is MGrass: - push_error("trying to merge grass sublayer, but active object is not MGrass") - return - if not active_object.is_init(): - push_error("trying to merge grass sublayer, but grass is not init()") - return - if not active_object.has_sublayer(): - push_error("trying to merge grass sublayer, but grass doesn't have sublayer") - return - active_object.merge_sublayer() - - - -func _on_walk_terrain_toggled(toggled_on): - if not get_active_mterrain(): - push_error("trying to walk mterrain, but there is no active mterrain") - walk_terrain_button.button_pressed = false - return - walking_terrain = toggled_on - if toggled_on: - Input.mouse_mode = Input.MOUSE_MODE_CAPTURED - else: - Input.mouse_mode = Input.MOUSE_MODE_VISIBLE - - - diff --git a/addons/m_terrain/gui/mtools.tscn b/addons/m_terrain/gui/mtools.tscn deleted file mode 100644 index 800d047..0000000 --- a/addons/m_terrain/gui/mtools.tscn +++ /dev/null @@ -1,704 +0,0 @@ -[gd_scene load_steps=26 format=3 uid="uid://bdxfu7h15wijq"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_avwfe"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools.gd" id="1_l6paa"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_options.gd" id="2_2bis6"] -[ext_resource type="Texture2D" uid="uid://bw2njdr7ynhtk" path="res://addons/m_terrain/icons/settings_icon.svg" id="2_mjshi"] -[ext_resource type="Texture2D" uid="uid://dgjegrn8jhlf6" path="res://addons/m_terrain/icons/human_disabled.svg" id="4_rgpuu"] -[ext_resource type="Texture2D" uid="uid://dj86rx42xt6wc" path="res://addons/m_terrain/icons/save_icon.svg" id="6_di4ov"] -[ext_resource type="Texture2D" uid="uid://btn8tgu2yhlxj" path="res://addons/m_terrain/icons/save_icon_disable.svg" id="7_nh28h"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_status_bar.gd" id="9_666yn"] -[ext_resource type="Texture2D" uid="uid://cjs22nfbjl71l" path="res://addons/m_terrain/icons/rotation.svg" id="9_ck5t3"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_edit_mode_selector.gd" id="10_qe47s"] -[ext_resource type="Texture2D" uid="uid://t8tdan3853oy" path="res://addons/m_terrain/icons/icon_close.svg" id="11_0dtgq"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_brushes.gd" id="11_c6bj1"] -[ext_resource type="Texture2D" uid="uid://b4ylxie43lan2" path="res://addons/m_terrain/icons/more_options_icon.svg" id="11_qk86q"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_layers.gd" id="13_1tujl"] -[ext_resource type="Texture2D" uid="uid://tow1rj13cxaw" path="res://addons/m_terrain/icons/merge_down_icon.svg" id="15_sjvca"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_masks.gd" id="16_h7wnm"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_slider_value.gd" id="18_vmcc8"] -[ext_resource type="Texture2D" uid="uid://rtqaiuii2jml" path="res://addons/m_terrain/icons/no_mask_icon.svg" id="19_epiyr"] -[ext_resource type="Texture2D" uid="uid://b8xvuorm57o1s" path="res://addons/m_terrain/icons/invert_icon_normal.svg" id="20_8anom"] -[ext_resource type="Texture2D" uid="uid://tmhtthjk2rb4" path="res://addons/m_terrain/icons/invert_icon_inverted.svg" id="21_lodvs"] -[ext_resource type="Texture2D" uid="uid://2dpvr41alpt8" path="res://addons/m_terrain/icons/walk_icon.svg" id="22_c7tyl"] -[ext_resource type="PackedScene" uid="uid://btfhp7mnhc5nj" path="res://addons/m_terrain/gizmos/mpath_gizmo_gui.tscn" id="23_i5qr3"] -[ext_resource type="PackedScene" uid="uid://b6wfdaqojnwju" path="res://addons/m_terrain/gui/mtools_mask_list.tscn" id="23_qb0vt"] -[ext_resource type="PackedScene" uid="uid://b76ioum2i7yjy" path="res://addons/m_terrain/gizmos/mcurve_mesh_gui.tscn" id="28_x63ge"] - -[sub_resource type="GDScript" id="GDScript_tlie2"] -script/source = "@tool -extends Button - -func _pressed(): - var popup = preload(\"res://addons/m_terrain/gui/mtools_transform_terrain_popup.tscn\").instantiate() - add_child(popup) - -" - -[node name="mtools" type="Control"] -layout_mode = 3 -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 4.0 -grow_horizontal = 2 -grow_vertical = 0 -theme = ExtResource("1_avwfe") -script = ExtResource("1_l6paa") - -[node name="VSplitContainer" type="VSplitContainer" parent="."] -layout_mode = 1 -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -46.4375 -offset_right = 43624.0 -grow_horizontal = 2 -grow_vertical = 0 -theme_override_constants/separation = 0 -split_offset = -28 - -[node name="Control" type="Control" parent="VSplitContainer"] -layout_mode = 2 -size_flags_vertical = 3 -mouse_filter = 1 - -[node name="mtools_root" type="Panel" parent="VSplitContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 - -[node name="hbox" type="HBoxContainer" parent="VSplitContainer/mtools_root"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -offset_right = 1148.0 -offset_bottom = 11.0 - -[node name="options_button" type="Button" parent="VSplitContainer/mtools_root/hbox"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "More MTerrain settings" -theme_type_variation = &"button_icon_only" -toggle_mode = true -icon = ExtResource("2_mjshi") -expand_icon = true -script = ExtResource("2_2bis6") - -[node name="PanelContainer" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/options_button"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 0 -offset_top = -510.0 -offset_right = 475.0 -offset_bottom = -4.0 -mouse_filter = 1 - -[node name="MarginContainer" type="MarginContainer" parent="VSplitContainer/mtools_root/hbox/options_button/PanelContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="VBoxContainer" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="heightmap_import_button" type="Button" parent="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 -text = "Import/Export -" -alignment = 0 - -[node name="image_creator_button" type="Button" parent="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 -text = "Image Creator" -alignment = 0 - -[node name="transform_terrain_button" type="Button" parent="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 -text = "Transform Terrain" -alignment = 0 -script = SubResource("GDScript_tlie2") - -[node name="hide_status" type="CheckButton" parent="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 -button_pressed = true -text = "Hide Status" - -[node name="info_btn" type="Button" parent="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 -text = "More Settings" -alignment = 0 -icon_alignment = 2 -expand_icon = true - -[node name="VSeparator" type="VSeparator" parent="VSplitContainer/mtools_root/hbox"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="save_button" type="TextureButton" parent="VSplitContainer/mtools_root/hbox"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -toggle_mode = true -texture_normal = ExtResource("6_di4ov") -texture_disabled = ExtResource("7_nh28h") -stretch_mode = 5 - -[node name="reload" type="TextureButton" parent="VSplitContainer/mtools_root/hbox"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -toggle_mode = true -texture_normal = ExtResource("9_ck5t3") -stretch_mode = 5 - -[node name="VSeparator2" type="VSeparator" parent="VSplitContainer/mtools_root/hbox"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="status_bar" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -alignment = 1 -script = ExtResource("9_666yn") - -[node name="h_label" type="Label" parent="VSplitContainer/mtools_root/hbox/status_bar"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "H: 321m" -vertical_alignment = 1 - -[node name="d_label" type="Label" parent="VSplitContainer/mtools_root/hbox/status_bar"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "D: 620m" -vertical_alignment = 1 - -[node name="g_label" type="Label" parent="VSplitContainer/mtools_root/hbox/status_bar"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "G: 271543" -vertical_alignment = 1 - -[node name="r_label" type="Label" parent="VSplitContainer/mtools_root/hbox/status_bar"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "R:2" -vertical_alignment = 1 - -[node name="VSeparator3" type="VSeparator" parent="VSplitContainer/mtools_root/hbox/status_bar"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="PaintControls" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="edit_selected_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Edit currently selected node" -text = "Edit MGrass1" - -[node name="edit_mode_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Select MTerrain edit mode" -theme_type_variation = &"button_icon_only" -toggle_mode = true -icon = ExtResource("11_qk86q") -icon_alignment = 1 -expand_icon = true -script = ExtResource("10_qe47s") - -[node name="Panel2" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/edit_mode_button"] -visible = false -clip_contents = true -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 1 -offset_left = -6.0 -offset_top = -198.0 -offset_right = 298.0 -offset_bottom = -1.0 -mouse_filter = 1 - -[node name="MarginContainer" type="MarginContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/edit_mode_button/Panel2"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="ScrollContainer" type="ScrollContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/edit_mode_button/Panel2/MarginContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_vertical = 3 -horizontal_scroll_mode = 0 - -[node name="edit_mode_item_container" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/edit_mode_button/Panel2/MarginContainer/ScrollContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/edit_mode_button/Panel2/MarginContainer/ScrollContainer/edit_mode_item_container"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -text = "TEST" - -[node name="edit_mode_exit_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Exit edit mode for MTerrain related nodes" -theme_type_variation = &"button_icon_only" -icon = ExtResource("11_0dtgq") -expand_icon = true - -[node name="paint_panel" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="layers_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Current Layer. Click to show layer menu" -toggle_mode = true -text = "LayerName" -script = ExtResource("13_1tujl") - -[node name="Panel2" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button"] -visible = false -clip_contents = true -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 1 -offset_top = -296.0 -offset_right = 401.0 -offset_bottom = -2.0 -mouse_filter = 1 - -[node name="MarginContainer" type="MarginContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="VBoxContainer" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2/MarginContainer"] -clip_contents = true -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="layer_controls" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2/MarginContainer/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="add_height_layer_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2/MarginContainer/VBoxContainer/layer_controls"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Add new heightmap layer" -mouse_filter = 1 -text = "+ Add Layer" -alignment = 0 -expand_icon = true - -[node name="add_color_layer_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2/MarginContainer/VBoxContainer/layer_controls"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Add new heightmap layer" -mouse_filter = 1 -text = "+ Add Layer" -alignment = 0 -expand_icon = true - -[node name="merge_height_layers_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2/MarginContainer/VBoxContainer/layer_controls"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Merge all heightmap layers with background (flatten)" -mouse_filter = 1 -text = "Merge All" -icon = ExtResource("15_sjvca") -alignment = 0 -icon_alignment = 2 -expand_icon = true - -[node name="ScrollContainer" type="ScrollContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2/MarginContainer/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_vertical = 3 -horizontal_scroll_mode = 3 -vertical_scroll_mode = 3 - -[node name="layer_item_container" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/layers_button/Panel2/MarginContainer/VBoxContainer/ScrollContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="grass_merge_sublayer" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Merge grass sublayer" -mouse_filter = 1 -theme_type_variation = &"button_icon_only" -icon = ExtResource("15_sjvca") -alignment = 0 -icon_alignment = 2 -expand_icon = true - -[node name="brush_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Current Brush. Click to show brush menu" -theme_type_variation = &"button_icon_only" -toggle_mode = true -text = "Brush" -expand_icon = true -script = ExtResource("11_c6bj1") - -[node name="Panel" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 1 -offset_left = -252.0 -offset_top = -202.2 -offset_right = 984.0 -mouse_filter = 1 - -[node name="HBoxContainer" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="brush_settings_panel" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer"] -clip_contents = true -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 - -[node name="ScrollContainer" type="ScrollContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_settings_panel"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="brush_settings" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_settings_panel/ScrollContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -size_flags_stretch_ratio = 0.5 -alignment = 2 - -[node name="brush_size_panel" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer"] -clip_contents = true -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 -metadata/_edit_group_ = true - -[node name="MarginContainer" type="MarginContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_size_panel"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -theme_override_constants/margin_top = 12 - -[node name="brush_size" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_size_panel/MarginContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -alignment = 2 -script = ExtResource("18_vmcc8") - -[node name="VSlider" type="VSlider" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_size_panel/MarginContainer/brush_size"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 1 -size_flags_vertical = 3 -mouse_filter = 1 -max_value = 500.0 -step = 0.1 -value = 50.0 - -[node name="LineEdit" type="LineEdit" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_size_panel/MarginContainer/brush_size"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -text = "21.5" -alignment = 1 -middle_mouse_paste_enabled = false - -[node name="Label" type="Label" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_size_panel/MarginContainer/brush_size"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "size" -horizontal_alignment = 1 - -[node name="brush_brushes_panel" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 - -[node name="VBoxContainer" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_brushes_panel"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="add_color_brush_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_brushes_panel/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 0 -mouse_filter = 1 -text = "Add Brush" - -[node name="zbrush_container" type="ItemList" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_brushes_panel/VBoxContainer"] -visible = false -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -mouse_filter = 1 -allow_reselect = true -auto_height = true -fixed_icon_size = Vector2i(64, 64) - -[node name="scroll_container" type="ScrollContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_brushes_panel/VBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="brush_container" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel/HBoxContainer/brush_brushes_panel/VBoxContainer/scroll_container"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="mask_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Current mask. Click to show mask menu" -theme_type_variation = &"button_icon_only" -toggle_mode = true -icon = ExtResource("19_epiyr") -expand_icon = true -script = ExtResource("16_h7wnm") - -[node name="Panel2" type="PanelContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 1 -offset_left = -192.0 -offset_top = -265.8 -offset_right = 1044.0 -mouse_filter = 1 - -[node name="HBoxContainer" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="mask_list" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer" instance=ExtResource("23_qb0vt")] -custom_minimum_size = Vector2(192, 2.125) -layout_mode = 2 -size_flags_vertical = 3 -mouse_filter = 1 -max_columns = 48 -fixed_icon_size = Vector2i(4, 4) -metadata/_edit_group_ = true - -[node name="MarginContainer" type="MarginContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -theme_override_constants/margin_top = 12 - -[node name="mask_size" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -script = ExtResource("18_vmcc8") - -[node name="VSlider" type="VSlider" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer/mask_size"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 1 -size_flags_vertical = 3 -mouse_filter = 1 -max_value = 500.0 -step = 0.1 -value = 50.0 - -[node name="LineEdit" type="LineEdit" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer/mask_size"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -text = "21.5" -middle_mouse_paste_enabled = false - -[node name="Label" type="Label" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer/mask_size"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "size" -horizontal_alignment = 1 - -[node name="MarginContainer2" type="MarginContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -theme_override_constants/margin_top = 12 - -[node name="mask_settings" type="HBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -alignment = 2 - -[node name="invert_mask" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="invert_mask_button" type="TextureButton" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/invert_mask"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_vertical = 3 -mouse_filter = 1 -toggle_mode = true -texture_normal = ExtResource("20_8anom") -texture_pressed = ExtResource("21_lodvs") -ignore_texture_size = true -stretch_mode = 3 - -[node name="Label" type="Label" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/invert_mask"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "invert" -horizontal_alignment = 1 - -[node name="mask_cutoff" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -script = ExtResource("18_vmcc8") - -[node name="VSlider" type="VSlider" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/mask_cutoff"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 1 -size_flags_vertical = 3 -mouse_filter = 1 -max_value = 1.0 -step = 0.05 -value = 0.5 - -[node name="LineEdit" type="LineEdit" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/mask_cutoff"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -text = "0.5" -middle_mouse_paste_enabled = false - -[node name="Label" type="Label" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/mask_cutoff"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = "cutoff" -horizontal_alignment = 1 - -[node name="mask_rotation" type="VBoxContainer" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -script = ExtResource("18_vmcc8") - -[node name="VSlider" type="VSlider" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/mask_rotation"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -size_flags_horizontal = 1 -size_flags_vertical = 3 -mouse_filter = 1 -max_value = 4.0 -rounded = true - -[node name="LineEdit" type="LineEdit" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/mask_rotation"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -text = "0" -middle_mouse_paste_enabled = false - -[node name="Label" type="Label" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2/HBoxContainer/MarginContainer2/mask_settings/mask_rotation"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -text = " 90º " -horizontal_alignment = 1 - -[node name="mask_clear_button" type="Button" parent="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel"] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -icon = ExtResource("11_0dtgq") -expand_icon = true - -[node name="human_male" type="Button" parent="VSplitContainer/mtools_root/hbox"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -mouse_filter = 1 -theme_type_variation = &"button_icon_only" -toggle_mode = true -icon = ExtResource("4_rgpuu") -alignment = 0 -icon_alignment = 2 -expand_icon = true - -[node name="walk_terrain" type="Button" parent="VSplitContainer/mtools_root/hbox"] -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 -tooltip_text = "Walk on terrain" -mouse_filter = 1 -theme_type_variation = &"button_icon_only" -toggle_mode = true -icon = ExtResource("22_c7tyl") -alignment = 0 -icon_alignment = 2 -expand_icon = true - -[node name="mpath_gizmo_gui" parent="VSplitContainer/mtools_root/hbox" instance=ExtResource("23_i5qr3")] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[node name="mcurve_mesh" parent="VSplitContainer/mtools_root/hbox" instance=ExtResource("28_x63ge")] -visible = false -custom_minimum_size = Vector2(32.4375, 32.4375) -layout_mode = 2 - -[connection signal="dragged" from="VSplitContainer" to="." method="_on_v_split_container_dragged"] -[connection signal="ready" from="VSplitContainer/mtools_root" to="." method="_on_resized"] -[connection signal="resized" from="VSplitContainer/mtools_root/hbox/options_button/PanelContainer" to="VSplitContainer/mtools_root/hbox/options_button" method="_on_panel_container_resized"] -[connection signal="pressed" from="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer/heightmap_import_button" to="." method="_on_heightmap_import_button_pressed"] -[connection signal="pressed" from="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer/image_creator_button" to="." method="_on_image_creator_button_pressed"] -[connection signal="toggled" from="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer/hide_status" to="VSplitContainer/mtools_root/hbox/status_bar" method="toggle_visible"] -[connection signal="pressed" from="VSplitContainer/mtools_root/hbox/options_button/PanelContainer/MarginContainer/VBoxContainer/info_btn" to="." method="_on_info_btn_pressed"] -[connection signal="pressed" from="VSplitContainer/mtools_root/hbox/save_button" to="." method="_on_save_pressed"] -[connection signal="pressed" from="VSplitContainer/mtools_root/hbox/reload" to="." method="_on_reload_pressed"] -[connection signal="pressed" from="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/grass_merge_sublayer" to="." method="_on_grass_merge_sublayer_pressed"] -[connection signal="minimum_size_changed" from="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button/Panel" to="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/brush_button" method="_on_resized"] -[connection signal="minimum_size_changed" from="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button/Panel2" to="VSplitContainer/mtools_root/hbox/PaintControls/paint_panel/mask_button" method="_on_h_box_container_resized"] -[connection signal="toggled" from="VSplitContainer/mtools_root/hbox/human_male" to="." method="_on_human_male_toggled"] -[connection signal="toggled" from="VSplitContainer/mtools_root/hbox/walk_terrain" to="." method="_on_walk_terrain_toggled"] diff --git a/addons/m_terrain/gui/mtools_brush_item.gd b/addons/m_terrain/gui/mtools_brush_item.gd deleted file mode 100644 index 0c7841f..0000000 --- a/addons/m_terrain/gui/mtools_brush_item.gd +++ /dev/null @@ -1,107 +0,0 @@ -@tool -extends PanelContainer - -signal brush_selected -signal brush_edited -signal brush_removed - -@onready var label = find_child("label") -@onready var edit= find_child("edit") -@onready var remove = find_child("remove") -var color -var brush_type = 0 -var brush_data = {} -var brush_layer - -func _ready(): - label.pressed.connect(func(): brush_selected.emit()) - visibility_changed.connect(on_resize) - resized.connect(on_resize) - -func set_height_brush(bname, bicon): - edit.free() - remove.free() - label.text = bname - label.icon = bicon - -func set_color_brush(layer_group, i): - brush_layer = layer_group - var brush = layer_group.layers[i] - label.text = brush.NAME - label.icon = load(brush.ICON) if FileAccess.file_exists(brush.ICON) else null - if layer_group.brush_name == "Color Paint": - brush_data = {"color": brush.color, "hardness":brush.hardness } - brush_type = 0 - elif layer_group.brush_name == "Channel Painter": - brush_data = { - "hardness":brush.hardness, - "r_on": brush.red, - "r_value":brush['red-value'], - "g_on": brush.green, - "g_value":brush['green-value'], - "b_on": brush.blue, - "b_value":brush['blue-value'], - "a_on": brush.alpha, - "a_value":brush['alpha-value'], - } - brush_type = 1 - elif layer_group.brush_name == "Bitwise Brush": - brush_data = {"bit": brush.bit, "value":brush.value } - brush_type = 2 - elif layer_group.brush_name == "Paint 16": - brush_data = {"paint16layer": brush['paint-layer'] } - brush_type = 3 - elif layer_group.brush_name == "Paint 256": - brush_data = {"paint256layer": brush['paint-layer'] } - brush_type = 4 - - if brush_type == 0: - color = brush.color - var stylebox = preload("res://addons/m_terrain/gui/styles/button_stylebox.tres").duplicate() - stylebox.bg_color = color - label.set("theme_override_styles/normal", stylebox) - label.set("theme_override_styles/focus", stylebox) - label.set("theme_override_styles/hover", stylebox) - label.set("theme_override_styles/pressed", stylebox) - else: - label.set("theme_override_styles/normal", null) - label.set("theme_override_styles/focus", null) - label.set("theme_override_styles/hover", null) - label.set("theme_override_styles/pressed", null) - edit.pressed.connect(edit_brush) - edit.tooltip_text = str("edit ", brush.NAME) - if layer_group.layers[i].NAME == "background": - remove.disabled = true - remove.tooltip_text = "cannot remove background brush" - else: - remove.pressed.connect(remove_brush) - -func set_text_brush(text): - label.text = text - label.icon = null - edit.queue_free() - remove.queue_free() - -func edit_brush(): - var popup = preload("res://addons/m_terrain/gui/mtools_create_color_brush.tscn").instantiate() - add_child(popup) - var bicon = label.icon.resource_path if label.icon else "" - popup.load_brush(brush_layer, label.text, bicon, brush_data) - popup.brush_created.connect( - func(new_name, new_icon_path, data): - brush_edited.emit(new_name, new_icon_path, data, get_index()) - ) - -func remove_brush(): - var popup = preload("res://addons/m_terrain/gui/mtools_layer_warning_popup.tscn").instantiate() - add_child(popup) - popup.confirmed.connect(func(): - brush_removed.emit(get_index()) - queue_free() - get_parent().remove_child(self) - - - ) - -func on_resize(): - label.set("theme_override_constants/icon_max_width", theme.default_font_size*2) diff --git a/addons/m_terrain/gui/mtools_brush_item.tscn b/addons/m_terrain/gui/mtools_brush_item.tscn deleted file mode 100644 index a28dabe..0000000 --- a/addons/m_terrain/gui/mtools_brush_item.tscn +++ /dev/null @@ -1,42 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://d3k4sbpnxyybs"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_ch6cx"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_brush_item.gd" id="2_1pgox"] -[ext_resource type="Texture2D" uid="uid://lwsbiudya0cf" path="res://addons/m_terrain/icons/brush_icon_to_height.svg" id="3_c0sww"] -[ext_resource type="Texture2D" uid="uid://s6jqtql0r2bw" path="res://addons/m_terrain/icons/edit_icon.svg" id="3_uev0k"] -[ext_resource type="Texture2D" uid="uid://t8tdan3853oy" path="res://addons/m_terrain/icons/icon_close.svg" id="4_7obfx"] - -[node name="BrushItem" type="PanelContainer"] -offset_right = 175.0 -offset_bottom = 64.0 -mouse_filter = 1 -theme = ExtResource("1_ch6cx") -script = ExtResource("2_1pgox") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -custom_minimum_size = Vector2(64, 64) -layout_mode = 2 - -[node name="label" type="Button" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -mouse_filter = 1 -text = "Brush name" -icon = ExtResource("3_c0sww") -alignment = 0 - -[node name="edit" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -mouse_filter = 1 -theme_type_variation = &"button_icon_only" -icon = ExtResource("3_uev0k") -expand_icon = true - -[node name="remove" type="Button" parent="HBoxContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -mouse_filter = 1 -theme_type_variation = &"button_icon_only" -icon = ExtResource("4_7obfx") -expand_icon = true diff --git a/addons/m_terrain/gui/mtools_brush_size.gd b/addons/m_terrain/gui/mtools_brush_size.gd deleted file mode 100644 index d90b091..0000000 --- a/addons/m_terrain/gui/mtools_brush_size.gd +++ /dev/null @@ -1,26 +0,0 @@ -@tool -extends Button - -signal brush_size_changed - -@export var slider: VSlider -@export var textbox: LineEdit - -func _ready(): - slider.value_changed.connect(update_value) - textbox.text_submitted.connect(update_value) - - var panel = get_child(0) - panel.visible = false - panel.position.y = -panel.size.y - -func update_value(new_value): - var changed = false - if slider.value != float(new_value): - slider.value = float(new_value) - changed = true - if textbox.text != str(new_value): - textbox.text = str(new_value) - changed = true - if changed: - brush_size_changed.emit(float(new_value)) diff --git a/addons/m_terrain/gui/mtools_brushes.gd b/addons/m_terrain/gui/mtools_brushes.gd deleted file mode 100644 index 323f69a..0000000 --- a/addons/m_terrain/gui/mtools_brushes.gd +++ /dev/null @@ -1,398 +0,0 @@ -#BRUSH button -@tool -extends Button - -@onready var brush_container = find_child("brush_container") -@onready var brush_settings_container = find_child("brush_settings") - -var height_brush_id = 0 - -var last_height_brush_id -var is_grass_add = true -var brush_mode = &"" # &"sculpt", &"paint", &"grass", &"navigation" -var active_terrain #used for setting active color brush - -var float_prop_element=preload("res://addons/m_terrain/gui/control_prop_element/float.tscn") -var float_range_prop_element=preload("res://addons/m_terrain/gui/control_prop_element/float_range.tscn") -var bool_element = preload("res://addons/m_terrain/gui/control_prop_element/bool.tscn") -var int_element = preload("res://addons/m_terrain/gui/control_prop_element/int.tscn") -var int_enum_element = preload("res://addons/m_terrain/gui/control_prop_element/int_enum.tscn") - - -var height_brush_manager - -var smooth_brush_id -var raise_brush_id -var to_height_brush_id -var hole_brush_id -var reverse_property_control - -var property_element_list:Array - -var color_brush_layer: MBrushLayers -var color_layer_group_id:int -var color_brush_uniform:String -var color_brush_name:String # "Color Paint", "Channel Painter", "Bitwise Brush", "Paint 16", Paint 256" - -var no_image = preload("res://addons/m_terrain/icons/no_images.png") #For color brush - - -@onready var add_color_brush_button = find_child("add_color_brush_button") - -func _ready(): - var panel = get_child(0) - panel.visible = false - panel.position.y = -panel.size.y - panel.gui_input.connect(fix_gui_input) - panel.size.x = get_viewport().size.x - global_position.x - panel.visibility_changed.connect(_on_panel_visibility_changed) - add_color_brush_button.pressed.connect(show_add_color_brush_popup) - -func fix_gui_input(event: InputEvent): - if event is InputEventMouseButton: - get_viewport().set_input_as_handled() - -func _toggled(toggled_on): - if toggled_on: - get_child(0).size.x = get_viewport().size.x - global_position.x - -func clear_brushes(): - #brush_container.clear() - for child in brush_container.get_children(): - brush_container.remove_child(child) - child.queue_free() - clear_property_element() - set("theme_override_styles/normal", null) - text = "" - for connection in brush_container.get_signal_connection_list("brush_selected"): - connection.signal.disconnect(connection.callable) - #for connection in brush_container.get_signal_connection_list("item_clicked"): - # connection.signal.disconnect(connection.callable) - add_color_brush_button.visible = false - find_child("brush_settings_panel").visible = false - - -#region Height Brushes -func init_height_brushes(new_brush_manager): - clear_brushes() - find_child("brush_settings_panel").visible = true - - brush_mode = &"sculpt" - #brush_container.brush_selected.connect(on_height_brush_select) - height_brush_manager = new_brush_manager - smooth_brush_id = height_brush_manager.get_height_brush_id("Smooth") - raise_brush_id = height_brush_manager.get_height_brush_id("Raise") - to_height_brush_id = height_brush_manager.get_height_brush_id("To Height") - hole_brush_id = height_brush_manager.get_height_brush_id("Hole") - - var brush_names = height_brush_manager.get_height_brush_list() - - for n in brush_names: - var brush_item = preload("res://addons/m_terrain/gui/mtools_brush_item.tscn").instantiate() - brush_container.add_child(brush_item) - if "raise" in n.to_lower(): - brush_item.set_height_brush(n, preload("res://addons/m_terrain/icons/brush_icon_raise.svg")) - if "height" in n.to_lower(): - brush_item.set_height_brush(n, preload("res://addons/m_terrain/icons/brush_icon_to_height.svg")) - if "smooth" in n.to_lower(): - brush_item.set_height_brush(n, preload("res://addons/m_terrain/icons/brush_icon_smooth.svg")) - if "hole" in n.to_lower(): - brush_item.set_height_brush(n, preload("res://addons/m_terrain/icons/brush_icon_hole.svg")) - if "layer" in n.to_lower(): - brush_item.set_height_brush(n, preload("res://addons/m_terrain/icons/eraser_icon.svg")) - - brush_item.brush_selected.connect(on_height_brush_select.bind(brush_item)) - on_height_brush_select(brush_container.get_child(0)) - -func on_height_brush_select(item): - clear_property_element() - height_brush_id = item.get_index() - var brush_props = height_brush_manager.get_height_brush_property(height_brush_id) - for p in brush_props: - create_props(p) - text = "" - set("theme_override_styles/normal", null) - icon = item.label.icon - tooltip_text = "Current brush: " + item.label.text - -func create_props(dic:Dictionary): - var element - if dic["type"]==TYPE_FLOAT: - var rng = dic["max"] - dic["min"] - if dic["hint"] == "range": - element = float_range_prop_element.instantiate() - brush_settings_container.add_child(element) - element.set_min(dic["min"]) - element.set_max(dic["max"]) - element.set_step(dic["hint_string"].to_float()) - else: - element = float_prop_element.instantiate() - brush_settings_container.add_child(element) - element.min = dic["min"] - element.max = dic["max"] - elif dic["type"]==TYPE_BOOL: - element = bool_element.instantiate() - brush_settings_container.add_child(element) - elif dic["type"]==TYPE_INT: - if dic["hint"] == "enum": - element = int_enum_element.instantiate() - brush_settings_container.add_child(element) - element.set_options(dic["hint_string"]) - else: - element = int_element.instantiate() - brush_settings_container.add_child(element) - element.set_min(dic["min"]) - element.set_max(dic["max"]) - element.prop_changed.connect(prop_change) - element.set_value(dic["default_value"]) - element.set_name(dic["name"]) - property_element_list.append(element) - if element.prop_name.to_lower() == "revers": - reverse_property_control = element - -func clear_property_element(): - for e in property_element_list: - if is_instance_valid(e): - e.queue_free() - property_element_list = [] - -func prop_change(prop_name,value): - height_brush_manager.set_height_brush_property(prop_name,value,height_brush_id) - -#endregion - -#region Color Brushes -func init_color_brushes(terrain: MTerrain = null, layer_group_id=0): - clear_brushes() - active_terrain = terrain - brush_mode = &"paint" - if terrain == null: - return - - add_color_brush_button.visible = true - color_brush_layer = active_terrain.brush_layers[layer_group_id] - - for i in color_brush_layer.layers.size(): - var brush = color_brush_layer.layers[i] - var bname = brush.NAME - if bname.is_empty(): - bname = str("layer ", i) - var bicon:Texture = load(brush.ICON) if FileAccess.file_exists(brush.ICON) else null - - var brush_item = preload("res://addons/m_terrain/gui/mtools_brush_item.tscn").instantiate() - brush_container.add_child(brush_item) - brush_item.set_color_brush(color_brush_layer, i) - brush_item.brush_selected.connect( brush_layer_selected.bind(brush_item.get_index(), color_brush_layer)) - brush_item.brush_edited.connect(update_color_brush) - brush_item.brush_removed.connect(remove_color_brush) - - color_layer_group_id = layer_group_id - color_brush_uniform = color_brush_layer.uniform_name - color_brush_name = color_brush_layer.brush_name - - if brush_container.get_child_count() != 0: - brush_layer_selected(0, layer_group_id) - -func brush_layer_selected(index, layer_group): - active_terrain.set_color_layer(index, color_layer_group_id,color_brush_name) - var brush_icon = brush_container.get_child(index).label.icon - if brush_icon and brush_icon != no_image: - icon = brush_icon - else: - icon = null - text = "" #brush_container.get_item_text(index) - tooltip_text = "Current brush: " + brush_container.get_child(index).label.text - var color = brush_container.get_child(index).color - if color: - var stylebox = StyleBoxFlat.new() - stylebox.bg_color = color - set("theme_override_styles/normal", stylebox) - set("theme_override_styles/focus", stylebox) - set("theme_override_styles/hover", stylebox) - set("theme_override_styles/pressed", stylebox) - else: - set("theme_override_styles/normal", null) - set("theme_override_styles/focus", null) - set("theme_override_styles/hover", null) - set("theme_override_styles/pressed", null) - - -func show_add_color_brush_popup(): - var popup = preload("res://addons/m_terrain/gui/mtools_create_color_brush.tscn").instantiate() - add_child(popup) - popup.size = get_viewport_rect().size / 3 - - var existing_brushes = color_brush_layer.layers.map(func(a): return a.NAME) - if color_brush_name == "Color Paint": - popup.init_for_color(existing_brushes) - elif color_brush_name == "Channel Painter": - popup.init_for_channel(existing_brushes) - elif color_brush_name == "Bitwise": - popup.init_for_bitwise(existing_brushes) - elif color_brush_name == "Paint 16": - popup.init_for_16(existing_brushes) - elif color_brush_name == "Paint 256": - popup.init_for_256(existing_brushes) - popup.brush_created.connect(update_color_brush.bind(-1)) - -func update_color_brush(brush_name, brush_icon, data, id): - if id == -1: - color_brush_layer.layers_num += 1 - id = color_brush_layer.layers_num -1 - color_brush_layer.layers[id].NAME = brush_name - color_brush_layer.layers[id].ICON = brush_icon - if "color" in data.keys(): - color_brush_layer.layers[id].color = data.color - color_brush_layer.layers[id].hardness = data.hardness - elif "r_on" in data.keys(): - color_brush_layer.layers[id].red = data.r_on - color_brush_layer.layers[id].green = data.g_on - color_brush_layer.layers[id].blue = data.b_on - color_brush_layer.layers[id].alpha = data.a_on - color_brush_layer.layers[id]["red-value"] = data.r_value - color_brush_layer.layers[id]["green-value"] = data.g_value - color_brush_layer.layers[id]["blue-value"] = data.b_value - color_brush_layer.layers[id]["alpha-value"] = data.a_value - color_brush_layer.layers[id].hardness = data.hardness - elif "bit" in data.keys(): - color_brush_layer.layers[id].value = data.bit_value - color_brush_layer.layers[id].bit = data.bit - elif "paint16layer" in data.keys(): - color_brush_layer.layers[id]['paint-layer'] = data.paint16layer - elif "paint256layer" in data.keys(): - color_brush_layer.layers[id]['paint-layer'] = data.paint256layer - - init_color_brushes(active_terrain, color_layer_group_id) - -func remove_color_brush(id): - var group: MBrushLayers = active_terrain.brush_layers[color_layer_group_id] - var brushes = group.layers.duplicate() - var index = 0 - if id > brushes.size()-1 or id < 0: - push_error("trying to delete nonexistant brush. Id: ", id) - return - for i in brushes.size(): - if i != id: - group.layers[index] = brushes[i] - index += 1 - group.layers_num -= 1 - - init_color_brushes.call_deferred(active_terrain, color_layer_group_id) -#endregion - -#region Grass Brushes -func init_grass_brushes(): - clear_brushes() - brush_mode = &"grass" - var brush_item_scene = preload("res://addons/m_terrain/gui/mtools_brush_item.tscn") - var brush_item = brush_item_scene.instantiate() - brush_container.add_child(brush_item) - brush_item.set_text_brush("Add Grass") - brush_item.brush_selected.connect(func(): on_grass_brush_select(0)) - - brush_item = brush_item_scene.instantiate() - brush_container.add_child(brush_item) - brush_item.set_text_brush("Remove Grass") - brush_item.brush_selected.connect(func(): on_grass_brush_select(1)) - - on_grass_brush_select(0) - -func on_grass_brush_select(id): - icon = null - if id==0: - is_grass_add = true - text = "Add Grass" - else: - is_grass_add = false - text = "Remove Grass" - -#endregion - - -#region MNavigation Brushes -func init_mnavigation_brushes(): - clear_brushes() - - brush_mode = &"navigation" - - var brush_item_scene = preload("res://addons/m_terrain/gui/mtools_brush_item.tscn") - var brush_item = brush_item_scene.instantiate() - brush_container.add_child(brush_item) - brush_item.set_text_brush("Add Navigation") - brush_item.brush_selected.connect(func(): on_grass_brush_select(0)) - - brush_item = brush_item_scene.instantiate() - brush_container.add_child(brush_item) - brush_item.set_text_brush("Remove Navigation") - brush_item.brush_selected.connect(func(): on_grass_brush_select(1)) - - on_mnavigation_brush_select(0) - -func on_mnavigation_brush_select(id): - if id==0: - is_grass_add = true - text = "Add Navigation" - else: - is_grass_add = false - text = "Remove Navigation" - -#endregion - -#region Input - -func process_input(event): - if brush_mode == &"sculpt": - if event.keycode == KEY_SHIFT: - if event.is_pressed(): - if not event.echo: - last_height_brush_id = height_brush_id - height_brush_id = smooth_brush_id - else: - height_brush_id = last_height_brush_id - elif event.keycode == KEY_CTRL: - if event.is_pressed(): - if not event.echo: - last_height_brush_id = height_brush_id - height_brush_id = to_height_brush_id - else: - height_brush_id = last_height_brush_id - elif event.keycode == KEY_ALT: - if not event.echo: - reverse_property_control.set_value(not reverse_property_control.value) - - elif brush_mode == &"paint": - pass - elif brush_mode == &"grass": - if event.keycode == KEY_ALT: - if event.is_pressed(): - if not event.echo: - is_grass_add = not is_grass_add - else: - is_grass_add = not is_grass_add -#endregion - - -func _on_resized(): - var vbox = get_child(0) - var settings = find_child("brush_settings_panel") - settings.custom_minimum_size.x = global_position.x-owner.global_position.x - settings.size = settings.custom_minimum_size - var size_panel = find_child("brush_size_panel") - size_panel.custom_minimum_size.x = size.x - size_panel.size = size_panel.custom_minimum_size - var brushes_panel = find_child("brush_brushes_panel") - brushes_panel.custom_minimum_size.x = (owner.size.x - size_panel.size.x - settings.size.x - 12) *0.5 - brushes_panel.size = brushes_panel.custom_minimum_size - - vbox.size.x = settings.size.x + size_panel.size.x + brushes_panel.size.x * 1.01 - if settings.visible: - vbox.global_position.x = owner.global_position.x - else: - vbox.position.x = 0 - - vbox.size.y = get_viewport_rect().size.y/5 - vbox.position.y = -vbox.size.y - - -func _on_panel_visibility_changed(): - _on_resized() diff --git a/addons/m_terrain/gui/mtools_color_brush_item.gd b/addons/m_terrain/gui/mtools_color_brush_item.gd deleted file mode 100644 index 997e804..0000000 --- a/addons/m_terrain/gui/mtools_color_brush_item.gd +++ /dev/null @@ -1,13 +0,0 @@ -extends Control - -var no_image = preload("res://addons/m_terrain/icons/no_images.png") - -var index:int -var uniform:String -var brush_name:String - -#func create(brush_name="", icon=no_image): - #if brush_name.is_empty(): - # brush_name = "layer "+str(index) - #var id = add_item(iname,icon) - #set_item_custom_bg_color(index,i["icon-color"]) diff --git a/addons/m_terrain/gui/mtools_color_brush_item.tscn b/addons/m_terrain/gui/mtools_color_brush_item.tscn deleted file mode 100644 index 192ac30..0000000 --- a/addons/m_terrain/gui/mtools_color_brush_item.tscn +++ /dev/null @@ -1,9 +0,0 @@ -[gd_scene format=3 uid="uid://bviuhw13qam3a"] - -[node name="Control" type="Control"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 diff --git a/addons/m_terrain/gui/mtools_create_color_brush.gd b/addons/m_terrain/gui/mtools_create_color_brush.gd deleted file mode 100644 index b2e5aea..0000000 --- a/addons/m_terrain/gui/mtools_create_color_brush.gd +++ /dev/null @@ -1,156 +0,0 @@ -@tool -extends Window -signal brush_created -@onready var create_button = find_child("create") -@onready var brush_name = find_child("brush_name") -@onready var icon = find_child("icon_path") -@onready var hardness = find_child("hardness") -@onready var color = find_child("color_picker") -@onready var r = find_child("ChannelR") -@onready var g = find_child("ChannelG") -@onready var b = find_child("ChannelB") -@onready var a = find_child("ChannelA") -@onready var bitwise = find_child("Bitwise") -@onready var paint16 = find_child("Paint16") -@onready var paint256 = find_child("Paint256") -@onready var brush_type = find_child("brush_type") -var existing_brush_names = [] -var is_update_mode = false - -func _ready(): - brush_name.text_changed.connect(validate_brush_name) - create_button.pressed.connect(func(): - brush_created.emit(brush_name.text, icon.text, get_data()) - queue_free() - ) - close_requested.connect(queue_free) - color.pressed.connect(func(): - var picker = color.get_picker().get_parent() - picker.position.x+= picker.size.x - picker.position.y = color.global_position.y + position.y - ) - var load_icon_button = find_child("load_icon_button") - load_icon_button.pressed.connect(func(): - var popup = FileDialog.new() - popup.file_mode = FileDialog.FILE_MODE_OPEN_FILE - popup.use_native_dialog = true - popup.filters = PackedStringArray(["*.png, *.jpg ; Image Files"]) - add_child(popup) - popup.show() - popup.size = size - popup.position = position - popup.file_selected.connect(func(file): icon.text = file) - ) - -func validate_brush_name(new_name): - if new_name in existing_brush_names: - create_button.disabled = true - create_button.text = "please pick a different brush name" - else: - create_button.disabled = false - create_button.text = "Update" if is_update_mode else "Create" - - -func get_data(): - if color.visible: - return {"color": color.color, "hardness": hardness.value} - elif r.visible: - return { - "r_on": r.button.button_pressed, - "r_value": r.slider.value, - "g_on": g.button.button_pressed, - "g_value": g.slider.value, - "b_on": b.button.button_pressed, - "b_value": b.slider.value, - "a_on": a.button.button_pressed, - "a_value": a.slider.value, - "hardness": hardness.value, - } - elif bitwise.visible: - return { "bit": bitwise.slider.value, "bit_value": bitwise.button.button_pressed} - elif paint16.visible: - return {"paint16layer": paint16.slider.value} - elif paint256.visible: - return {"paint256layer": paint256.slider.value} - -func clear_options(): - hardness.visible = false - color.visible = false - r.visible = false - g.visible = false - b.visible = false - a.visible = false - bitwise.visible = false - paint16.visible = false - paint256.visible = false - hardness.visible = false - -func init_for_color(existing_brushes): - clear_options() - color.visible = true - hardness.visible = true - existing_brush_names = existing_brushes - brush_type.text = "Color Brush Settings" - -func init_for_channel(existing_brushes): - clear_options() - r.visible = true - g.visible = true - b.visible = true - a.visible = true - hardness.visible = true - existing_brush_names = existing_brushes - brush_type.text = "Channel Brush Settings" - -func init_for_bitwise(existing_brushes): - clear_options() - bitwise.visible = true - existing_brush_names = existing_brushes - brush_type.text = "Bitwise Brush Settings" - -func init_for_16(existing_brushes): - clear_options() - paint16.visible = true - existing_brush_names = existing_brushes - brush_type.text = "Paint16 Brush Settings" - -func init_for_256(existing_brushes): - clear_options() - paint256.visible = true - existing_brush_names = existing_brushes - brush_type.text = "Paint256 Brush Settings" - -func load_brush(layer_group, bname, bicon, data={}): - var existing_brush_names = layer_group.layers.map(func(a): return a.NAME).filter(func(a): return a != bname) - brush_name.text = bname - if bname == "background": - brush_name.editable = false - icon.text = bicon - if layer_group.brush_name == "Color Paint": - init_for_color(existing_brush_names) - color.color = data.color - hardness.value = data.hardness - if layer_group.brush_name == "Channel Painter": - init_for_channel(existing_brush_names) - hardness.value = data.hardness - r.button.button_pressed = data.r_on - r.value_changed(data.r_value) - g.button.button_pressed = data.g_on - g.value_changed(data.g_value) - b.button.button_pressed = data.b_on - b.value_changed(data.b_value) - a.button.button_pressed = data.a_on - a.value_changed(data.a_value) - if layer_group.brush_name == "Bitwise Brush": - init_for_bitwise(existing_brush_names) - bitwise.button.button_pressed = data.bit_value - bitwise.value_changed(data.bit) - if layer_group.brush_name == "Paint 16": - init_for_16(existing_brush_names) - paint16.value_changed(data.paint16Layer) - if layer_group.brush_name == "Paint 256": - init_for_256(existing_brush_names) - paint256.value_changed(data.paint256Layer) - create_button.text = "Update" - is_update_mode = true - diff --git a/addons/m_terrain/gui/mtools_create_color_brush.tscn b/addons/m_terrain/gui/mtools_create_color_brush.tscn deleted file mode 100644 index 20082c4..0000000 --- a/addons/m_terrain/gui/mtools_create_color_brush.tscn +++ /dev/null @@ -1,261 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://csp8xxyqqfo6"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_10jgu"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_create_color_brush.gd" id="2_shva1"] -[ext_resource type="Texture2D" uid="uid://b4ylxie43lan2" path="res://addons/m_terrain/icons/more_options_icon.svg" id="3_hsfs1"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/channel_brush_control.gd" id="3_maa7g"] - -[sub_resource type="LabelSettings" id="LabelSettings_ukpju"] -font_size = 32 - -[node name="Window" type="Window"] -initial_position = 1 -size = Vector2i(800, 600) -wrap_controls = true -popup_window = true -max_size = Vector2i(800, 600) -theme = ExtResource("1_10jgu") -script = ExtResource("2_shva1") - -[node name="PanelContainer" type="PanelContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"] -layout_mode = 2 -theme_override_constants/separation = 15 - -[node name="brush_type" type="Label" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 -text = "Brush Type -" -label_settings = SubResource("LabelSettings_ukpju") -horizontal_alignment = 1 - -[node name="brush_name" type="LineEdit" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 -text = "New Brush" -alignment = 1 - -[node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 - -[node name="icon_path" type="LineEdit" parent="PanelContainer/VBoxContainer/HBoxContainer2"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "icon path eg. res://abc.svg" -alignment = 1 - -[node name="load_icon_button" type="Button" parent="PanelContainer/VBoxContainer/HBoxContainer2"] -custom_minimum_size = Vector2(64, 64) -layout_mode = 2 -icon = ExtResource("3_hsfs1") -icon_alignment = 1 -expand_icon = true - -[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Hardness: " - -[node name="hardness" type="HSlider" parent="PanelContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 1.0 -step = 0.05 - -[node name="color_picker" type="ColorPickerButton" parent="PanelContainer/VBoxContainer"] -visible = false -layout_mode = 2 -size_flags_vertical = 3 -text = " " - -[node name="ChannelR" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -visible = false -layout_mode = 2 -script = ExtResource("3_maa7g") - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/ChannelR"] -layout_mode = 2 -text = "R " -horizontal_alignment = 2 - -[node name="CheckBox" type="CheckBox" parent="PanelContainer/VBoxContainer/ChannelR"] -layout_mode = 2 - -[node name="LineEdit" type="LineEdit" parent="PanelContainer/VBoxContainer/ChannelR"] -layout_mode = 2 -theme_override_constants/minimum_character_width = 2 -text = "0" -max_length = 4 -editable = false - -[node name="HSlider" type="HSlider" parent="PanelContainer/VBoxContainer/ChannelR"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 1.0 -step = 0.05 -editable = false - -[node name="ChannelG" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -visible = false -layout_mode = 2 -script = ExtResource("3_maa7g") - -[node name="Label2" type="Label" parent="PanelContainer/VBoxContainer/ChannelG"] -layout_mode = 2 -text = "G " - -[node name="CheckBox" type="CheckBox" parent="PanelContainer/VBoxContainer/ChannelG"] -layout_mode = 2 - -[node name="LineEdit" type="LineEdit" parent="PanelContainer/VBoxContainer/ChannelG"] -layout_mode = 2 -theme_override_constants/minimum_character_width = 2 -text = "0" -max_length = 4 -editable = false - -[node name="HSlider" type="HSlider" parent="PanelContainer/VBoxContainer/ChannelG"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 1.0 -step = 0.05 -editable = false - -[node name="ChannelB" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -visible = false -layout_mode = 2 -script = ExtResource("3_maa7g") - -[node name="Label2" type="Label" parent="PanelContainer/VBoxContainer/ChannelB"] -layout_mode = 2 -text = "B " - -[node name="CheckBox" type="CheckBox" parent="PanelContainer/VBoxContainer/ChannelB"] -layout_mode = 2 - -[node name="LineEdit" type="LineEdit" parent="PanelContainer/VBoxContainer/ChannelB"] -layout_mode = 2 -theme_override_constants/minimum_character_width = 2 -text = "0" -max_length = 4 -editable = false - -[node name="HSlider" type="HSlider" parent="PanelContainer/VBoxContainer/ChannelB"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 1.0 -step = 0.05 -editable = false - -[node name="ChannelA" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -visible = false -layout_mode = 2 -script = ExtResource("3_maa7g") - -[node name="Label2" type="Label" parent="PanelContainer/VBoxContainer/ChannelA"] -layout_mode = 2 -text = "A " - -[node name="CheckBox" type="CheckBox" parent="PanelContainer/VBoxContainer/ChannelA"] -layout_mode = 2 - -[node name="LineEdit" type="LineEdit" parent="PanelContainer/VBoxContainer/ChannelA"] -layout_mode = 2 -theme_override_constants/minimum_character_width = 2 -text = "0" -max_length = 4 -editable = false - -[node name="HSlider" type="HSlider" parent="PanelContainer/VBoxContainer/ChannelA"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 1.0 -step = 0.05 -editable = false - -[node name="Bitwise" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 -script = ExtResource("3_maa7g") -is_bit = true -force_int = true - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/Bitwise"] -layout_mode = 2 -text = "Bit " - -[node name="CheckBox" type="CheckBox" parent="PanelContainer/VBoxContainer/Bitwise"] -layout_mode = 2 - -[node name="LineEdit" type="LineEdit" parent="PanelContainer/VBoxContainer/Bitwise"] -layout_mode = 2 -theme_override_constants/minimum_character_width = 2 -text = "0" -max_length = 3 - -[node name="HSlider" type="HSlider" parent="PanelContainer/VBoxContainer/Bitwise"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 127.0 - -[node name="Paint16" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -visible = false -layout_mode = 2 -script = ExtResource("3_maa7g") -is_bit = true -force_int = true - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/Paint16"] -layout_mode = 2 -text = "Paint layer: " - -[node name="HSlider" type="HSlider" parent="PanelContainer/VBoxContainer/Paint16"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 15.0 - -[node name="LineEdit" type="LineEdit" parent="PanelContainer/VBoxContainer/Paint16"] -layout_mode = 2 -theme_override_constants/minimum_character_width = 2 -text = "0" -max_length = 3 - -[node name="Paint256" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -visible = false -layout_mode = 2 -script = ExtResource("3_maa7g") -is_bit = true -force_int = true - -[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/Paint256"] -layout_mode = 2 -text = "Paint layer: " - -[node name="HSlider" type="HSlider" parent="PanelContainer/VBoxContainer/Paint256"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 255.0 - -[node name="LineEdit" type="LineEdit" parent="PanelContainer/VBoxContainer/Paint256"] -layout_mode = 2 -theme_override_constants/minimum_character_width = 2 -text = "0" -max_length = 3 - -[node name="create" type="Button" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 -text = "Create" diff --git a/addons/m_terrain/gui/mtools_edit_mode_selector.gd b/addons/m_terrain/gui/mtools_edit_mode_selector.gd deleted file mode 100644 index 4a73113..0000000 --- a/addons/m_terrain/gui/mtools_edit_mode_selector.gd +++ /dev/null @@ -1,138 +0,0 @@ -@tool -extends Button - -signal edit_mode_changed - -var item_container -var exit_edit_mode_button -var edit_selected_button -var active_object - -var more_options_icon = preload("res://addons/m_terrain/icons/more_options_icon.svg") - -func _ready(): - var panel = get_child(0) - panel.visible = false - panel.position.y = -panel.size.y-1 - - item_container = find_child("edit_mode_item_container") - exit_edit_mode_button = get_node("../edit_mode_exit_button") - edit_selected_button = get_node("../edit_selected_button") - - if not edit_selected_button.pressed.is_connected(edit_selected): - edit_selected_button.pressed.connect(edit_selected) - edit_selected_button.visible = false - - if not exit_edit_mode_button.pressed.is_connected(exit_edit_mode_button_pressed): - exit_edit_mode_button.pressed.connect(exit_edit_mode_button_pressed) - if not exit_edit_mode_button.pressed.is_connected(exit_edit_mode_button.hide): - exit_edit_mode_button.pressed.connect(exit_edit_mode_button.hide) - -func init_edit_mode_options(all_mterrain): - var button_template = Button.new() - button_template.mouse_filter = Control.MOUSE_FILTER_PASS - button_template.alignment = HORIZONTAL_ALIGNMENT_LEFT - var biggest_button_size = 0 - for child in item_container.get_children(): - child.queue_free() - - if all_mterrain.size() != 0: - for terrain in all_mterrain: - var button = button_template.duplicate() - button.text = "Sculpt " + terrain.name - item_container.add_child(button) - biggest_button_size = max(biggest_button_size, button.size.x) - button.pressed.connect(edit_selected.bind(terrain)) - - button = button_template.duplicate() - button.text = "Paint " + terrain.name - item_container.add_child(button) - button.pressed.connect(edit_selected.bind(terrain, &"paint")) - for child in terrain.get_children(): - if child is MGrass or child is MNavigationRegion3D: - button = button_template.duplicate() - button.text = "Paint " + child.name - item_container.add_child(button) - biggest_button_size = max(biggest_button_size, button.size.x) - button.pressed.connect(edit_selected.bind(child)) - - var all_nodes = EditorInterface.get_edited_scene_root().find_children("*") - for child in all_nodes: - var button - if child is MPath or child is MCurveMesh: - button = button_template.duplicate() - button.text = "Edit " + child.name - item_container.add_child(button) - biggest_button_size = max(biggest_button_size, button.size.x) - button.pressed.connect(edit_selected.bind(child)) - button_template.queue_free() - get_child(0).size. x = biggest_button_size + 12 - -func change_active_object(object): - #In future, make it auto-switch to the same edit mode, just for different object - if not object == active_object: - exit_edit_mode_button_pressed() - active_object = null - exit_edit_mode_button.visible = false - edit_selected_button.visible = true - if object is MTerrain: - active_object = object - edit_selected_button.text = "Click to Sculpt " + object.name - elif object is MGrass or object is MNavigationRegion3D: - active_object = object - edit_selected_button.text = "Click to Paint " + object.name - elif object is MPath or object is MCurveMesh: - active_object = object - edit_selected_button.text = "Click to Edit " + object.name - else: - edit_selected_button.visible = false - - text = "" - theme_type_variation - icon = more_options_icon - -func exit_edit_mode_button_pressed(): - edit_mode_changed.emit(null, &"") - change_active_object(active_object) - - - -func edit_selected(object = active_object, override_mode=null): - if object is MTerrain: - if override_mode and override_mode==&"paint": - text = "Paint " + object.name - theme_type_variation = "" - icon = null - edit_mode_changed.emit(object, &"paint") - else: - text = "Sculpt " + object.name - theme_type_variation = "" - icon = null - edit_mode_changed.emit(object, &"sculpt") - edit_selected_button.visible = false - exit_edit_mode_button.show() - active_object = object - elif object is MGrass or object is MNavigationRegion3D: - text = "Paint " + object.name - theme_type_variation = "" - icon = null - edit_mode_changed.emit(object, &"paint") - edit_selected_button.visible = false - exit_edit_mode_button.visible = true - active_object = object - elif object is MPath: - text = "Edit " + object.name - theme_type_variation = "" - icon = null - edit_mode_changed.emit(object, &"mpath") - edit_selected_button.visible = false - exit_edit_mode_button.show() - active_object = object - elif object is MCurveMesh: - text = "Edit " + object.name - theme_type_variation = "" - icon = null - edit_mode_changed.emit(object, &"mcurve_mesh") - edit_selected_button.visible = false - exit_edit_mode_button.show() - active_object = object diff --git a/addons/m_terrain/gui/mtools_keyboard_shortcut_item.gd b/addons/m_terrain/gui/mtools_keyboard_shortcut_item.gd deleted file mode 100644 index 1e0501d..0000000 --- a/addons/m_terrain/gui/mtools_keyboard_shortcut_item.gd +++ /dev/null @@ -1,34 +0,0 @@ -@tool -extends HBoxContainer - -signal keymap_changed - -@onready var label = $Label -@onready var value = $Button - -var waiting_for_input = false - -func _ready(): - value.pressed.connect(begin_remap) - -func begin_remap(): - value.text = "...waiting for input..." - waiting_for_input = true - -func _input(event): - if waiting_for_input and event is InputEventKey and event.pressed: - if event.keycode in [KEY_SHIFT, KEY_CTRL, KEY_ALT]: - return - var new_text = "" - if Input.is_key_pressed(KEY_CTRL): - new_text += "ctrl " - if Input.is_key_pressed(KEY_ALT): - if new_text != "": - new_text += "+ " - new_text += "alt " - if Input.is_key_pressed(KEY_SHIFT): - if new_text != "": - new_text += "+ " - new_text += "shift " - value.text = OS.get_keycode_string(event.keycode) - keymap_changed.emit(name, event.keycode, Input.is_key_pressed(KEY_CTRL), Input.is_key_pressed(KEY_ALT), Input.is_key_pressed(KEY_SHIFT) ) diff --git a/addons/m_terrain/gui/mtools_keyboard_shortcut_item.tscn b/addons/m_terrain/gui/mtools_keyboard_shortcut_item.tscn deleted file mode 100644 index 9d7c07a..0000000 --- a/addons/m_terrain/gui/mtools_keyboard_shortcut_item.tscn +++ /dev/null @@ -1,23 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://co53fkr4oogwn"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_keyboard_shortcut_item.gd" id="1_e0rfo"] - -[node name="HBoxContainer" type="HBoxContainer"] -alignment = 1 -script = ExtResource("1_e0rfo") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -text = "key" -horizontal_alignment = 2 - -[node name="VSeparator" type="VSeparator" parent="."] -layout_mode = 2 -theme_override_constants/separation = 32 - -[node name="Button" type="Button" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -text = "value" -alignment = 0 diff --git a/addons/m_terrain/gui/mtools_layer_item.gd b/addons/m_terrain/gui/mtools_layer_item.gd deleted file mode 100644 index 8b11129..0000000 --- a/addons/m_terrain/gui/mtools_layer_item.gd +++ /dev/null @@ -1,153 +0,0 @@ -@tool -extends Control - -signal layer_visibility_changed -signal layer_renamed -signal layer_index_changed -signal layer_removed -signal layer_selected -signal color_layer_removed -signal layer_merged_with_background - - -@onready var visibility_button = $hbox/visible -@onready var name_button = $hbox/name -@onready var merge_down_button = $hbox/merge_down -@onready var remove_button = $hbox/remove -@onready var move_up_button = $hbox/move_up -@onready var move_down_button = $hbox/move_down -@onready var rename_button = $hbox/rename -@onready var rename_input = $hbox/rename_input -var icon_visible = preload("res://addons/m_terrain/icons/eye.svg") -var icon_hidden = preload("res://addons/m_terrain/icons/eye-close.svg") - -var selected = false - -var confirmation_popup_scene = preload("res://addons/m_terrain/gui/mtools_layer_warning_popup.tscn") - -func _ready(): - name_button.pressed.connect(select_layer) - -func disconnect_signals(): -# for connection in name_button.get_signal_connection_list("pressed"): -# connection.signal.disconnect(connection.callable) -# for connection in remove_button.get_signal_connection_list("pressed"): -# connection.signal.disconnect(connection.callable) - for connection in rename_button.get_signal_connection_list("pressed"): - connection.signal.disconnect(connection.callable) - for connection in rename_input.get_signal_connection_list("text_submitted"): - connection.signal.disconnect(connection.callable) - for connection in rename_input.get_signal_connection_list("focus_exited"): - connection.signal.disconnect(connection.callable) - -func select_layer(): - layer_selected.emit(get_index(), name_button.text) - -func remove_heightmap_layer(): - var popup = confirmation_popup_scene.instantiate() - add_child(popup) - popup.confirmed.connect( func(): - layer_removed.emit(name) - queue_free() - ) - - -func init_for_heightmap(): - disconnect_signals() - if name == "background": - rename_button.queue_free() - remove_button.queue_free() - move_up_button.queue_free() - move_down_button.queue_free() - visibility_button.queue_free() - name_button.text = name - visibility_button.toggled.connect(change_visibility) - merge_down_button.pressed.connect(merge_layer_down) - rename_button.pressed.connect(begin_rename) - rename_input.text_submitted.connect(end_rename) - rename_input.focus_exited.connect(end_rename.bind("")) - remove_button.pressed.connect(remove_heightmap_layer) - -func change_visibility(toggle_on): - visibility_button.icon = icon_hidden if toggle_on else icon_visible - layer_visibility_changed.emit(name) - -func merge_layer_down(): - var popup = confirmation_popup_scene.instantiate() - add_child(popup) - popup.confirmed.connect( func(): - layer_merged_with_background.emit(name) - queue_free() - ) - -func begin_rename(): - rename_input.text = name_button.text - rename_input.visible = true - name_button.visible = false - rename_button.visible = false - rename_input.grab_focus() - -func end_rename(_new_name=""): - if rename_input.text == "": return - rename_input.visible = false - name_button.visible = true - rename_button.visible = true - layer_renamed.emit(name_button, rename_input.text) - - -func remove_color_layer(terrain:MTerrain,layer_group_index:int): - var popup = preload("res://addons/m_terrain/gui/mtools_popup_remove_color_layer.tscn").instantiate() - var layer:MBrushLayers = terrain.brush_layers[layer_group_index] - add_child(popup) - var uniform = layer.uniform_name - var layers_with_same_uniform = [] - for l in terrain.brush_layers: - if l.uniform_name == uniform and l.layers_title != name: - layers_with_same_uniform.push_back(l.layers_title) - popup.set_shared_uniform_label(layers_with_same_uniform) - popup.confirmed.connect( func(both): - color_layer_removed.emit(terrain, layer_group_index,both) - queue_free() - ) - -func init_for_colors(terrain:MTerrain, layer_group_index:int): - var layer:MBrushLayers = terrain.brush_layers[layer_group_index] - disconnect_signals() - rename_button.queue_free() - rename_input.queue_free() - #remove_button.queue_free() - move_up_button.queue_free() - move_down_button.queue_free() - merge_down_button.queue_free() - visibility_button.queue_free() - - name_button.text = layer.layers_title if layer.layers_title != "" else str("layer group ", layer_group_index) - remove_button.pressed.connect(remove_color_layer.bind(terrain,layer_group_index)) - #rename_button.pressed.connect(begin_rename) - #rename_input.text_submitted.connect(end_rename) - #rename_input.focus_exited.connect(end_rename.bind("")) - - -#region Theme: color and size etc -func _on_resized(): - resize_children_recursive(self, custom_minimum_size.y) - -func resize_children_recursive(parent, new_size): - for child in parent.get_children(): - if child is Control: - child.custom_minimum_size.x = new_size - child.custom_minimum_size.y = new_size - resize_children_recursive(child, new_size) - -func get_total_width(): - var total = name_button.text.length() * get_theme_default_font_size() *0.75 - #name_button.size.x if is_instance_valid(name_button) and name_button.visible else total - - total = total + visibility_button.size.x if is_instance_valid(visibility_button) and visibility_button.visible else total - total = total + rename_button.size.x if is_instance_valid(rename_button) and rename_button.visible else total - total = total + merge_down_button.size.x if is_instance_valid(merge_down_button) and merge_down_button.visible else total - total = total + remove_button.size.x if is_instance_valid(remove_button) and remove_button.visible else total - total *= 1.01 - return total -#endregion - diff --git a/addons/m_terrain/gui/mtools_layer_item.tscn b/addons/m_terrain/gui/mtools_layer_item.tscn deleted file mode 100644 index 727113f..0000000 --- a/addons/m_terrain/gui/mtools_layer_item.tscn +++ /dev/null @@ -1,97 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://yyvmuhqx1jgi"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_layer_item.gd" id="1_v5m32"] -[ext_resource type="Texture2D" uid="uid://fj1va27m7i5e" path="res://addons/m_terrain/icons/eye.svg" id="2_h5ewu"] -[ext_resource type="Texture2D" uid="uid://s6jqtql0r2bw" path="res://addons/m_terrain/icons/edit_icon.svg" id="3_8xkqq"] -[ext_resource type="Texture2D" uid="uid://tow1rj13cxaw" path="res://addons/m_terrain/icons/merge_down_icon.svg" id="4_brtxh"] -[ext_resource type="Texture2D" uid="uid://t8tdan3853oy" path="res://addons/m_terrain/icons/icon_close.svg" id="5_yuyg3"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_swm5a"] - -[node name="Panel" type="Panel"] -custom_minimum_size = Vector2(0, 42) -anchors_preset = 10 -anchor_right = 1.0 -grow_horizontal = 2 -size_flags_horizontal = 3 -mouse_filter = 1 -theme_override_styles/panel = SubResource("StyleBoxEmpty_swm5a") -script = ExtResource("1_v5m32") - -[node name="hbox" type="HBoxContainer" parent="."] -show_behind_parent = true -custom_minimum_size = Vector2(42, 42) -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="visible" type="Button" parent="hbox"] -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -tooltip_text = "Hide layer" -mouse_filter = 1 -toggle_mode = true -icon = ExtResource("2_h5ewu") -expand_icon = true - -[node name="name" type="Button" parent="hbox"] -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "select layer" -mouse_filter = 1 -text = "Panel" -alignment = 0 - -[node name="move_up" type="Button" parent="hbox"] -visible = false -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -mouse_filter = 1 -text = "^" - -[node name="move_down" type="Button" parent="hbox"] -visible = false -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -mouse_filter = 1 -text = "v" - -[node name="rename_input" type="LineEdit" parent="hbox"] -visible = false -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -size_flags_horizontal = 3 -mouse_filter = 1 -placeholder_text = "Old Layer name" -max_length = 36 -expand_to_text_length = true - -[node name="rename" type="Button" parent="hbox"] -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -tooltip_text = "edit layer" -mouse_filter = 1 -icon = ExtResource("3_8xkqq") -expand_icon = true - -[node name="merge_down" type="Button" parent="hbox"] -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -tooltip_text = "merge layer with background" -mouse_filter = 1 -icon = ExtResource("4_brtxh") -expand_icon = true - -[node name="remove" type="Button" parent="hbox"] -custom_minimum_size = Vector2(42, 42) -layout_mode = 2 -tooltip_text = "remove layer" -mouse_filter = 1 -icon = ExtResource("5_yuyg3") -expand_icon = true - -[connection signal="resized" from="." to="." method="_on_resized"] diff --git a/addons/m_terrain/gui/mtools_layer_warning_popup.gd b/addons/m_terrain/gui/mtools_layer_warning_popup.gd deleted file mode 100644 index 9ec2819..0000000 --- a/addons/m_terrain/gui/mtools_layer_warning_popup.gd +++ /dev/null @@ -1,8 +0,0 @@ -@tool -extends Window -signal confirmed -func _ready(): - find_child("confirm_button").pressed.connect(func(): confirmed.emit()) - find_child("confirm_button").pressed.connect(queue_free) - find_child("cancel_button").pressed.connect(queue_free) - close_requested.connect(queue_free) diff --git a/addons/m_terrain/gui/mtools_layer_warning_popup.tscn b/addons/m_terrain/gui/mtools_layer_warning_popup.tscn deleted file mode 100644 index ca380d1..0000000 --- a/addons/m_terrain/gui/mtools_layer_warning_popup.tscn +++ /dev/null @@ -1,52 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://c58bes0ffhqo"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_layer_warning_popup.gd" id="1_ledk4"] -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_or3fh"] - -[node name="Control" type="Window"] -initial_position = 2 -size = Vector2i(400, 300) -always_on_top = true -popup_window = true -theme = ExtResource("1_or3fh") -script = ExtResource("1_ledk4") - -[node name="Panel" type="PanelContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="MarginContainer" type="MarginContainer" parent="Panel"] -layout_mode = 2 -theme_override_constants/margin_left = 0 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="Panel/MarginContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 6 -text = "Are you sure? - -You will not be able to undo this." -horizontal_alignment = 1 - -[node name="HBoxContainer" type="HBoxContainer" parent="Panel/MarginContainer/VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="confirm_button" type="Button" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Confirm" - -[node name="VSeparator" type="VSeparator" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -theme_override_constants/separation = 20 - -[node name="cancel_button" type="Button" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Cancel" diff --git a/addons/m_terrain/gui/mtools_layers.gd b/addons/m_terrain/gui/mtools_layers.gd deleted file mode 100644 index 4a9cad4..0000000 --- a/addons/m_terrain/gui/mtools_layers.gd +++ /dev/null @@ -1,228 +0,0 @@ -@tool -extends Button - -signal layer_changed - -@onready var layers_container:Control = find_child("layer_item_container") -@onready var add_height_layer_button: Button = find_child("add_height_layer_button") -@onready var add_color_layer_button: Button = find_child("add_color_layer_button") -@onready var merge_height_layers_button: Button = find_child("merge_height_layers_button") -@onready var height_layer_controls: Control = find_child("layer_controls") -var active_terrain: MTerrain = null -var active_heightmap_layer = "" - -var hide_icon = preload("res://addons/m_terrain/icons/hidden.png") -var show_icon = preload("res://addons/m_terrain/icons/show.png") -var layer_item_scene = preload("res://addons/m_terrain/gui/mtools_layer_item.tscn") -var stylebox_selected = preload("res://addons/m_terrain/gui/styles/stylebox_selected.tres") - -var brush_control: Control -var confirmation_popup_scene = preload("res://addons/m_terrain/gui/mtools_layer_warning_popup.tscn") - - -func _ready(): - var panel:Control = get_child(0) - panel.visible = false - panel.position.y = -panel.size.y-2 - panel.gui_input.connect(fix_gui_input) - panel.visibility_changed.connect(func(): - var max_width = 0 - for child in layers_container.get_children(): - if child.get_total_width() > max_width: - max_width = child.get_total_width() - max_width = min(max_width, owner.mtools_root.get_child(0).size.x) - panel.custom_minimum_size.x = max_width - panel.size.x = max_width - ) - - merge_height_layers_button.pressed.connect(merge_all_heightmap_layers) - add_height_layer_button.pressed.connect(add_heightmap_layer) - add_color_layer_button.pressed.connect(add_color_layer) - -func fix_gui_input(event: InputEvent): - if event is InputEventMouseButton: - get_viewport().set_input_as_handled() - -func clear_layers(): - add_height_layer_button.visible = false - merge_height_layers_button.visible = false - add_color_layer_button.visible = false - for child in layers_container.get_children(): - child.queue_free() - layers_container.remove_child(child) - -#region Height Layers -func init_height_layers(mterrain:MTerrain): - active_terrain = mterrain - clear_layers() - add_height_layer_button.visible = true - merge_height_layers_button.visible = true - for layer in active_terrain.heightmap_layers: - var layer_item = layer_item_scene.instantiate() - layer_item.name = layer - layers_container.add_child(layer_item) - layer_item.custom_minimum_size = custom_minimum_size - layer_item.init_for_heightmap() - layer_item.layer_selected.connect(change_heightmap_layer_selection) - layer_item.layer_visibility_changed.connect(toggle_heightmap_layer_visibility) - layer_item.layer_renamed.connect(rename_heightmap_layer) - #layer_item.layer_index_changed.connect(????) - layer_item.layer_removed.connect(remove_heightmap_layer) - layer_item.layer_merged_with_background.connect(merge_heightmap_layer_with_background) - if layers_container.get_child_count()!=0: - layers_container.get_child(0).select_layer.call_deferred() - - -func add_heightmap_layer(): - var i = 0 - while str("New Layer ", i) in active_terrain.heightmap_layers: - i+= 1 - active_terrain.add_heightmap_layer(str("New Layer ", i)) - init_height_layers(active_terrain) - -func remove_heightmap_layer(layer_name): - active_terrain.set_active_layer_by_name(layer_name) - active_terrain.remove_heightmap_layer() - if layer_name == active_heightmap_layer: - change_heightmap_layer_selection(0, "background") - else: - active_terrain.set_active_layer_by_name(active_heightmap_layer) - -func toggle_heightmap_layer_visibility(layer_name): - active_terrain.set_active_layer_by_name(layer_name) - active_terrain.toggle_heightmap_layer_visibile() - active_terrain.set_active_layer_by_name(active_heightmap_layer) - -func change_heightmap_layer_selection(id, layer_name): - active_heightmap_layer = layer_name - active_terrain.set_active_layer_by_name(layer_name) - for layer in layers_container.get_children(): - if layer.name == layer_name: - layer.selected = true - layer.set("theme_override_styles/panel", stylebox_selected) - else: - layer.selected = false - layer.set("theme_override_styles/panel", StyleBoxEmpty.new()) - text = layer_name - layer_changed.emit(layer_name) - -func merge_all_heightmap_layers(): - var popup = confirmation_popup_scene.instantiate() - add_child(popup) - popup.confirmed.connect( func(): - for layer in active_terrain.heightmap_layers: - if layer == "background": continue - active_terrain.set_active_layer_by_name(layer) - active_terrain.merge_heightmap_layer() - init_height_layers(active_terrain) - ) - -func merge_heightmap_layer_with_background(layer): - active_terrain.set_active_layer_by_name(layer) - active_terrain.merge_heightmap_layer() - -func rename_heightmap_layer(name_button, new_name): - if new_name == "": return - if new_name in active_terrain.heightmap_layers: return - var layers = active_terrain.heightmap_layers - - for i in layers.size(): - if layers[i] == name_button.text: - if active_terrain.rename_heightmap_layer(layers[i], new_name): - layers[i] = new_name - - name_button.text = new_name - name_button.name = new_name - text = new_name - - #init_height_layers(active_terrain) - -#endregion - -#region Color Layers -func init_color_layers(mterrain:MTerrain = active_terrain, brush_button = brush_control): - if not mterrain or not brush_button: - push_error("init color layers failed: no mterrain or no brush button" ) - return - active_terrain = mterrain - clear_layers() - add_color_layer_button.visible = true - brush_control = brush_button - var valid_count:int = 0 - for i in range(active_terrain.brush_layers.size()): - if validate_brush_layer_data(active_terrain.brush_layers[i]): - add_color_layer_item(active_terrain, i) - valid_count += 1 - else: - active_terrain.brush_layers.erase(active_terrain.brush_layers[i]) - active_terrain.brush_layers_groups_num -= 1 - if valid_count > 0: - layers_container.get_child(0).select_layer() - else: - text = "(click to add a color layer)" - change_color_layer_selection(-1, "") - -func validate_brush_layer_data(layer): - if layer.uniform_name in active_terrain.get_image_list(): - return true - else: - - push_error("layer ", layer.layers_title, " has invalid uniform: ", layer.uniform_name) - -func add_color_layer_item(terrain:MTerrain, layer_group_index:int): - var layer_item = layer_item_scene.instantiate() - #layer_item.name = layer.layers_title if layer.layers_title != "" else str("layer group ", layer_group_id) - layers_container.add_child(layer_item) - layer_item.init_for_colors(terrain,layer_group_index) - #layer_item.name_button.tooltip_text = str("select ", layer.layers_title, ". Uniform: ", layer.uniform_name) - layer_item.layer_selected.connect(change_color_layer_selection) - layer_item.color_layer_removed.connect(remove_color_layer) - -func change_color_layer_selection(layer_id, layer_name): - if layer_id < 0: - layer_changed.emit(layer_id) - else: - brush_control.init_color_brushes(active_terrain, layer_id) - text = layer_name - layer_changed.emit(layer_id) - - -func add_color_layer(): - var window = preload("res://addons/m_terrain/gui/color_layer_creator_window.tscn").instantiate() - add_child(window) - window.set_terrain(active_terrain) - window.layer_created.connect(func(layer): - add_color_layer_item(active_terrain, active_terrain.brush_layers_groups_num-1 ) - change_color_layer_selection(active_terrain.brush_layers_groups_num-1, active_terrain.brush_layers[active_terrain.brush_layers_groups_num-1].layers_title) - ) - -func rename_color_layer(): - pass - -func remove_color_layer(terrain:MTerrain, layer_group_index:int,both:bool): - var layer:MBrushLayers = terrain.brush_layers[layer_group_index] - var dname = layer.uniform_name - if both: - owner.remove_image(active_terrain, dname) - var layers = terrain.brush_layers - var id = 0 - var remove_count = 0 - if both: - var i:int=terrain.brush_layers.size() - 1 - while i >= 0: - if(terrain.brush_layers[i].uniform_name == dname): - terrain.brush_layers.remove_at(i) - i-=1 - else: - terrain.brush_layers.remove_at(layer_group_index) - terrain.brush_layers_groups_num = terrain.brush_layers.size() - if terrain.brush_layers.size() > 0: - change_color_layer_selection(0, terrain.brush_layers[0].layers_title) - else: - change_color_layer_selection(-1, "") - init_color_layers() - -#endregion - -func init_grass_toggle(): - pass diff --git a/addons/m_terrain/gui/mtools_mask_list.gd b/addons/m_terrain/gui/mtools_mask_list.gd deleted file mode 100644 index 74f50ff..0000000 --- a/addons/m_terrain/gui/mtools_mask_list.gd +++ /dev/null @@ -1,81 +0,0 @@ -@tool -extends ItemList - -const brush_masks_dir:String = "res://addons/m_terrain/brush_masks/" -const allowed_extension:PackedStringArray = ["jpg","jpeg","png","exr","bmp","dds","hdr","tga","svg","webp"] - -var mask = null - -var is_loaded := false -var current_selected_index:int=-1 - -var images:Array -var textures:Array - -func _ready(): - clear() - -func load_images(mask_decal): - mask = mask_decal - if is_loaded: return - clear() - add_icon_item( preload("res://addons/m_terrain/icons/no_mask_icon.svg")) - #add_item("NULL") - var dir = DirAccess.open(brush_masks_dir) - if not dir: - printerr("Can not open brush masks directory") - return - var files:Array - dir.list_dir_begin() - ## finding files inside mask directory - while true: - var f = dir.get_next() - if f == "": - break - files.push_back(f) - var files_path:Array - ## Validating files path - for f in files: - if allowed_extension.has(f.get_extension()): - files_path.push_back(brush_masks_dir.path_join(f)) - ## Creating image and texture - for p in files_path: - var img = Image.load_from_file(p) - img.convert(Image.FORMAT_RF) - if img: - images.push_back(img) - textures.push_back(ImageTexture.create_from_image(img)) - ## Adding items - for tex in textures: - add_item("",tex) - is_loaded = true - if images.size() > 0: - mask.set_mask(null,null) - -func get_image(): - if images.size() == 0 : return -1 - return images[current_selected_index] - -func get_texture(): - if images.size() == 0 : return -1 - return textures[current_selected_index] - -func _on_item_selected(index): - if index == 0: - mask.set_mask(null,null) - current_selected_index = -1 - return - current_selected_index = index - 1 - mask.set_mask(images[current_selected_index],textures[current_selected_index]) - -func invert_selected_image(): - if current_selected_index == -1:return - var img:Image= images[current_selected_index] - for j in range(img.get_height()): - for i in range(img.get_width()): - var val:float= img.get_pixel(i,j).r - val = 1.0 - val; - img.set_pixel(i,j,Color(val,0,0,1)) - textures[current_selected_index] = ImageTexture.create_from_image(img) - set_item_icon(current_selected_index+1,textures[current_selected_index]) - mask.set_mask(images[current_selected_index],textures[current_selected_index]) diff --git a/addons/m_terrain/gui/mtools_mask_list.tscn b/addons/m_terrain/gui/mtools_mask_list.tscn deleted file mode 100644 index b51758f..0000000 --- a/addons/m_terrain/gui/mtools_mask_list.tscn +++ /dev/null @@ -1,16 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://b6wfdaqojnwju"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_mask_list.gd" id="1_sg3sf"] - -[node name="brush_masks" type="ItemList"] -custom_minimum_size = Vector2(0, 160) -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 160.0 -grow_horizontal = 2 -allow_reselect = true -max_columns = 8 -fixed_icon_size = Vector2i(64, 64) -script = ExtResource("1_sg3sf") - -[connection signal="item_selected" from="." to="." method="_on_item_selected"] diff --git a/addons/m_terrain/gui/mtools_masks.gd b/addons/m_terrain/gui/mtools_masks.gd deleted file mode 100644 index d9b0aa1..0000000 --- a/addons/m_terrain/gui/mtools_masks.gd +++ /dev/null @@ -1,91 +0,0 @@ -#MASK BUTTON -@tool -extends Button - -@onready var mask_container = find_child("mask_list") -var mask_cutoff_control -var mask_decal -var mask_clear_button -var mterrain:MTerrain # this is set when MTools is changing edit mode - -func _ready(): - var panel = get_child(0) - panel.visible = false - panel.position.y = -panel.size.y - panel.size.x = get_viewport().size.x - global_position.x - panel.gui_input.connect(fix_gui_input) - mask_clear_button = $"../mask_clear_button" - mask_clear_button.visible = false - - -func fix_gui_input(event:InputEvent): - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: - get_viewport().set_input_as_handled() - - -func init_masks(mask, mask_size_control, mask_rotation_control, new_mask_cutoff_control:Control, mask_invert_button:BaseButton): - mask_cutoff_control = new_mask_cutoff_control - mask_clear_button.pressed.connect(clear_mask) - mask_container.load_images(mask) - mask_decal = mask - mask_container.item_selected.connect(start_mask_placement) - mask_size_control.value_changed.connect(change_mask_size) - mask_rotation_control.value_changed.connect(change_mask_rotation) - mask_cutoff_control.value_changed.connect(change_mask_cutoff) - mask_invert_button.pressed.connect(mask_container.invert_selected_image) - -func clear_mask(): - var current_selection = mask_container.get_selected_items() - if current_selection.size()==0: return - mask_clear_button.visible = false - mask_decal.visible = false - mask_decal.is_being_edited = false - #change_mask_cutoff(0) - if current_selection[0] != 0: - mask_container.select(0) - mask_decal.set_mask(null,null) - icon = mask_container.get_item_icon(0) - text = "" - clear_mask() - - -func change_mask_size(value): - mask_decal.set_size(value) - -func change_mask_rotation(value): - mask_decal.set_image_rotation(value) - -func change_mask_cutoff(value): - mterrain.set_mask_cutoff(value) - -func start_mask_placement(id): - if id == 0: - clear_mask() - return - mask_clear_button.visible = true - mask_decal.visible = true - mask_decal.is_being_edited = true - icon = mask_decal.active_tex - text = "" - -func toggle_grass_settings(toggle_on): - mask_cutoff_control.visible = toggle_on - mterrain.set_mask_cutoff(mask_cutoff_control.slider.value) - -func _on_h_box_container_resized(): - var vbox = get_child(0) - if not mask_container: - await ready - mask_container.custom_minimum_size.x = global_position.x-owner.global_position.x - mask_container.fixed_icon_size = get_parent().custom_minimum_size *2 - mask_container.max_columns = floor( mask_container.custom_minimum_size.x / mask_container.fixed_icon_size.x) - find_child("mask_size").custom_minimum_size.x = size.x - vbox.size.x = owner.size.x - vbox.global_position.x = owner.global_position.x - vbox.size.y = get_viewport_rect().size.y/5 - vbox.position.y = -vbox.size.y-2 - - #vbox.size.x = owner.size.x - (global_position.x - owner.global_position.x) - #vbox.global_position.x = global_position.x - - diff --git a/addons/m_terrain/gui/mtools_options.gd b/addons/m_terrain/gui/mtools_options.gd deleted file mode 100644 index 5fa605b..0000000 --- a/addons/m_terrain/gui/mtools_options.gd +++ /dev/null @@ -1,12 +0,0 @@ -@tool -extends Button - -func _ready(): - var panel = get_child(0) - panel.visible = false - #panel.size.y = - panel.position.y = -panel.size.y - 4 - - -func _on_panel_container_resized(): - $PanelContainer.position.y = -$PanelContainer.size.y - 2 diff --git a/addons/m_terrain/gui/mtools_popup_remove_color_layer.gd b/addons/m_terrain/gui/mtools_popup_remove_color_layer.gd deleted file mode 100644 index df79700..0000000 --- a/addons/m_terrain/gui/mtools_popup_remove_color_layer.gd +++ /dev/null @@ -1,19 +0,0 @@ -@tool -extends Window -signal confirmed -func _ready(): - find_child("delete_layer").pressed.connect(func(): confirmed.emit(false)) - find_child("delete_layer_and_image").pressed.connect(func(): confirmed.emit(true)) - find_child("delete_layer").pressed.connect(queue_free) - find_child("delete_layer_and_image").pressed.connect(queue_free) - find_child("cancel_button").pressed.connect(queue_free) - close_requested.connect(queue_free) - -func set_shared_uniform_label(list:Array): - if list == []: - find_child("shared_uniform_label").visible = false - else: - var names = "" - for i in list: - names += str(i, ", ") - find_child("shared_uniform_label").text = "this image is shared with: " + names diff --git a/addons/m_terrain/gui/mtools_popup_remove_color_layer.tscn b/addons/m_terrain/gui/mtools_popup_remove_color_layer.tscn deleted file mode 100644 index 6bf8eae..0000000 --- a/addons/m_terrain/gui/mtools_popup_remove_color_layer.tscn +++ /dev/null @@ -1,59 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cj0dtgvd7v07g"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_ebtbp"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/mtools_popup_remove_color_layer.gd" id="2_65b52"] - -[node name="Control" type="Window"] -initial_position = 2 -size = Vector2i(400, 300) -wrap_controls = true -always_on_top = true -popup_window = true -theme = ExtResource("1_ebtbp") -script = ExtResource("2_65b52") - -[node name="Panel" type="PanelContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="MarginContainer" type="MarginContainer" parent="Panel"] -layout_mode = 2 -theme_override_constants/margin_left = 0 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="Panel/MarginContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 6 -text = "Are you sure? - -You will not be able to undo this." -horizontal_alignment = 1 - -[node name="shared_uniform_label" type="Label" parent="Panel/MarginContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 6 -text = "This image is also used by:" -horizontal_alignment = 1 - -[node name="HBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer/VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="delete_layer" type="Button" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Delete Layer Only" - -[node name="delete_layer_and_image" type="Button" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Delete Image And Connnected Layers" - -[node name="cancel_button" type="Button" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Cancel" diff --git a/addons/m_terrain/gui/mtools_slider_value.gd b/addons/m_terrain/gui/mtools_slider_value.gd deleted file mode 100644 index 61e9c42..0000000 --- a/addons/m_terrain/gui/mtools_slider_value.gd +++ /dev/null @@ -1,23 +0,0 @@ -@tool -extends BoxContainer -signal value_changed -@onready var slider = $VSlider -@onready var textbox = $LineEdit - - -func _ready(): - slider.value_changed.connect(update_value) - textbox.text_submitted.connect(update_value) - -func update_value(new_value): - var changed = false - new_value = clamp(float(new_value), slider.min_value, slider.max_value) - if slider.value != float(new_value): - textbox.text = str(new_value) #to ensure that it is clamped - slider.value = new_value - changed = true - if textbox.text != str(new_value): - textbox.text = str(new_value) - changed = true - if changed: - value_changed.emit(new_value) diff --git a/addons/m_terrain/gui/mtools_status_bar.gd b/addons/m_terrain/gui/mtools_status_bar.gd deleted file mode 100644 index 4c776ed..0000000 --- a/addons/m_terrain/gui/mtools_status_bar.gd +++ /dev/null @@ -1,33 +0,0 @@ -@tool -extends HBoxContainer - -func toggle_visible(toggled_on): - visible = not toggled_on - -func set_height_label(input:float): - $h_label.text = ("H: "+str(input)+"m").pad_decimals(2) - -func disable_height_label(): - $h_label.text = "H: UNKOWN" - -func set_distance_label(input:float): - $d_label.text = ("D: "+str(input)+"m").pad_decimals(2) - -func disable_distance_label(): - $d_label.text = "D: UNKOWN" - -func set_grass_label(input:int): - $g_label.text = " G: " + str(input) - -func disable_grass_label(): - $g_label.text = "" - -func set_region_label(input:int): - $r_label.text = "R:"+str(input) - -func disable_region_label(): - $r_label.text = "" - - -func _on_hide_status_toggled(toggled_on: bool) -> void: - pass # Replace with function body. diff --git a/addons/m_terrain/gui/mtools_transform_terrain_popup.tscn b/addons/m_terrain/gui/mtools_transform_terrain_popup.tscn deleted file mode 100644 index 14e792b..0000000 --- a/addons/m_terrain/gui/mtools_transform_terrain_popup.tscn +++ /dev/null @@ -1,129 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://c32yod36qfp5l"] - -[sub_resource type="GDScript" id="GDScript_siatt"] -script/source = "extends Panel -@export var confirm_transform: Button -func _ready(): - confirm_transform.pressed.connect(_on_button_pressed) - -func _on_button_pressed() -> void: - get_parent().hide() -" - -[node name="Popup" type="Popup"] -title = "Transform Terrain" -initial_position = 1 -size = Vector2i(200, 200) -visible = true -borderless = false -keep_title_visible = true - -[node name="TransformTerrainPopup" type="Panel" parent="." node_paths=PackedStringArray("confirm_transform")] -custom_minimum_size = Vector2(32, 32) -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -100.0 -offset_top = -100.0 -offset_right = 100.0 -offset_bottom = 100.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 0 -script = SubResource("GDScript_siatt") -confirm_transform = NodePath("") - -[node name="VBoxContainer" type="VBoxContainer" parent="TransformTerrainPopup"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -alignment = 1 - -[node name="Label" type="Label" parent="TransformTerrainPopup/VBoxContainer"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -text = "Offset" -horizontal_alignment = 1 - -[node name="HBoxContainer" type="HBoxContainer" parent="TransformTerrainPopup/VBoxContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -alignment = 1 - -[node name="LineEdit" type="LineEdit" parent="TransformTerrainPopup/VBoxContainer/HBoxContainer"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -placeholder_text = " X " -expand_to_text_length = true - -[node name="LineEdit2" type="LineEdit" parent="TransformTerrainPopup/VBoxContainer/HBoxContainer"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -placeholder_text = " Y " -expand_to_text_length = true - -[node name="LineEdit3" type="LineEdit" parent="TransformTerrainPopup/VBoxContainer/HBoxContainer"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -placeholder_text = " Z " -expand_to_text_length = true - -[node name="Label2" type="Label" parent="TransformTerrainPopup/VBoxContainer"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -text = "Scale" -horizontal_alignment = 1 - -[node name="HBoxContainer2" type="HBoxContainer" parent="TransformTerrainPopup/VBoxContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -alignment = 1 - -[node name="LineEdit" type="LineEdit" parent="TransformTerrainPopup/VBoxContainer/HBoxContainer2"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -placeholder_text = " X " -expand_to_text_length = true - -[node name="LineEdit2" type="LineEdit" parent="TransformTerrainPopup/VBoxContainer/HBoxContainer2"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -placeholder_text = " Y " -expand_to_text_length = true - -[node name="LineEdit3" type="LineEdit" parent="TransformTerrainPopup/VBoxContainer/HBoxContainer2"] -custom_minimum_size = Vector2(42.7188, 42.7188) -layout_mode = 2 -mouse_filter = 1 -theme_override_constants/minimum_character_width = 0 -placeholder_text = " Z " -expand_to_text_length = true - -[node name="MarginContainer" type="MarginContainer" parent="TransformTerrainPopup/VBoxContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -theme_override_constants/margin_top = 12 - -[node name="confirm_transform" type="Button" parent="TransformTerrainPopup/VBoxContainer"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -mouse_filter = 1 -text = "Transform!" diff --git a/addons/m_terrain/gui/paint_mode_instructions_popup.tscn b/addons/m_terrain/gui/paint_mode_instructions_popup.tscn deleted file mode 100644 index 0300e1a..0000000 --- a/addons/m_terrain/gui/paint_mode_instructions_popup.tscn +++ /dev/null @@ -1,80 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://ytqqrfb408u0"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_stqfj"] - -[sub_resource type="GDScript" id="GDScript_h52qr"] -script/source = "@tool -extends Window - -func _on_button_pressed(): - queue_free() - - -func load_tutorial(): - OS.shell_open(\"https://www.youtube.com/watch?v=0zEYzKEMWR8\") -" - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_q0632"] - -[node name="Window" type="Window"] -initial_position = 2 -size = Vector2i(400, 300) -theme = ExtResource("1_stqfj") -script = SubResource("GDScript_h52qr") - -[node name="PanelContainer" type="PanelContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"] -layout_mode = 2 - -[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="Panel" type="Panel" parent="PanelContainer/VBoxContainer/MarginContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -theme_override_styles/panel = SubResource("StyleBoxEmpty_q0632") - -[node name="Label" type="RichTextLabel" parent="PanelContainer/VBoxContainer/MarginContainer/Panel"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -text = "This MTerrain has no color layers or brushes yet. - -Please go to the inspector and add a brush layer. - -You will also need to use the mterrain image creator to create a shader uniform which you can then reference in your mterrain shader. - -For instructions on how to use mterrain color painting please watch the tutorial" -autowrap_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="Button" type="Button" parent="PanelContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Tutorial" - -[node name="Button2" type="Button" parent="PanelContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "OK" - -[connection signal="pressed" from="PanelContainer/VBoxContainer/HBoxContainer/Button" to="." method="load_tutorial"] -[connection signal="pressed" from="PanelContainer/VBoxContainer/HBoxContainer/Button2" to="." method="_on_button_pressed"] diff --git a/addons/m_terrain/gui/paint_panel.gd b/addons/m_terrain/gui/paint_panel.gd deleted file mode 100644 index 81792f4..0000000 --- a/addons/m_terrain/gui/paint_panel.gd +++ /dev/null @@ -1 +0,0 @@ -extends HBoxContainer diff --git a/addons/m_terrain/gui/paint_panel.tscn b/addons/m_terrain/gui/paint_panel.tscn deleted file mode 100644 index 857e5ff..0000000 --- a/addons/m_terrain/gui/paint_panel.tscn +++ /dev/null @@ -1,160 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://cesssdkp0wyi8"] - -[ext_resource type="Script" path="res://addons/m_terrain/gui/paint_panel_old.gd" id="1_udfkn"] -[ext_resource type="PackedScene" uid="uid://b6wfdaqojnwju" path="res://addons/m_terrain/gui/mtools_mask_list.tscn" id="2_o8i15"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_iouu7"] -bg_color = Color(0.117647, 0.180392, 0.537255, 1) - -[node name="paint" type="VBoxContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -script = ExtResource("1_udfkn") - -[node name="brush_size" type="HBoxContainer" parent="."] -custom_minimum_size = Vector2(250, 0) -layout_mode = 2 - -[node name="lable" type="Label" parent="brush_size"] -custom_minimum_size = Vector2(130, 0) -layout_mode = 2 -text = "brush size 50.0" -clip_text = true - -[node name="brush_slider" type="HSlider" parent="brush_size"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -min_value = 0.5 -max_value = 323.364 -step = 0.5 -value = 50.0 - -[node name="brush_type" type="CheckButton" parent="."] -layout_mode = 2 -text = "Height brush" - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="HBoxContainer"] -layout_mode = 2 -text = "Brush Masks " - -[node name="invert_btn" type="Button" parent="HBoxContainer"] -layout_mode = 2 -text = "Invert" - -[node name="Label2" type="Label" parent="HBoxContainer"] -layout_mode = 2 -theme_override_font_sizes/font_size = 12 -text = " Hot Keys:" - -[node name="Label3" type="Label" parent="HBoxContainer"] -layout_mode = 2 -theme_override_font_sizes/font_size = 12 -theme_override_styles/normal = SubResource("StyleBoxFlat_iouu7") -text = ", . k l ; middle_mouse_btn" - -[node name="HBoxContainer2" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Labelmask_cutt_off_label" type="Label" parent="HBoxContainer2"] -layout_mode = 2 -text = "Mask Cutoff: 0.5" -vertical_alignment = 1 - -[node name="mask_cutt_off_slider" type="HSlider" parent="HBoxContainer2"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 4 -max_value = 1.0 -step = 0.01 -value = 0.5 - -[node name="brush_masks" parent="." instance=ExtResource("2_o8i15")] -layout_mode = 2 - -[node name="grass_lable" type="Label" parent="."] -visible = false -layout_mode = 2 -text = "Hold Shift to revers" - -[node name="grass_add" type="CheckButton" parent="."] -visible = false -layout_mode = 2 -button_pressed = true -text = "Grass Add" - -[node name="layer_buttons" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="addBT" type="Button" parent="layer_buttons"] -layout_mode = 2 -text = "Add" - -[node name="addName" type="LineEdit" parent="layer_buttons"] -custom_minimum_size = Vector2(120, 0) -layout_mode = 2 - -[node name="mergeBT" type="Button" parent="layer_buttons"] -layout_mode = 2 -text = "Merge" - -[node name="visibiltyBT" type="Button" parent="layer_buttons"] -layout_mode = 2 -text = "visibility" - -[node name="removeBT" type="Button" parent="layer_buttons"] -layout_mode = 2 -text = "Remove" - -[node name="layer_note" type="Label" parent="."] -layout_mode = 2 -theme_override_font_sizes/font_size = 12 -text = "Note: By Changing the layer the undo data will lost" - -[node name="heightmap_layers" type="ItemList" parent="."] -custom_minimum_size = Vector2(0, 100) -layout_mode = 2 - -[node name="brush_list" type="OptionButton" parent="."] -layout_mode = 2 -selected = 0 -item_count = 5 -popup/item_0/text = "Raise" -popup/item_1/text = "To Height" -popup/item_1/id = 1 -popup/item_2/text = "Smooth" -popup/item_2/id = 2 -popup/item_3/text = "Remove Layer" -popup/item_3/id = 3 -popup/item_4/text = "Hole" -popup/item_4/id = 4 - -[node name="color_brushe_scroll" type="ScrollContainer" parent="."] -visible = false -layout_mode = 2 -size_flags_vertical = 3 - -[node name="color_brushe_root" type="VBoxContainer" parent="color_brushe_scroll"] -visible = false -layout_mode = 2 -size_flags_horizontal = 3 - -[connection signal="value_changed" from="brush_size/brush_slider" to="." method="_on_brush_slider_value_changed"] -[connection signal="toggled" from="brush_type" to="." method="_on_brush_type_toggled"] -[connection signal="pressed" from="HBoxContainer/invert_btn" to="brush_masks" method="invert_selected_image"] -[connection signal="value_changed" from="HBoxContainer2/mask_cutt_off_slider" to="." method="set_mask_cutoff_value"] -[connection signal="toggled" from="grass_add" to="." method="_on_grass_add_toggled"] -[connection signal="pressed" from="layer_buttons/addBT" to="." method="_on_add_bt_pressed"] -[connection signal="gui_input" from="layer_buttons/addName" to="." method="_on_add_name_gui_input"] -[connection signal="pressed" from="layer_buttons/mergeBT" to="." method="_on_merge_bt_pressed"] -[connection signal="pressed" from="layer_buttons/visibiltyBT" to="." method="_on_visibilty_bt_pressed"] -[connection signal="pressed" from="layer_buttons/removeBT" to="." method="_on_remove_bt_pressed"] -[connection signal="item_selected" from="heightmap_layers" to="." method="_on_heightmap_layer_item_selected"] -[connection signal="item_selected" from="brush_list" to="." method="_on_brush_list_item_selected"] diff --git a/addons/m_terrain/gui/styles/button_stylebox.tres b/addons/m_terrain/gui/styles/button_stylebox.tres deleted file mode 100644 index e6f1921..0000000 --- a/addons/m_terrain/gui/styles/button_stylebox.tres +++ /dev/null @@ -1,12 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://b6h5l26dxm8gu"] - -[resource] -content_margin_left = 12.0 -content_margin_top = 5.0 -content_margin_right = 12.0 -content_margin_bottom = 5.0 -bg_color = Color(0, 0, 0, 0.203922) -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 diff --git a/addons/m_terrain/gui/styles/button_stylebox_icon_only.tres b/addons/m_terrain/gui/styles/button_stylebox_icon_only.tres deleted file mode 100644 index 6eebbcc..0000000 --- a/addons/m_terrain/gui/styles/button_stylebox_icon_only.tres +++ /dev/null @@ -1,8 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://c3g6qjhhpkliw"] - -[resource] -bg_color = Color(0, 0, 0, 0.203922) -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 diff --git a/addons/m_terrain/gui/styles/button_stylebox_icon_only_hover.tres b/addons/m_terrain/gui/styles/button_stylebox_icon_only_hover.tres deleted file mode 100644 index 5483207..0000000 --- a/addons/m_terrain/gui/styles/button_stylebox_icon_only_hover.tres +++ /dev/null @@ -1,12 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://bwtrldgojexog"] - -[resource] -content_margin_left = 3.0 -content_margin_top = 3.0 -content_margin_right = 3.0 -content_margin_bottom = 3.0 -bg_color = Color(0, 0, 0, 0.203922) -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 diff --git a/addons/m_terrain/gui/styles/mterrain_gui_theme.tres b/addons/m_terrain/gui/styles/mterrain_gui_theme.tres deleted file mode 100644 index 50ca4c6..0000000 --- a/addons/m_terrain/gui/styles/mterrain_gui_theme.tres +++ /dev/null @@ -1,35 +0,0 @@ -[gd_resource type="Theme" load_steps=10 format=3 uid="uid://b3bd1lceed8ec"] - -[ext_resource type="StyleBox" uid="uid://b1hcaoigsih7c" path="res://addons/m_terrain/gui/styles/popup_panel_stylebox.tres" id="1_pvcuc"] -[ext_resource type="StyleBox" uid="uid://b6h5l26dxm8gu" path="res://addons/m_terrain/gui/styles/button_stylebox.tres" id="1_set7o"] -[ext_resource type="Texture2D" uid="uid://bxeg3w2i6m1dd" path="res://addons/m_terrain/icons/slider_grabber.svg" id="3_0xpim"] -[ext_resource type="Texture2D" uid="uid://b0m46wjnrfder" path="res://addons/m_terrain/icons/slider_grabber_highlight_icon.svg" id="4_wqnvw"] -[ext_resource type="StyleBox" uid="uid://boeh2uxqt0aso" path="res://addons/m_terrain/gui/styles/sider_front_stylebox.tres" id="5_uxsd7"] -[ext_resource type="StyleBox" uid="uid://ppgo6r7jw03e" path="res://addons/m_terrain/gui/styles/sider_highlight_stylebox.tres" id="6_uducl"] -[ext_resource type="StyleBox" uid="uid://bwtrldgojexog" path="res://addons/m_terrain/gui/styles/button_stylebox_icon_only_hover.tres" id="7_b6jf6"] -[ext_resource type="StyleBox" uid="uid://c3g6qjhhpkliw" path="res://addons/m_terrain/gui/styles/button_stylebox_icon_only.tres" id="7_wkvrx"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_2e40r"] - -[resource] -default_font_size = 16 -Button/styles/hover = null -Button/styles/normal = ExtResource("1_set7o") -Button/styles/pressed = ExtResource("1_set7o") -CheckBox/styles/normal = ExtResource("1_set7o") -CheckBox/styles/pressed = SubResource("StyleBoxEmpty_2e40r") -ItemList/styles/panel = ExtResource("1_pvcuc") -Panel/styles/panel = ExtResource("1_pvcuc") -PanelContainer/styles/panel = ExtResource("1_pvcuc") -TabContainer/styles/panel = ExtResource("1_pvcuc") -TabContainer/styles/tab_selected = ExtResource("1_pvcuc") -TabContainer/styles/tab_unselected = null -VSlider/icons/grabber = ExtResource("3_0xpim") -VSlider/icons/grabber_highlight = ExtResource("4_wqnvw") -VSlider/styles/grabber_area = ExtResource("5_uxsd7") -VSlider/styles/grabber_area_highlight = ExtResource("6_uducl") -VSlider/styles/slider = ExtResource("5_uxsd7") -button_icon_only/base_type = &"Button" -button_icon_only/styles/hover = ExtResource("7_b6jf6") -button_icon_only/styles/normal = ExtResource("7_wkvrx") -button_icon_only/styles/pressed = SubResource("StyleBoxEmpty_2e40r") diff --git a/addons/m_terrain/gui/styles/popup_panel_stylebox.tres b/addons/m_terrain/gui/styles/popup_panel_stylebox.tres deleted file mode 100644 index 83a7f92..0000000 --- a/addons/m_terrain/gui/styles/popup_panel_stylebox.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://b1hcaoigsih7c"] - -[resource] -bg_color = Color(0.21, 0.24, 0.29, 1) -corner_radius_top_left = 15 -corner_radius_top_right = 15 diff --git a/addons/m_terrain/gui/styles/sider_back_stylebox.tres b/addons/m_terrain/gui/styles/sider_back_stylebox.tres deleted file mode 100644 index 2bb7c3f..0000000 --- a/addons/m_terrain/gui/styles/sider_back_stylebox.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://cij0yplibynjc"] - -[resource] -bg_color = Color(0.356942, 0.396185, 0.46897, 1) -expand_margin_left = 12.0 -expand_margin_right = 12.0 diff --git a/addons/m_terrain/gui/styles/sider_front_stylebox.tres b/addons/m_terrain/gui/styles/sider_front_stylebox.tres deleted file mode 100644 index 3b2b377..0000000 --- a/addons/m_terrain/gui/styles/sider_front_stylebox.tres +++ /dev/null @@ -1,10 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://boeh2uxqt0aso"] - -[resource] -bg_color = Color(0.405714, 0.447509, 0.52497, 1) -corner_radius_top_left = 4 -corner_radius_top_right = 4 -corner_radius_bottom_right = 4 -corner_radius_bottom_left = 4 -expand_margin_left = 12.0 -expand_margin_right = 12.0 diff --git a/addons/m_terrain/gui/styles/sider_highlight_stylebox.tres b/addons/m_terrain/gui/styles/sider_highlight_stylebox.tres deleted file mode 100644 index ccb19e0..0000000 --- a/addons/m_terrain/gui/styles/sider_highlight_stylebox.tres +++ /dev/null @@ -1,4 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://ppgo6r7jw03e"] - -[resource] -bg_color = Color(0.704788, 0.737992, 0.79912, 1) diff --git a/addons/m_terrain/gui/styles/stylebox_selected.tres b/addons/m_terrain/gui/styles/stylebox_selected.tres deleted file mode 100644 index 399d93d..0000000 --- a/addons/m_terrain/gui/styles/stylebox_selected.tres +++ /dev/null @@ -1,9 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://xtya3snybrwa"] - -[resource] -draw_center = false -border_width_left = 2 -border_width_top = 2 -border_width_right = 2 -border_width_bottom = 2 -border_color = Color(0.312375, 0.675219, 0.689798, 1) diff --git a/addons/m_terrain/gui/styles/terrain_info_label_stylebox.tres b/addons/m_terrain/gui/styles/terrain_info_label_stylebox.tres deleted file mode 100644 index d96defd..0000000 --- a/addons/m_terrain/gui/styles/terrain_info_label_stylebox.tres +++ /dev/null @@ -1,16 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://cjys1hccuc4wx"] - -[resource] -content_margin_left = 7.0 -content_margin_top = 2.0 -content_margin_right = 10.0 -bg_color = Color(0.180392, 0.180392, 0.180392, 1) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(1, 1, 1, 1) -corner_radius_top_left = 4 -corner_radius_top_right = 4 -corner_radius_bottom_right = 4 -corner_radius_bottom_left = 4 diff --git a/addons/m_terrain/gui/terrain_info.gd b/addons/m_terrain/gui/terrain_info.gd deleted file mode 100644 index 3602923..0000000 --- a/addons/m_terrain/gui/terrain_info.gd +++ /dev/null @@ -1,120 +0,0 @@ -@tool -extends Window - -signal keymap_changed -signal restore_default_keymap_requested - -@onready var Terror:=$base/TabContainer/Terrain/VBoxContainer/Error -@onready var Rwarning:=$base/TabContainer/Region/VBoxContainer/Warning -@onready var tsizeg:=$base/TabContainer/Terrain/VBoxContainer/tsizeg -@onready var tsizem:=$base/TabContainer/Terrain/VBoxContainer/tsizem -@onready var takm:=$base/TabContainer/Terrain/VBoxContainer/takm -@onready var tsizepx:=$base/TabContainer/Terrain/VBoxContainer/tsizepx -@onready var tregioncount:=$base/TabContainer/Terrain/VBoxContainer/tregioncount -@onready var tregioncountX:=$base/TabContainer/Terrain/VBoxContainer/tregioncountX -@onready var tregioncountY:=$base/TabContainer/Terrain/VBoxContainer/tregioncountZ - -@onready var rsizem:=$base/TabContainer/Region/VBoxContainer/rsizem -@onready var rsizepixel:=$base/TabContainer/Region/VBoxContainer/rsizepixel - -@onready var base_unit:=$"base/TabContainer/Base Size/base_unit" - -@onready var info:=$base/TabContainer/info/info - -@onready var save_config = find_child("Manage Images") - -var version:String - -var terrain:MTerrain=null -var region_meter_size:int=0 -var terrain_area:int -var region_pixel_size:int=0 -var region_grid_size:Vector2i -var region_count:int -var terrain_meter_size:Vector2 -var terrain_pixel_size:Vector2 - -var mtools - -func generate_info(_t:MTerrain,_version:String, keyboard_actions): - save_config.init_save_config(_t) - terrain = _t - version = _version - if not _t: - Terror.text = "No Active Terrain" - Terror.visible = true - return - var errstr:String="" - if terrain.terrain_size.x%terrain.region_size!=0 or terrain.terrain_size.x%terrain.region_size!=0: - errstr="Terrain size in x or y direction must be divisible by region size\nfor example in this case as your region size %s your terain size can be (%d,%d) or (%d,%d) or (%d,%d)\nThese are in grid unit which currently is %d meter" - var ex1:=Vector2i(terrain.region_size*1,terrain.region_size*1) - var ex2:=Vector2i(terrain.region_size*2,terrain.region_size*2) - var ex3:=Vector2i(terrain.region_size*1,terrain.region_size*2) - errstr = errstr % [terrain.region_size,ex1.x,ex1.y,ex2.x,ex2.y,ex3.x,ex3.y,terrain.get_base_size()] - if not errstr.is_empty(): - errstr +="\n\nChange these and close and reopen this window" - Terror.text = errstr - Terror.visible = true - region_meter_size = (terrain.get_base_size()*terrain.region_size) - region_pixel_size = (region_meter_size/terrain.get_h_scale()) + 1 - terrain_meter_size = terrain.terrain_size*terrain.get_base_size() - terrain_area = terrain_meter_size.x * terrain_meter_size.x - terrain_pixel_size = (terrain_meter_size/terrain.get_h_scale()) + Vector2(1,1) - region_grid_size = (terrain.terrain_size) / terrain.region_size - region_count = region_grid_size.x * region_grid_size.y - var warnstr:String="" - warnstr = "Images in data directory should be width=height=%d one common edge pixel between regions will be created at load time."%(region_pixel_size-1) - Rwarning.text = warnstr - tsizeg.text += " %d X %d" % [terrain.terrain_size.x,terrain.terrain_size.y] - tsizem.text += " %dm X %dm" % [terrain_meter_size.x,terrain_meter_size.y] - takm.text += " %10.3f km2" % [float(terrain_area)/1000000.0] - tsizepx.text += " %d X %d" % [terrain_pixel_size.x,terrain_pixel_size.y] - tregioncount.text += " %d" % [region_count] - tregioncountX.text += " %d" % [region_grid_size.x] - tregioncountY.text += " %d" % [region_grid_size.y] - rsizem.text += " %dm" % [region_meter_size] - rsizepixel.text += " %d" % [region_pixel_size] - var vc = (terrain.get_base_size()/terrain.get_h_scale())+1 - vc *= vc - base_unit.text = base_unit.text % [terrain.get_base_size(),vc] - info.text = info.text % version - create_keymapping_interface(keyboard_actions) - -func create_keymapping_interface(keyboard_actions): - var mterrain_actions_list = find_child("mterrain_action_list") - for child in mterrain_actions_list.get_children(): - child.queue_free() - mterrain_actions_list.remove_child(child) - var mpath_actions_list = find_child("mpath_action_list") - for child in mpath_actions_list .get_children(): - child.queue_free() - mterrain_actions_list.remove_child(child) - var restore_default_keymap = find_child("restore_default_keymap") - restore_default_keymap.pressed.connect( func(): restore_default_keymap_requested.emit() ) - for action in keyboard_actions: - var item = preload("res://addons/m_terrain/gui/mtools_keyboard_shortcut_item.tscn").instantiate() - if action.name.begins_with("mterrain_"): - mterrain_actions_list.add_child(item) - item.label.text = action.name.substr(9) - item.name = action.name - elif action.name.begins_with("mpath_"): - mpath_actions_list.add_child(item) - item.label.text = action.name.substr(6) - item.name = action.name - item.value.text = OS.get_keycode_string(action.keycode) - item.keymap_changed.connect( func(who, keycode, ctrl,alt,shift): keymap_changed.emit(who, keycode,ctrl,alt,shift)) - -func _on_info_meta_clicked(meta): - OS.shell_open(meta) - -func _on_close_requested(): - queue_free() - -func _on_delete_uniform_pressed(): - var confirm_label = find_child("delete_confirm_label") - if confirm_label.visible: - mtools.remove_image(mtools.get_active_mterrain(), find_child("data_name_option").text) - save_config.init_save_config(terrain) - confirm_label.visible = false - else: - confirm_label.visible = true diff --git a/addons/m_terrain/gui/terrain_info.tscn b/addons/m_terrain/gui/terrain_info.tscn deleted file mode 100644 index d6cccff..0000000 --- a/addons/m_terrain/gui/terrain_info.tscn +++ /dev/null @@ -1,412 +0,0 @@ -[gd_scene load_steps=13 format=3 uid="uid://bcvync03h4h35"] - -[ext_resource type="Theme" uid="uid://b3bd1lceed8ec" path="res://addons/m_terrain/gui/styles/mterrain_gui_theme.tres" id="1_qudvd"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/terrain_info.gd" id="1_wd31j"] -[ext_resource type="Script" path="res://addons/m_terrain/gui/Save config.gd" id="2_iihim"] -[ext_resource type="StyleBox" uid="uid://cjys1hccuc4wx" path="res://addons/m_terrain/gui/styles/terrain_info_label_stylebox.tres" id="2_mc1wb"] -[ext_resource type="PackedScene" uid="uid://c2pjojed3ox4q" path="res://addons/m_terrain/gui/gui_part/data_compress_option.tscn" id="3_41fbb"] -[ext_resource type="PackedScene" uid="uid://bt4wolcb7b55e" path="res://addons/m_terrain/gui/gui_part/file_compress.tscn" id="4_cuomh"] -[ext_resource type="Texture2D" uid="uid://t8tdan3853oy" path="res://addons/m_terrain/icons/icon_close.svg" id="4_l5kjq"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_283b4"] -content_margin_left = 5.0 - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_vv3ku"] -content_margin_left = 5.0 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4xytc"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xq60s"] -content_margin_left = 5.0 - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_g3do0"] -content_margin_left = 5.0 - -[node name="Terrain_info" type="Window"] -title = "M Terrain Info" -initial_position = 1 -size = Vector2i(520, 500) -theme = ExtResource("1_qudvd") -script = ExtResource("1_wd31j") - -[node name="base" type="Control" parent="."] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="TabContainer" type="TabContainer" parent="base"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -current_tab = 1 - -[node name="Shortcuts" type="Panel" parent="base/TabContainer"] -visible = false -layout_mode = 2 - -[node name="MarginContainer" type="MarginContainer" parent="base/TabContainer/Shortcuts"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="ScrollContainer" type="ScrollContainer" parent="base/TabContainer/Shortcuts/MarginContainer"] -layout_mode = 2 - -[node name="vbox" type="VBoxContainer" parent="base/TabContainer/Shortcuts/MarginContainer/ScrollContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Label" type="Label" parent="base/TabContainer/Shortcuts/MarginContainer/ScrollContainer/vbox"] -layout_mode = 2 -text = "MTerrain Shortcuts" -horizontal_alignment = 1 - -[node name="mterrain_action_list" type="VBoxContainer" parent="base/TabContainer/Shortcuts/MarginContainer/ScrollContainer/vbox"] -layout_mode = 2 - -[node name="Label2" type="Label" parent="base/TabContainer/Shortcuts/MarginContainer/ScrollContainer/vbox"] -layout_mode = 2 -text = "MPath Shortcuts" -horizontal_alignment = 1 - -[node name="mpath_action_list" type="VBoxContainer" parent="base/TabContainer/Shortcuts/MarginContainer/ScrollContainer/vbox"] -layout_mode = 2 - -[node name="restore_default_keymap" type="Button" parent="base/TabContainer/Shortcuts/MarginContainer/ScrollContainer/vbox"] -layout_mode = 2 -text = "Restore Defaults" - -[node name="Manage Images" type="TabBar" parent="base/TabContainer"] -layout_mode = 2 -script = ExtResource("2_iihim") - -[node name="scroll" type="ScrollContainer" parent="base/TabContainer/Manage Images"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="base/TabContainer/Manage Images/scroll"] -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -visible = false -layout_mode = 2 - -[node name="hlable" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 6 -theme_override_colors/font_color = Color(1, 1, 0.219608, 1) -theme_override_font_sizes/font_size = 22 -theme_override_styles/normal = SubResource("StyleBoxEmpty_283b4") -text = "Heightmap" - -[node name="HSeparator2" type="HSeparator" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="HSeparator5" type="HSeparator" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -visible = false -layout_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/HBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_vv3ku") -text = "Compress_qtq" - -[node name="compress_qtq" type="CheckBox" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/HBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxFlat_4xytc") -button_pressed = true - -[node name="HBoxContainer2" type="HBoxContainer" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/HBoxContainer2"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_xq60s") -text = "Compression accuracy" - -[node name="LineEdit" type="LineEdit" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/HBoxContainer2"] -layout_mode = 2 -text = "0.02" - -[node name="hfilecomrpess" type="HBoxContainer" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hfilecomrpess"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_g3do0") -text = "File compress" - -[node name="file_compress" type="OptionButton" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hfilecomrpess"] -layout_mode = 2 -item_count = 5 -selected = 0 -popup/item_0/text = "FILE_COMPRESSION_NONE" -popup/item_0/id = 0 -popup/item_1/text = "FILE_COMPRESSION_FASTLZ" -popup/item_1/id = 1 -popup/item_2/text = "FILE_COMPRESSION_DEFLATE" -popup/item_2/id = 2 -popup/item_3/text = "FILE_COMPRESSION_ZSTD" -popup/item_3/id = 3 -popup/item_4/text = "FILE_COMPRESSION_GZIP" -popup/item_4/id = 4 - -[node name="HSeparator3" type="HSeparator" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="Dlable2" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 6 -theme_override_colors/font_color = Color(1, 1, 0.219608, 1) -theme_override_font_sizes/font_size = 22 -theme_override_styles/normal = SubResource("StyleBoxEmpty_283b4") -text = "Data" - -[node name="HSeparator4" type="HSeparator" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="hb" type="HBoxContainer" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_g3do0") -text = "Name" - -[node name="data_name_option" type="OptionButton" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb"] -layout_mode = 2 - -[node name="delete_confirm_label" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb"] -visible = false -layout_mode = 2 -text = "Click again to confirm delete:" - -[node name="delete_uniform" type="Button" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -tooltip_text = "Delete selected uniform" -theme_type_variation = &"button_icon_only" -icon = ExtResource("4_l5kjq") -expand_icon = true - -[node name="hb2" type="HBoxContainer" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb2"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_g3do0") -text = "Compress" - -[node name="data_compress_option" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb2" instance=ExtResource("3_41fbb")] -layout_mode = 2 - -[node name="hb3" type="HBoxContainer" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb3"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_g3do0") -text = "File Compress" - -[node name="file_compress" parent="base/TabContainer/Manage Images/scroll/VBoxContainer/hb3" instance=ExtResource("4_cuomh")] -layout_mode = 2 - -[node name="HSeparator6" type="HSeparator" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 - -[node name="warn" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.690196, 0.372549, 1) -theme_override_styles/normal = ExtResource("2_mc1wb") -text = "Please note that applying a lossy compression might be irreversible." -autowrap_mode = 2 - -[node name="Error" type="Label" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.172549, 0.219608, 1) -theme_override_font_sizes/font_size = 11 -theme_override_styles/normal = ExtResource("2_mc1wb") -text = "Error: No Active Terrain" -autowrap_mode = 2 - -[node name="force_apply_all" type="CheckBox" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 -text = "Force re-apply to all resources" - -[node name="apply" type="Button" parent="base/TabContainer/Manage Images/scroll/VBoxContainer"] -layout_mode = 2 -text = "Apply Changes" - -[node name="Region" type="TabBar" parent="base/TabContainer"] -visible = false -layout_mode = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="base/TabContainer/Region"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="rsizem" type="RichTextLabel" parent="base/TabContainer/Region/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Region size in meter:[/color]" -fit_content = true - -[node name="rsizepixel" type="RichTextLabel" parent="base/TabContainer/Region/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Region size in pixel:[/color]" -fit_content = true - -[node name="Warning" type="Label" parent="base/TabContainer/Region/VBoxContainer"] -layout_mode = 2 -theme_override_colors/font_color = Color(1, 1, 0.4, 1) -theme_override_styles/normal = ExtResource("2_mc1wb") -text = "Please note: No Active TerrainPlease note: No Active TerrainPlease note: No Active Terrain" -autowrap_mode = 2 - -[node name="note" type="Label" parent="base/TabContainer/Region/VBoxContainer"] -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.729412, 0, 1) -theme_override_styles/normal = ExtResource("2_mc1wb") -text = "In case you change region size after initializing terrain data you should reimport heightmap data and adjust your heightmap data to region pixel " -autowrap_mode = 2 - -[node name="Terrain" type="TabBar" parent="base/TabContainer"] -visible = false -layout_mode = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="base/TabContainer/Terrain"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="Error" type="Label" parent="base/TabContainer/Terrain/VBoxContainer"] -visible = false -layout_mode = 2 -theme_override_colors/font_color = Color(1, 0.172549, 0.219608, 1) -theme_override_styles/normal = ExtResource("2_mc1wb") -text = "Error: No Active Terrain" -autowrap_mode = 2 - -[node name="tsizeg" type="RichTextLabel" parent="base/TabContainer/Terrain/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Terrain Size in Grid unit: [/color]" -fit_content = true - -[node name="tsizem" type="RichTextLabel" parent="base/TabContainer/Terrain/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Terrain size in meter: [/color]" -fit_content = true - -[node name="takm" type="RichTextLabel" parent="base/TabContainer/Terrain/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Terrain area square km: [/color]" -fit_content = true - -[node name="tsizepx" type="RichTextLabel" parent="base/TabContainer/Terrain/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Terrain pixel size:[/color]" -fit_content = true - -[node name="tregioncount" type="RichTextLabel" parent="base/TabContainer/Terrain/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Terrain region count:[/color]" -fit_content = true - -[node name="tregioncountX" type="RichTextLabel" parent="base/TabContainer/Terrain/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Terrain region count in X direction:[/color]" -fit_content = true - -[node name="tregioncountZ" type="RichTextLabel" parent="base/TabContainer/Terrain/VBoxContainer"] -layout_mode = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[color=green]Terrain region count in Z direction:[/color]" -fit_content = true -autowrap_mode = 2 - -[node name="Base Size" type="TabBar" parent="base/TabContainer"] -visible = false -layout_mode = 2 - -[node name="base_unit" type="Label" parent="base/TabContainer/Base Size"] -layout_mode = 1 -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 29.0 -grow_horizontal = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -text = "Smallest grid unit - -size: %d meter -vertex count: %d" - -[node name="info" type="TabBar" parent="base/TabContainer"] -visible = false -layout_mode = 2 - -[node name="info" type="RichTextLabel" parent="base/TabContainer/info"] -layout_mode = 1 -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 29.0 -grow_horizontal = 2 -theme_override_styles/normal = ExtResource("2_mc1wb") -bbcode_enabled = true -text = "[center]MTerrain %s - -For more information read [url=https://github.com/mohsenph69/Godot-MTerrain-plugin/wiki]wiki[/url] page -on [url=https://github.com/mohsenph69/Godot-MTerrain-plugin]Github[/url] -[/center]" -fit_content = true - -[connection signal="close_requested" from="." to="." method="_on_close_requested"] -[connection signal="item_selected" from="base/TabContainer/Manage Images/scroll/VBoxContainer/hb/data_name_option" to="base/TabContainer/Manage Images" method="_on_data_name_option_item_selected"] -[connection signal="pressed" from="base/TabContainer/Manage Images/scroll/VBoxContainer/hb/delete_uniform" to="." method="_on_delete_uniform_pressed"] -[connection signal="item_selected" from="base/TabContainer/Manage Images/scroll/VBoxContainer/hb2/data_compress_option" to="base/TabContainer/Manage Images" method="_on_data_compress_option_item_selected"] -[connection signal="item_selected" from="base/TabContainer/Manage Images/scroll/VBoxContainer/hb3/file_compress" to="base/TabContainer/Manage Images" method="_on_file_compress_item_selected"] -[connection signal="button_up" from="base/TabContainer/Manage Images/scroll/VBoxContainer/apply" to="base/TabContainer/Manage Images" method="_on_apply_button_up"] -[connection signal="meta_clicked" from="base/TabContainer/info/info" to="." method="_on_info_meta_clicked"] diff --git a/addons/m_terrain/gui/tsnap.tscn b/addons/m_terrain/gui/tsnap.tscn deleted file mode 100644 index 1955555..0000000 --- a/addons/m_terrain/gui/tsnap.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bnlxve4lvi4wb"] - -[ext_resource type="Texture2D" uid="uid://dl46tixprq2ro" path="res://addons/m_terrain/icons/tsnap_icon.png" id="1_jxji4"] -[ext_resource type="Texture2D" uid="uid://dow4horhd3x6v" path="res://addons/m_terrain/icons/tsnap_icon_pressed.png" id="2_yyg7b"] - -[node name="tsnap" type="TextureButton"] -offset_right = 40.0 -offset_bottom = 40.0 -texture_normal = ExtResource("1_jxji4") -texture_pressed = ExtResource("2_yyg7b") diff --git a/addons/m_terrain/icons/M-terrain_icon.png b/addons/m_terrain/icons/M-terrain_icon.png deleted file mode 100644 index aed05f4..0000000 Binary files a/addons/m_terrain/icons/M-terrain_icon.png and /dev/null differ diff --git a/addons/m_terrain/icons/M-terrain_icon.png.import b/addons/m_terrain/icons/M-terrain_icon.png.import deleted file mode 100644 index 337f2f9..0000000 --- a/addons/m_terrain/icons/M-terrain_icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cqh311apccvi3" -path="res://.godot/imported/M-terrain_icon.png-f2e09725d1b891d3a94829e81fc6b2c1.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/M-terrain_icon.png" -dest_files=["res://.godot/imported/M-terrain_icon.png-f2e09725d1b891d3a94829e81fc6b2c1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/MCurve.svg b/addons/m_terrain/icons/MCurve.svg deleted file mode 100644 index 0d2cc63..0000000 --- a/addons/m_terrain/icons/MCurve.svg +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - diff --git a/addons/m_terrain/icons/MCurve.svg.import b/addons/m_terrain/icons/MCurve.svg.import deleted file mode 100644 index 73d3e73..0000000 --- a/addons/m_terrain/icons/MCurve.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bxvgtqkrlo0rb" -path="res://.godot/imported/MCurve.svg-6f26c51826846fc7bc39dd58fa5c40dc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MCurve.svg" -dest_files=["res://.godot/imported/MCurve.svg-6f26c51826846fc7bc39dd58fa5c40dc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/MCurveMesh.svg b/addons/m_terrain/icons/MCurveMesh.svg deleted file mode 100644 index aaf8c38..0000000 --- a/addons/m_terrain/icons/MCurveMesh.svg +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/MCurveMesh.svg.import b/addons/m_terrain/icons/MCurveMesh.svg.import deleted file mode 100644 index 22165b1..0000000 --- a/addons/m_terrain/icons/MCurveMesh.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://daq4pwgpj56qq" -path="res://.godot/imported/MCurveMesh.svg-280f382b644e3514080bf343dda9b4e3.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MCurveMesh.svg" -dest_files=["res://.godot/imported/MCurveMesh.svg-280f382b644e3514080bf343dda9b4e3.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/MIntersection.svg b/addons/m_terrain/icons/MIntersection.svg deleted file mode 100644 index fda2643..0000000 --- a/addons/m_terrain/icons/MIntersection.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - diff --git a/addons/m_terrain/icons/MIntersection.svg.import b/addons/m_terrain/icons/MIntersection.svg.import deleted file mode 100644 index 0931b85..0000000 --- a/addons/m_terrain/icons/MIntersection.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://0xbn4pydp1uw" -path="res://.godot/imported/MIntersection.svg-e6fd1a4b5802f101afb5aa3697dac3a6.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MIntersection.svg" -dest_files=["res://.godot/imported/MIntersection.svg-e6fd1a4b5802f101afb5aa3697dac3a6.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/MMeshLod.svg b/addons/m_terrain/icons/MMeshLod.svg deleted file mode 100644 index 2e8952d..0000000 --- a/addons/m_terrain/icons/MMeshLod.svg +++ /dev/null @@ -1,36 +0,0 @@ - - diff --git a/addons/m_terrain/icons/MMeshLod.svg.import b/addons/m_terrain/icons/MMeshLod.svg.import deleted file mode 100644 index b7f059e..0000000 --- a/addons/m_terrain/icons/MMeshLod.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d11jov5wo0e14" -path="res://.godot/imported/MMeshLod.svg-b1a715d884f0d4baa20521fe4d9a7067.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MMeshLod.svg" -dest_files=["res://.godot/imported/MMeshLod.svg-b1a715d884f0d4baa20521fe4d9a7067.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/MNavigationRegion3D.png b/addons/m_terrain/icons/MNavigationRegion3D.png deleted file mode 100644 index 42157ac..0000000 Binary files a/addons/m_terrain/icons/MNavigationRegion3D.png and /dev/null differ diff --git a/addons/m_terrain/icons/MNavigationRegion3D.png.import b/addons/m_terrain/icons/MNavigationRegion3D.png.import deleted file mode 100644 index 2c35491..0000000 --- a/addons/m_terrain/icons/MNavigationRegion3D.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://piy6jiwu28vi" -path="res://.godot/imported/MNavigationRegion3D.png-1b7ea227137c1b5422cbad606885d6e1.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MNavigationRegion3D.png" -dest_files=["res://.godot/imported/MNavigationRegion3D.png-1b7ea227137c1b5422cbad606885d6e1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/MOctMesh.svg b/addons/m_terrain/icons/MOctMesh.svg deleted file mode 100644 index d45b725..0000000 --- a/addons/m_terrain/icons/MOctMesh.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/MOctMesh.svg.import b/addons/m_terrain/icons/MOctMesh.svg.import deleted file mode 100644 index d3a6484..0000000 --- a/addons/m_terrain/icons/MOctMesh.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c41xjqe630jml" -path="res://.godot/imported/MOctMesh.svg-6c645e2ef44f1dd7d9f37a7dc12056b8.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MOctMesh.svg" -dest_files=["res://.godot/imported/MOctMesh.svg-6c645e2ef44f1dd7d9f37a7dc12056b8.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/MOctree.svg b/addons/m_terrain/icons/MOctree.svg deleted file mode 100644 index c349672..0000000 --- a/addons/m_terrain/icons/MOctree.svg +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/MOctree.svg.import b/addons/m_terrain/icons/MOctree.svg.import deleted file mode 100644 index fb33610..0000000 --- a/addons/m_terrain/icons/MOctree.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cwc46klnknbkx" -path="res://.godot/imported/MOctree.svg-35b9165c170786a3b9b40f8572d27ba9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MOctree.svg" -dest_files=["res://.godot/imported/MOctree.svg-35b9165c170786a3b9b40f8572d27ba9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/MPath.svg b/addons/m_terrain/icons/MPath.svg deleted file mode 100644 index bf8f997..0000000 --- a/addons/m_terrain/icons/MPath.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - diff --git a/addons/m_terrain/icons/MPath.svg.import b/addons/m_terrain/icons/MPath.svg.import deleted file mode 100644 index 34389da..0000000 --- a/addons/m_terrain/icons/MPath.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cbl5d43yc6te0" -path="res://.godot/imported/MPath.svg-18f9e405115f5722d1c5830200273c21.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/MPath.svg" -dest_files=["res://.godot/imported/MPath.svg-18f9e405115f5722d1c5830200273c21.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/brush.png b/addons/m_terrain/icons/brush.png deleted file mode 100644 index 4ba6bff..0000000 Binary files a/addons/m_terrain/icons/brush.png and /dev/null differ diff --git a/addons/m_terrain/icons/brush.png.import b/addons/m_terrain/icons/brush.png.import deleted file mode 100644 index 3daa78c..0000000 --- a/addons/m_terrain/icons/brush.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b5cmhvvnwshvc" -path="res://.godot/imported/brush.png-6aba610ae344611474bfa9a9d874be2c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/brush.png" -dest_files=["res://.godot/imported/brush.png-6aba610ae344611474bfa9a9d874be2c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/brush_icon.png b/addons/m_terrain/icons/brush_icon.png deleted file mode 100644 index 39a2d97..0000000 Binary files a/addons/m_terrain/icons/brush_icon.png and /dev/null differ diff --git a/addons/m_terrain/icons/brush_icon.png.import b/addons/m_terrain/icons/brush_icon.png.import deleted file mode 100644 index cadee0d..0000000 --- a/addons/m_terrain/icons/brush_icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c08s0xlu8tted" -path="res://.godot/imported/brush_icon.png-c4cc34619fca37f96dc82cf66b3b7435.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/brush_icon.png" -dest_files=["res://.godot/imported/brush_icon.png-c4cc34619fca37f96dc82cf66b3b7435.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/brush_icon_hole.svg b/addons/m_terrain/icons/brush_icon_hole.svg deleted file mode 100644 index f33740f..0000000 --- a/addons/m_terrain/icons/brush_icon_hole.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/brush_icon_hole.svg.import b/addons/m_terrain/icons/brush_icon_hole.svg.import deleted file mode 100644 index af1fbf3..0000000 --- a/addons/m_terrain/icons/brush_icon_hole.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://buiuytfb4jvss" -path="res://.godot/imported/brush_icon_hole.svg-da0c0c66eb715324c938425f9a907c30.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/brush_icon_hole.svg" -dest_files=["res://.godot/imported/brush_icon_hole.svg-da0c0c66eb715324c938425f9a907c30.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/brush_icon_raise.svg b/addons/m_terrain/icons/brush_icon_raise.svg deleted file mode 100644 index e9a8bc0..0000000 --- a/addons/m_terrain/icons/brush_icon_raise.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/brush_icon_raise.svg.import b/addons/m_terrain/icons/brush_icon_raise.svg.import deleted file mode 100644 index bc59d09..0000000 --- a/addons/m_terrain/icons/brush_icon_raise.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://hr610g6qg0ch" -path="res://.godot/imported/brush_icon_raise.svg-70bccca072e213e6a11ff9b1170556dd.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/brush_icon_raise.svg" -dest_files=["res://.godot/imported/brush_icon_raise.svg-70bccca072e213e6a11ff9b1170556dd.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/brush_icon_smooth.svg b/addons/m_terrain/icons/brush_icon_smooth.svg deleted file mode 100644 index ad23799..0000000 --- a/addons/m_terrain/icons/brush_icon_smooth.svg +++ /dev/null @@ -1,45 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/brush_icon_smooth.svg.import b/addons/m_terrain/icons/brush_icon_smooth.svg.import deleted file mode 100644 index fd96cdf..0000000 --- a/addons/m_terrain/icons/brush_icon_smooth.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b8el0qgadshql" -path="res://.godot/imported/brush_icon_smooth.svg-f4f00802d78089d1ae75693d4e9ee168.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/brush_icon_smooth.svg" -dest_files=["res://.godot/imported/brush_icon_smooth.svg-f4f00802d78089d1ae75693d4e9ee168.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/brush_icon_to_height.svg b/addons/m_terrain/icons/brush_icon_to_height.svg deleted file mode 100644 index 36af7e2..0000000 --- a/addons/m_terrain/icons/brush_icon_to_height.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - diff --git a/addons/m_terrain/icons/brush_icon_to_height.svg.import b/addons/m_terrain/icons/brush_icon_to_height.svg.import deleted file mode 100644 index c36c6f0..0000000 --- a/addons/m_terrain/icons/brush_icon_to_height.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://lwsbiudya0cf" -path="res://.godot/imported/brush_icon_to_height.svg-3cb709c7ba0d22b01ac9c4cbd7f29bd0.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/brush_icon_to_height.svg" -dest_files=["res://.godot/imported/brush_icon_to_height.svg-3cb709c7ba0d22b01ac9c4cbd7f29bd0.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/collapse_normal.svg.import b/addons/m_terrain/icons/collapse_normal.svg.import deleted file mode 100644 index 6b03d45..0000000 --- a/addons/m_terrain/icons/collapse_normal.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ch4p2bk5wx574" -path="res://.godot/imported/collapse_normal.svg-d8d1dce8af952d8e5bce0cd73bca1c22.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/collapse_normal.svg" -dest_files=["res://.godot/imported/collapse_normal.svg-d8d1dce8af952d8e5bce0cd73bca1c22.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=0.15 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/collapse_pressed.svg.import b/addons/m_terrain/icons/collapse_pressed.svg.import deleted file mode 100644 index f60a6e9..0000000 --- a/addons/m_terrain/icons/collapse_pressed.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c5ca7hy0hp07k" -path="res://.godot/imported/collapse_pressed.svg-7b3fd37530cf2e62535b5cc40005e9f8.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/collapse_pressed.svg" -dest_files=["res://.godot/imported/collapse_pressed.svg-7b3fd37530cf2e62535b5cc40005e9f8.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=0.12 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/connect_icon.svg b/addons/m_terrain/icons/connect_icon.svg deleted file mode 100644 index bb7c2d6..0000000 --- a/addons/m_terrain/icons/connect_icon.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - diff --git a/addons/m_terrain/icons/connect_icon.svg.import b/addons/m_terrain/icons/connect_icon.svg.import deleted file mode 100644 index a50b173..0000000 --- a/addons/m_terrain/icons/connect_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cylua0xddvmx7" -path="res://.godot/imported/connect_icon.svg-d1088624f93fcfbeb3c8af14d05278f4.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/connect_icon.svg" -dest_files=["res://.godot/imported/connect_icon.svg-d1088624f93fcfbeb3c8af14d05278f4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/depth_test.svg b/addons/m_terrain/icons/depth_test.svg deleted file mode 100644 index 6ba7c21..0000000 --- a/addons/m_terrain/icons/depth_test.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - diff --git a/addons/m_terrain/icons/depth_test.svg.import b/addons/m_terrain/icons/depth_test.svg.import deleted file mode 100644 index 7038602..0000000 --- a/addons/m_terrain/icons/depth_test.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b2edfbh3q6uh2" -path="res://.godot/imported/depth_test.svg-97161f5b845c2fb919fec980e5e322f7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/depth_test.svg" -dest_files=["res://.godot/imported/depth_test.svg-97161f5b845c2fb919fec980e5e322f7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/disconnect_icon.svg b/addons/m_terrain/icons/disconnect_icon.svg deleted file mode 100644 index d94222f..0000000 --- a/addons/m_terrain/icons/disconnect_icon.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - diff --git a/addons/m_terrain/icons/disconnect_icon.svg.import b/addons/m_terrain/icons/disconnect_icon.svg.import deleted file mode 100644 index 5dc2a61..0000000 --- a/addons/m_terrain/icons/disconnect_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bnafvu7s1g7dn" -path="res://.godot/imported/disconnect_icon.svg-6d904c9ba1a378a0fc99a8e77f80643f.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/disconnect_icon.svg" -dest_files=["res://.godot/imported/disconnect_icon.svg-6d904c9ba1a378a0fc99a8e77f80643f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/edit_icon.svg b/addons/m_terrain/icons/edit_icon.svg deleted file mode 100644 index 58caa20..0000000 --- a/addons/m_terrain/icons/edit_icon.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - diff --git a/addons/m_terrain/icons/edit_icon.svg.import b/addons/m_terrain/icons/edit_icon.svg.import deleted file mode 100644 index 5e52421..0000000 --- a/addons/m_terrain/icons/edit_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://s6jqtql0r2bw" -path="res://.godot/imported/edit_icon.svg-0d72b21fa8822a5c6e1045524384b0c7.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/edit_icon.svg" -dest_files=["res://.godot/imported/edit_icon.svg-0d72b21fa8822a5c6e1045524384b0c7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/eraser_icon.svg b/addons/m_terrain/icons/eraser_icon.svg deleted file mode 100644 index d0a4d0d..0000000 --- a/addons/m_terrain/icons/eraser_icon.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/eraser_icon.svg.import b/addons/m_terrain/icons/eraser_icon.svg.import deleted file mode 100644 index 8a1a602..0000000 --- a/addons/m_terrain/icons/eraser_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b05yfhvcm8ehe" -path="res://.godot/imported/eraser_icon.svg-3ebb193a8538721051362a5a54652331.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/eraser_icon.svg" -dest_files=["res://.godot/imported/eraser_icon.svg-3ebb193a8538721051362a5a54652331.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/eye-close.svg b/addons/m_terrain/icons/eye-close.svg deleted file mode 100644 index 0bb856a..0000000 --- a/addons/m_terrain/icons/eye-close.svg +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - eye_close_fill - - - - - eye_close_fill - - - - diff --git a/addons/m_terrain/icons/eye-close.svg.import b/addons/m_terrain/icons/eye-close.svg.import deleted file mode 100644 index 47edb71..0000000 --- a/addons/m_terrain/icons/eye-close.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://boqh1mh7el3o4" -path="res://.godot/imported/eye-close.svg-604b8b623900231b051ae353abe040f1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/eye-close.svg" -dest_files=["res://.godot/imported/eye-close.svg-604b8b623900231b051ae353abe040f1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/eye.svg b/addons/m_terrain/icons/eye.svg deleted file mode 100644 index 0fbea5c..0000000 --- a/addons/m_terrain/icons/eye.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - diff --git a/addons/m_terrain/icons/eye.svg.import b/addons/m_terrain/icons/eye.svg.import deleted file mode 100644 index 6c86daa..0000000 --- a/addons/m_terrain/icons/eye.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://fj1va27m7i5e" -path="res://.godot/imported/eye.svg-5e00ddd1c83a88b12fc1c98b9d413b7e.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/eye.svg" -dest_files=["res://.godot/imported/eye.svg-5e00ddd1c83a88b12fc1c98b9d413b7e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/eye_hidden_icon.svg.import b/addons/m_terrain/icons/eye_hidden_icon.svg.import deleted file mode 100644 index abc3a77..0000000 --- a/addons/m_terrain/icons/eye_hidden_icon.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c8msryj1s2vke" -path="res://.godot/imported/eye_hidden_icon.svg-833112f8112054d69d35484e3d112f55.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/eye_hidden_icon.svg" -dest_files=["res://.godot/imported/eye_hidden_icon.svg-833112f8112054d69d35484e3d112f55.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/eye_icon.svg.import b/addons/m_terrain/icons/eye_icon.svg.import deleted file mode 100644 index 0cc1e33..0000000 --- a/addons/m_terrain/icons/eye_icon.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dm8sen8o0igtx" -path="res://.godot/imported/eye_icon.svg-a44c1349e79cf152d15fdf9373de534c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/eye_icon.svg" -dest_files=["res://.godot/imported/eye_icon.svg-a44c1349e79cf152d15fdf9373de534c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/eye_off.svg b/addons/m_terrain/icons/eye_off.svg deleted file mode 100644 index b3022f4..0000000 --- a/addons/m_terrain/icons/eye_off.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - diff --git a/addons/m_terrain/icons/eye_off.svg.import b/addons/m_terrain/icons/eye_off.svg.import deleted file mode 100644 index fd36de1..0000000 --- a/addons/m_terrain/icons/eye_off.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://27ttt2n4h3nb" -path="res://.godot/imported/eye_off.svg-b0753f76ac04a2ad05a50fd41ae7f21f.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/eye_off.svg" -dest_files=["res://.godot/imported/eye_off.svg-b0753f76ac04a2ad05a50fd41ae7f21f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/foilage_icon.png b/addons/m_terrain/icons/foilage_icon.png deleted file mode 100644 index 6951841..0000000 Binary files a/addons/m_terrain/icons/foilage_icon.png and /dev/null differ diff --git a/addons/m_terrain/icons/foilage_icon.png.import b/addons/m_terrain/icons/foilage_icon.png.import deleted file mode 100644 index cd684bb..0000000 --- a/addons/m_terrain/icons/foilage_icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d03ukmldfnxs3" -path="res://.godot/imported/foilage_icon.png-a98aa00adcd9b86d81ed6e14311d072b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/foilage_icon.png" -dest_files=["res://.godot/imported/foilage_icon.png-a98aa00adcd9b86d81ed6e14311d072b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/handle00.png b/addons/m_terrain/icons/handle00.png deleted file mode 100644 index 2cb1393..0000000 Binary files a/addons/m_terrain/icons/handle00.png and /dev/null differ diff --git a/addons/m_terrain/icons/handle00.png.import b/addons/m_terrain/icons/handle00.png.import deleted file mode 100644 index 1f8fdba..0000000 --- a/addons/m_terrain/icons/handle00.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bhmlyci7la1mr" -path.s3tc="res://.godot/imported/handle00.png-d60407c75e080273a89ee2b65f18efa9.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/icons/handle00.png" -dest_files=["res://.godot/imported/handle00.png-d60407c75e080273a89ee2b65f18efa9.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/icons/handle01.png b/addons/m_terrain/icons/handle01.png deleted file mode 100644 index 1dd47b1..0000000 Binary files a/addons/m_terrain/icons/handle01.png and /dev/null differ diff --git a/addons/m_terrain/icons/handle01.png.import b/addons/m_terrain/icons/handle01.png.import deleted file mode 100644 index a73f098..0000000 --- a/addons/m_terrain/icons/handle01.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://byodukiddauai" -path.s3tc="res://.godot/imported/handle01.png-d48928787d4c4175d463121762259d7e.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/m_terrain/icons/handle01.png" -dest_files=["res://.godot/imported/handle01.png-d48928787d4c4175d463121762259d7e.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/m_terrain/icons/hidden.png b/addons/m_terrain/icons/hidden.png deleted file mode 100644 index 6f336e8..0000000 Binary files a/addons/m_terrain/icons/hidden.png and /dev/null differ diff --git a/addons/m_terrain/icons/hidden.png.import b/addons/m_terrain/icons/hidden.png.import deleted file mode 100644 index 02e5201..0000000 --- a/addons/m_terrain/icons/hidden.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vfuxvuomsr10" -path="res://.godot/imported/hidden.png-06a999a48cefacfaee536072e67b7840.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/hidden.png" -dest_files=["res://.godot/imported/hidden.png-06a999a48cefacfaee536072e67b7840.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/human.svg b/addons/m_terrain/icons/human.svg deleted file mode 100644 index a948c09..0000000 --- a/addons/m_terrain/icons/human.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/addons/m_terrain/icons/human.svg.import b/addons/m_terrain/icons/human.svg.import deleted file mode 100644 index bcb17eb..0000000 --- a/addons/m_terrain/icons/human.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://lhctvyd5qpxt" -path="res://.godot/imported/human.svg-eb84eb5d95a5ca329cfed90e7298fefc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/human.svg" -dest_files=["res://.godot/imported/human.svg-eb84eb5d95a5ca329cfed90e7298fefc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/human_button_normal.png b/addons/m_terrain/icons/human_button_normal.png deleted file mode 100644 index 46fce90..0000000 Binary files a/addons/m_terrain/icons/human_button_normal.png and /dev/null differ diff --git a/addons/m_terrain/icons/human_button_normal.png.import b/addons/m_terrain/icons/human_button_normal.png.import deleted file mode 100644 index 9dea7e5..0000000 --- a/addons/m_terrain/icons/human_button_normal.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b72iot2bj8ls" -path="res://.godot/imported/human_button_normal.png-45bce41eaf0940826355249b10f5646e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/human_button_normal.png" -dest_files=["res://.godot/imported/human_button_normal.png-45bce41eaf0940826355249b10f5646e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/human_button_pressed.png b/addons/m_terrain/icons/human_button_pressed.png deleted file mode 100644 index e60e607..0000000 Binary files a/addons/m_terrain/icons/human_button_pressed.png and /dev/null differ diff --git a/addons/m_terrain/icons/human_button_pressed.png.import b/addons/m_terrain/icons/human_button_pressed.png.import deleted file mode 100644 index 05d4bbb..0000000 --- a/addons/m_terrain/icons/human_button_pressed.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c0lxruofvkcr" -path="res://.godot/imported/human_button_pressed.png-3ee2023e4b22982581fd3c4a260f5bb2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/human_button_pressed.png" -dest_files=["res://.godot/imported/human_button_pressed.png-3ee2023e4b22982581fd3c4a260f5bb2.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/human_disabled.svg b/addons/m_terrain/icons/human_disabled.svg deleted file mode 100644 index f9651da..0000000 --- a/addons/m_terrain/icons/human_disabled.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - diff --git a/addons/m_terrain/icons/human_disabled.svg.import b/addons/m_terrain/icons/human_disabled.svg.import deleted file mode 100644 index 5134c20..0000000 --- a/addons/m_terrain/icons/human_disabled.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dgjegrn8jhlf6" -path="res://.godot/imported/human_disabled.svg-98942ec12f6b8681850779552b3951f1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/human_disabled.svg" -dest_files=["res://.godot/imported/human_disabled.svg-98942ec12f6b8681850779552b3951f1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/icon_close.svg b/addons/m_terrain/icons/icon_close.svg deleted file mode 100644 index 5e116a4..0000000 --- a/addons/m_terrain/icons/icon_close.svg +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/addons/m_terrain/icons/icon_close.svg.import b/addons/m_terrain/icons/icon_close.svg.import deleted file mode 100644 index 77f1152..0000000 --- a/addons/m_terrain/icons/icon_close.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://t8tdan3853oy" -path="res://.godot/imported/icon_close.svg-b99ee13d9ea79d2266b745bfab188365.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/icon_close.svg" -dest_files=["res://.godot/imported/icon_close.svg-b99ee13d9ea79d2266b745bfab188365.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/info_icon.png b/addons/m_terrain/icons/info_icon.png deleted file mode 100644 index c249966..0000000 Binary files a/addons/m_terrain/icons/info_icon.png and /dev/null differ diff --git a/addons/m_terrain/icons/info_icon.png.import b/addons/m_terrain/icons/info_icon.png.import deleted file mode 100644 index ed9b829..0000000 --- a/addons/m_terrain/icons/info_icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cjho7a8u0ixdi" -path="res://.godot/imported/info_icon.png-dc36a7d205a77e9f2dc29af8151354c2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/info_icon.png" -dest_files=["res://.godot/imported/info_icon.png-dc36a7d205a77e9f2dc29af8151354c2.ctex"] - -[params] - -compress/mode=3 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=1 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/info_icon_pressed.png b/addons/m_terrain/icons/info_icon_pressed.png deleted file mode 100644 index 173d746..0000000 Binary files a/addons/m_terrain/icons/info_icon_pressed.png and /dev/null differ diff --git a/addons/m_terrain/icons/info_icon_pressed.png.import b/addons/m_terrain/icons/info_icon_pressed.png.import deleted file mode 100644 index 94bf7b7..0000000 --- a/addons/m_terrain/icons/info_icon_pressed.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cyftv3kygv5b7" -path="res://.godot/imported/info_icon_pressed.png-633638cd657b82eedb2a1ca18b093508.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/info_icon_pressed.png" -dest_files=["res://.godot/imported/info_icon_pressed.png-633638cd657b82eedb2a1ca18b093508.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/invert_icon.svg b/addons/m_terrain/icons/invert_icon.svg deleted file mode 100644 index 876a220..0000000 --- a/addons/m_terrain/icons/invert_icon.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/invert_icon.svg.import b/addons/m_terrain/icons/invert_icon.svg.import deleted file mode 100644 index 67d4c3b..0000000 --- a/addons/m_terrain/icons/invert_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c7p5vijgoev7o" -path="res://.godot/imported/invert_icon.svg-eb6168f9f5a3d00bab7a574e227c8c42.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/invert_icon.svg" -dest_files=["res://.godot/imported/invert_icon.svg-eb6168f9f5a3d00bab7a574e227c8c42.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/invert_icon_inverted.svg b/addons/m_terrain/icons/invert_icon_inverted.svg deleted file mode 100644 index 74a5b21..0000000 --- a/addons/m_terrain/icons/invert_icon_inverted.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/invert_icon_inverted.svg.import b/addons/m_terrain/icons/invert_icon_inverted.svg.import deleted file mode 100644 index 94c982d..0000000 --- a/addons/m_terrain/icons/invert_icon_inverted.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://tmhtthjk2rb4" -path="res://.godot/imported/invert_icon_inverted.svg-e5266d0a91ee17e04b50c0af5609da53.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/invert_icon_inverted.svg" -dest_files=["res://.godot/imported/invert_icon_inverted.svg-e5266d0a91ee17e04b50c0af5609da53.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/invert_icon_normal.svg b/addons/m_terrain/icons/invert_icon_normal.svg deleted file mode 100644 index 2358e7b..0000000 --- a/addons/m_terrain/icons/invert_icon_normal.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/invert_icon_normal.svg.import b/addons/m_terrain/icons/invert_icon_normal.svg.import deleted file mode 100644 index 64641dd..0000000 --- a/addons/m_terrain/icons/invert_icon_normal.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b8xvuorm57o1s" -path="res://.godot/imported/invert_icon_normal.svg-f1e1461b6de05d53eb1e8e9d8c63958a.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/invert_icon_normal.svg" -dest_files=["res://.godot/imported/invert_icon_normal.svg-f1e1461b6de05d53eb1e8e9d8c63958a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/lock.svg b/addons/m_terrain/icons/lock.svg deleted file mode 100644 index 056e178..0000000 --- a/addons/m_terrain/icons/lock.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/addons/m_terrain/icons/lock.svg.import b/addons/m_terrain/icons/lock.svg.import deleted file mode 100644 index e33ad6d..0000000 --- a/addons/m_terrain/icons/lock.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://jw6maiih4qf8" -path="res://.godot/imported/lock.svg-11d5771bf3a1e0eba9bcc0935adf2b7e.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/lock.svg" -dest_files=["res://.godot/imported/lock.svg-11d5771bf3a1e0eba9bcc0935adf2b7e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/magnet_icon.svg b/addons/m_terrain/icons/magnet_icon.svg deleted file mode 100644 index e371999..0000000 --- a/addons/m_terrain/icons/magnet_icon.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/magnet_icon.svg.import b/addons/m_terrain/icons/magnet_icon.svg.import deleted file mode 100644 index 6e48273..0000000 --- a/addons/m_terrain/icons/magnet_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ckbvdmvbcxfb6" -path="res://.godot/imported/magnet_icon.svg-d2c33a6be3fd993789e8360de5238e95.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/magnet_icon.svg" -dest_files=["res://.godot/imported/magnet_icon.svg-d2c33a6be3fd993789e8360de5238e95.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/merge_down_icon.svg b/addons/m_terrain/icons/merge_down_icon.svg deleted file mode 100644 index 602902d..0000000 --- a/addons/m_terrain/icons/merge_down_icon.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/merge_down_icon.svg.import b/addons/m_terrain/icons/merge_down_icon.svg.import deleted file mode 100644 index 63ce53c..0000000 --- a/addons/m_terrain/icons/merge_down_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://tow1rj13cxaw" -path="res://.godot/imported/merge_down_icon.svg-5bb88917ab333f03f5916d99f04806eb.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/merge_down_icon.svg" -dest_files=["res://.godot/imported/merge_down_icon.svg-5bb88917ab333f03f5916d99f04806eb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/merge_layers_icon.svg b/addons/m_terrain/icons/merge_layers_icon.svg deleted file mode 100644 index 3acabea..0000000 --- a/addons/m_terrain/icons/merge_layers_icon.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/merge_layers_icon.svg.import b/addons/m_terrain/icons/merge_layers_icon.svg.import deleted file mode 100644 index 6d57512..0000000 --- a/addons/m_terrain/icons/merge_layers_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://6ibn1gduso81" -path="res://.godot/imported/merge_layers_icon.svg-a7f760c4101101940d873cf31df839a3.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/merge_layers_icon.svg" -dest_files=["res://.godot/imported/merge_layers_icon.svg-a7f760c4101101940d873cf31df839a3.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/mirror_icon.svg b/addons/m_terrain/icons/mirror_icon.svg deleted file mode 100644 index 3aa1020..0000000 --- a/addons/m_terrain/icons/mirror_icon.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/mirror_icon.svg.import b/addons/m_terrain/icons/mirror_icon.svg.import deleted file mode 100644 index 7c4e516..0000000 --- a/addons/m_terrain/icons/mirror_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c64direekaeap" -path="res://.godot/imported/mirror_icon.svg-2c71e160a9f39f6427b0dcee4f5de248.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/mirror_icon.svg" -dest_files=["res://.godot/imported/mirror_icon.svg-2c71e160a9f39f6427b0dcee4f5de248.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/more_options_icon.svg b/addons/m_terrain/icons/more_options_icon.svg deleted file mode 100644 index 24876d8..0000000 --- a/addons/m_terrain/icons/more_options_icon.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/more_options_icon.svg.import b/addons/m_terrain/icons/more_options_icon.svg.import deleted file mode 100644 index 4162e88..0000000 --- a/addons/m_terrain/icons/more_options_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b4ylxie43lan2" -path="res://.godot/imported/more_options_icon.svg-1578d91250f3678ea66fd07a3541675c.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/more_options_icon.svg" -dest_files=["res://.godot/imported/more_options_icon.svg-1578d91250f3678ea66fd07a3541675c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/mpath_collapse_point_icon.svg b/addons/m_terrain/icons/mpath_collapse_point_icon.svg deleted file mode 100644 index bf7d300..0000000 --- a/addons/m_terrain/icons/mpath_collapse_point_icon.svg +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/mpath_collapse_point_icon.svg.import b/addons/m_terrain/icons/mpath_collapse_point_icon.svg.import deleted file mode 100644 index e3d992c..0000000 --- a/addons/m_terrain/icons/mpath_collapse_point_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://30e6iyx7q1y7" -path="res://.godot/imported/mpath_collapse_point_icon.svg-feccb3571057b23014824af7da01a92e.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/mpath_collapse_point_icon.svg" -dest_files=["res://.godot/imported/mpath_collapse_point_icon.svg-feccb3571057b23014824af7da01a92e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/no_images.png b/addons/m_terrain/icons/no_images.png deleted file mode 100644 index 7c10229..0000000 Binary files a/addons/m_terrain/icons/no_images.png and /dev/null differ diff --git a/addons/m_terrain/icons/no_images.png.import b/addons/m_terrain/icons/no_images.png.import deleted file mode 100644 index f5b099f..0000000 --- a/addons/m_terrain/icons/no_images.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://f1ola7kh408" -path="res://.godot/imported/no_images.png-56785ae7fc948df6ca282de9a9bdd9db.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/no_images.png" -dest_files=["res://.godot/imported/no_images.png-56785ae7fc948df6ca282de9a9bdd9db.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/no_mask_icon.svg b/addons/m_terrain/icons/no_mask_icon.svg deleted file mode 100644 index f530a04..0000000 --- a/addons/m_terrain/icons/no_mask_icon.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - diff --git a/addons/m_terrain/icons/no_mask_icon.svg.import b/addons/m_terrain/icons/no_mask_icon.svg.import deleted file mode 100644 index c83c6db..0000000 --- a/addons/m_terrain/icons/no_mask_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://rtqaiuii2jml" -path="res://.godot/imported/no_mask_icon.svg-e96d0ec2694647e6436fd3bb35cec387.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/no_mask_icon.svg" -dest_files=["res://.godot/imported/no_mask_icon.svg-e96d0ec2694647e6436fd3bb35cec387.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/obstacle_icon.png b/addons/m_terrain/icons/obstacle_icon.png deleted file mode 100644 index d92f916..0000000 Binary files a/addons/m_terrain/icons/obstacle_icon.png and /dev/null differ diff --git a/addons/m_terrain/icons/obstacle_icon.png.import b/addons/m_terrain/icons/obstacle_icon.png.import deleted file mode 100644 index 0628840..0000000 --- a/addons/m_terrain/icons/obstacle_icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ckixcw11hx25p" -path="res://.godot/imported/obstacle_icon.png-499922fa40b53000fee9abcac2a1bb00.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/obstacle_icon.png" -dest_files=["res://.godot/imported/obstacle_icon.png-499922fa40b53000fee9abcac2a1bb00.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/paint-normal.png b/addons/m_terrain/icons/paint-normal.png deleted file mode 100644 index 4417030..0000000 Binary files a/addons/m_terrain/icons/paint-normal.png and /dev/null differ diff --git a/addons/m_terrain/icons/paint-normal.png.import b/addons/m_terrain/icons/paint-normal.png.import deleted file mode 100644 index 8673940..0000000 --- a/addons/m_terrain/icons/paint-normal.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dok8ugsvea2hg" -path="res://.godot/imported/paint-normal.png-c6b2562f6c84603ad7f896e44c5ddb3e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/paint-normal.png" -dest_files=["res://.godot/imported/paint-normal.png-c6b2562f6c84603ad7f896e44c5ddb3e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/paint-pressed.png b/addons/m_terrain/icons/paint-pressed.png deleted file mode 100644 index b75fd5b..0000000 Binary files a/addons/m_terrain/icons/paint-pressed.png and /dev/null differ diff --git a/addons/m_terrain/icons/paint-pressed.png.import b/addons/m_terrain/icons/paint-pressed.png.import deleted file mode 100644 index 7918217..0000000 --- a/addons/m_terrain/icons/paint-pressed.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dc8xvtd03qq1j" -path="res://.godot/imported/paint-pressed.png-2aba7a39a29cb1d2747aa99fdd447a3c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/paint-pressed.png" -dest_files=["res://.godot/imported/paint-pressed.png-2aba7a39a29cb1d2747aa99fdd447a3c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/paint.svg b/addons/m_terrain/icons/paint.svg deleted file mode 100644 index 962791a..0000000 --- a/addons/m_terrain/icons/paint.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/paint.svg.import b/addons/m_terrain/icons/paint.svg.import deleted file mode 100644 index daf0f9f..0000000 --- a/addons/m_terrain/icons/paint.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bv66xmw5mis4k" -path="res://.godot/imported/paint.svg-cc3eae7fd8485a70abf8ca51b9d99e5e.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/paint.svg" -dest_files=["res://.godot/imported/paint.svg-cc3eae7fd8485a70abf8ca51b9d99e5e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/raise_brush_icon.svg.import b/addons/m_terrain/icons/raise_brush_icon.svg.import deleted file mode 100644 index 926a297..0000000 --- a/addons/m_terrain/icons/raise_brush_icon.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://5i1jry2pnvsj" -path="res://.godot/imported/raise_brush_icon.svg-ee8613b8f51cc9c183fe3c0e54296441.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/raise_brush_icon.svg" -dest_files=["res://.godot/imported/raise_brush_icon.svg-ee8613b8f51cc9c183fe3c0e54296441.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/reverse_brush_icon.svg b/addons/m_terrain/icons/reverse_brush_icon.svg deleted file mode 100644 index 08da2a5..0000000 --- a/addons/m_terrain/icons/reverse_brush_icon.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/reverse_brush_icon.svg.import b/addons/m_terrain/icons/reverse_brush_icon.svg.import deleted file mode 100644 index 5271907..0000000 --- a/addons/m_terrain/icons/reverse_brush_icon.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://byb7ewq1mckcf" -path="res://.godot/imported/reverse_brush_icon.svg-0b1bf8352bb6eeb0118ce8bcc82d1095.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/reverse_brush_icon.svg" -dest_files=["res://.godot/imported/reverse_brush_icon.svg-0b1bf8352bb6eeb0118ce8bcc82d1095.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/reverse_brush_icon_normal.svg b/addons/m_terrain/icons/reverse_brush_icon_normal.svg deleted file mode 100644 index f083f18..0000000 --- a/addons/m_terrain/icons/reverse_brush_icon_normal.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/reverse_brush_icon_normal.svg.import b/addons/m_terrain/icons/reverse_brush_icon_normal.svg.import deleted file mode 100644 index cc1f81c..0000000 --- a/addons/m_terrain/icons/reverse_brush_icon_normal.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dk80nxh0y8ojg" -path="res://.godot/imported/reverse_brush_icon_normal.svg-45a8d178d7b3701e174b8d47401597ca.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/reverse_brush_icon_normal.svg" -dest_files=["res://.godot/imported/reverse_brush_icon_normal.svg-45a8d178d7b3701e174b8d47401597ca.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/reverse_brush_icon_reversed.svg b/addons/m_terrain/icons/reverse_brush_icon_reversed.svg deleted file mode 100644 index 6a6b140..0000000 --- a/addons/m_terrain/icons/reverse_brush_icon_reversed.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/reverse_brush_icon_reversed.svg.import b/addons/m_terrain/icons/reverse_brush_icon_reversed.svg.import deleted file mode 100644 index a3f4896..0000000 --- a/addons/m_terrain/icons/reverse_brush_icon_reversed.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dodufn5ecw4pa" -path="res://.godot/imported/reverse_brush_icon_reversed.svg-11d8161c2835b01ffbdbc46e22e925b4.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/reverse_brush_icon_reversed.svg" -dest_files=["res://.godot/imported/reverse_brush_icon_reversed.svg-11d8161c2835b01ffbdbc46e22e925b4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/rotation.svg b/addons/m_terrain/icons/rotation.svg deleted file mode 100644 index e71120b..0000000 --- a/addons/m_terrain/icons/rotation.svg +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - diff --git a/addons/m_terrain/icons/rotation.svg.import b/addons/m_terrain/icons/rotation.svg.import deleted file mode 100644 index 93e8bb5..0000000 --- a/addons/m_terrain/icons/rotation.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cjs22nfbjl71l" -path="res://.godot/imported/rotation.svg-5da06ade55b907392c07caeb6c805099.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/rotation.svg" -dest_files=["res://.godot/imported/rotation.svg-5da06ade55b907392c07caeb6c805099.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/save_active.png b/addons/m_terrain/icons/save_active.png deleted file mode 100644 index 5a319d8..0000000 Binary files a/addons/m_terrain/icons/save_active.png and /dev/null differ diff --git a/addons/m_terrain/icons/save_active.png.import b/addons/m_terrain/icons/save_active.png.import deleted file mode 100644 index e9633d2..0000000 --- a/addons/m_terrain/icons/save_active.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://balqs3xpw1e3p" -path="res://.godot/imported/save_active.png-758ea1124ee860b4879c519910c5b9bb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/save_active.png" -dest_files=["res://.godot/imported/save_active.png-758ea1124ee860b4879c519910c5b9bb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/save_deactive.png b/addons/m_terrain/icons/save_deactive.png deleted file mode 100644 index 49ab051..0000000 Binary files a/addons/m_terrain/icons/save_deactive.png and /dev/null differ diff --git a/addons/m_terrain/icons/save_deactive.png.import b/addons/m_terrain/icons/save_deactive.png.import deleted file mode 100644 index 86246bf..0000000 --- a/addons/m_terrain/icons/save_deactive.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vj2s60luchw7" -path="res://.godot/imported/save_deactive.png-4d38f2b11928d31fe1a01fbc9ead326a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/save_deactive.png" -dest_files=["res://.godot/imported/save_deactive.png-4d38f2b11928d31fe1a01fbc9ead326a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/save_icon.svg b/addons/m_terrain/icons/save_icon.svg deleted file mode 100644 index f5dff6e..0000000 --- a/addons/m_terrain/icons/save_icon.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - diff --git a/addons/m_terrain/icons/save_icon.svg.import b/addons/m_terrain/icons/save_icon.svg.import deleted file mode 100644 index c53bacd..0000000 --- a/addons/m_terrain/icons/save_icon.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dj86rx42xt6wc" -path="res://.godot/imported/save_icon.svg-1bd5835ef7201c14e61b40f3cb921cf8.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/save_icon.svg" -dest_files=["res://.godot/imported/save_icon.svg-1bd5835ef7201c14e61b40f3cb921cf8.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/save_icon_disable.svg b/addons/m_terrain/icons/save_icon_disable.svg deleted file mode 100644 index 2362c8c..0000000 --- a/addons/m_terrain/icons/save_icon_disable.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - diff --git a/addons/m_terrain/icons/save_icon_disable.svg.import b/addons/m_terrain/icons/save_icon_disable.svg.import deleted file mode 100644 index b280c98..0000000 --- a/addons/m_terrain/icons/save_icon_disable.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://btn8tgu2yhlxj" -path="res://.godot/imported/save_icon_disable.svg-617bf87679baadf262a3b5977269a03e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/save_icon_disable.svg" -dest_files=["res://.godot/imported/save_icon_disable.svg-617bf87679baadf262a3b5977269a03e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/sculpt_terrain.svg b/addons/m_terrain/icons/sculpt_terrain.svg deleted file mode 100644 index 0283298..0000000 --- a/addons/m_terrain/icons/sculpt_terrain.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/sculpt_terrain.svg.import b/addons/m_terrain/icons/sculpt_terrain.svg.import deleted file mode 100644 index 94a14e2..0000000 --- a/addons/m_terrain/icons/sculpt_terrain.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://kmamiw46mftf" -path="res://.godot/imported/sculpt_terrain.svg-6bb3c406d1a6169745d9a508fbf101e8.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/sculpt_terrain.svg" -dest_files=["res://.godot/imported/sculpt_terrain.svg-6bb3c406d1a6169745d9a508fbf101e8.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/settings_icon.svg b/addons/m_terrain/icons/settings_icon.svg deleted file mode 100644 index 480e4c2..0000000 --- a/addons/m_terrain/icons/settings_icon.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/m_terrain/icons/settings_icon.svg.import b/addons/m_terrain/icons/settings_icon.svg.import deleted file mode 100644 index 3e456c9..0000000 --- a/addons/m_terrain/icons/settings_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bw2njdr7ynhtk" -path="res://.godot/imported/settings_icon.svg-3542b39b807f7b578dc7af22d8ab8fd7.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/settings_icon.svg" -dest_files=["res://.godot/imported/settings_icon.svg-3542b39b807f7b578dc7af22d8ab8fd7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/show.png b/addons/m_terrain/icons/show.png deleted file mode 100644 index 8b965ff..0000000 Binary files a/addons/m_terrain/icons/show.png and /dev/null differ diff --git a/addons/m_terrain/icons/show.png.import b/addons/m_terrain/icons/show.png.import deleted file mode 100644 index 5ea5c70..0000000 --- a/addons/m_terrain/icons/show.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://h6h1w7oah3kx" -path="res://.godot/imported/show.png-b6f0fd77cdcfcdeb31b2481976608ec2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/show.png" -dest_files=["res://.godot/imported/show.png-b6f0fd77cdcfcdeb31b2481976608ec2.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/slider_grabber.svg b/addons/m_terrain/icons/slider_grabber.svg deleted file mode 100644 index 4c205b6..0000000 --- a/addons/m_terrain/icons/slider_grabber.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - diff --git a/addons/m_terrain/icons/slider_grabber.svg.import b/addons/m_terrain/icons/slider_grabber.svg.import deleted file mode 100644 index fd39a31..0000000 --- a/addons/m_terrain/icons/slider_grabber.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bxeg3w2i6m1dd" -path="res://.godot/imported/slider_grabber.svg-29e6a9dfa935cd5e9316051ef5634bfc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/slider_grabber.svg" -dest_files=["res://.godot/imported/slider_grabber.svg-29e6a9dfa935cd5e9316051ef5634bfc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/slider_grabber_highlight_icon.svg b/addons/m_terrain/icons/slider_grabber_highlight_icon.svg deleted file mode 100644 index 8430f73..0000000 --- a/addons/m_terrain/icons/slider_grabber_highlight_icon.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - diff --git a/addons/m_terrain/icons/slider_grabber_highlight_icon.svg.import b/addons/m_terrain/icons/slider_grabber_highlight_icon.svg.import deleted file mode 100644 index 0ee4b1c..0000000 --- a/addons/m_terrain/icons/slider_grabber_highlight_icon.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b0m46wjnrfder" -path="res://.godot/imported/slider_grabber_highlight_icon.svg-b8a8342e31fd5797cca85da080966fc9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/slider_grabber_highlight_icon.svg" -dest_files=["res://.godot/imported/slider_grabber_highlight_icon.svg-b8a8342e31fd5797cca85da080966fc9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/icons/switch_direction_icon.svg b/addons/m_terrain/icons/switch_direction_icon.svg deleted file mode 100644 index 6c0ee55..0000000 --- a/addons/m_terrain/icons/switch_direction_icon.svg +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - diff --git a/addons/m_terrain/icons/switch_direction_icon.svg.import b/addons/m_terrain/icons/switch_direction_icon.svg.import deleted file mode 100644 index 66923a1..0000000 --- a/addons/m_terrain/icons/switch_direction_icon.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ckrq26s3bkih3" -path="res://.godot/imported/switch_direction_icon.svg-685456fe990114ea89d3df8486e9ed04.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/switch_direction_icon.svg" -dest_files=["res://.godot/imported/switch_direction_icon.svg-685456fe990114ea89d3df8486e9ed04.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/terrain_icon.png b/addons/m_terrain/icons/terrain_icon.png deleted file mode 100644 index a91aa59..0000000 Binary files a/addons/m_terrain/icons/terrain_icon.png and /dev/null differ diff --git a/addons/m_terrain/icons/terrain_icon.png.import b/addons/m_terrain/icons/terrain_icon.png.import deleted file mode 100644 index 04a9d40..0000000 --- a/addons/m_terrain/icons/terrain_icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bsdfn2yec6vtv" -path="res://.godot/imported/terrain_icon.png-7662a98f11adcb134a1396ae4615bee6.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/terrain_icon.png" -dest_files=["res://.godot/imported/terrain_icon.png-7662a98f11adcb134a1396ae4615bee6.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/toggle_connection.svg b/addons/m_terrain/icons/toggle_connection.svg deleted file mode 100644 index eb6d751..0000000 --- a/addons/m_terrain/icons/toggle_connection.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/toggle_connection.svg.import b/addons/m_terrain/icons/toggle_connection.svg.import deleted file mode 100644 index ae558e9..0000000 --- a/addons/m_terrain/icons/toggle_connection.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c32td7i377ewu" -path="res://.godot/imported/toggle_connection.svg-98488a96328727a238b1a03a7b759541.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/toggle_connection.svg" -dest_files=["res://.godot/imported/toggle_connection.svg-98488a96328727a238b1a03a7b759541.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/m_terrain/icons/tsnap_icon.png b/addons/m_terrain/icons/tsnap_icon.png deleted file mode 100644 index f934b12..0000000 Binary files a/addons/m_terrain/icons/tsnap_icon.png and /dev/null differ diff --git a/addons/m_terrain/icons/tsnap_icon.png.import b/addons/m_terrain/icons/tsnap_icon.png.import deleted file mode 100644 index 79d64e8..0000000 --- a/addons/m_terrain/icons/tsnap_icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dl46tixprq2ro" -path="res://.godot/imported/tsnap_icon.png-3d3cafa79db00a2e849830ba4628ce16.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/tsnap_icon.png" -dest_files=["res://.godot/imported/tsnap_icon.png-3d3cafa79db00a2e849830ba4628ce16.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/tsnap_icon_pressed.png b/addons/m_terrain/icons/tsnap_icon_pressed.png deleted file mode 100644 index 1205610..0000000 Binary files a/addons/m_terrain/icons/tsnap_icon_pressed.png and /dev/null differ diff --git a/addons/m_terrain/icons/tsnap_icon_pressed.png.import b/addons/m_terrain/icons/tsnap_icon_pressed.png.import deleted file mode 100644 index 0a9f0d8..0000000 --- a/addons/m_terrain/icons/tsnap_icon_pressed.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dow4horhd3x6v" -path="res://.godot/imported/tsnap_icon_pressed.png-033b63880538ce81eeec190409033cf7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/tsnap_icon_pressed.png" -dest_files=["res://.godot/imported/tsnap_icon_pressed.png-033b63880538ce81eeec190409033cf7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/m_terrain/icons/walk_icon.svg b/addons/m_terrain/icons/walk_icon.svg deleted file mode 100644 index 752286e..0000000 --- a/addons/m_terrain/icons/walk_icon.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - diff --git a/addons/m_terrain/icons/walk_icon.svg.import b/addons/m_terrain/icons/walk_icon.svg.import deleted file mode 100644 index 39c65d3..0000000 --- a/addons/m_terrain/icons/walk_icon.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://2dpvr41alpt8" -path="res://.godot/imported/walk_icon.svg-18243c4282b1183d699db0b62b64ff9f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/m_terrain/icons/walk_icon.svg" -dest_files=["res://.godot/imported/walk_icon.svg-18243c4282b1183d699db0b62b64ff9f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/m_terrain/inspector/gui/curve_terrain.gd b/addons/m_terrain/inspector/gui/curve_terrain.gd deleted file mode 100644 index 1d0a53c..0000000 --- a/addons/m_terrain/inspector/gui/curve_terrain.gd +++ /dev/null @@ -1,277 +0,0 @@ -@tool -extends VBoxContainer - -var grass_icon_tex = preload("res://addons/m_terrain/icons/foilage_icon.png") - -var curve_terrain:MCurveTerrain -var gizmo -var path:MPath -var active_grass:MGrass=null - -func start_curve_terrain(_gizmo,_path): - $tsv2/deform_tools.get_popup().connect("index_pressed",deform_tool_index_pressed) - $tsv3/paint_tools.get_popup().connect("index_pressed",paint_tool_index_pressed) - $g_container/gt/grass_tool.get_popup().connect("index_pressed",grass_tool_index_pressed) - gizmo = _gizmo - path = _path - curve_terrain = gizmo.curve_terrain - curve_terrain.curve = path.curve - if path.has_meta("curve_terrain"): - var d = path.get_meta("curve_terrain") - set_values(d) - else: - set_default_values() - ### Grass system is a bit different - load_grass_settings() - - -func set_default_values(): - #print("set default -----------------------") - var new_mcurve:=MCurveTerrain.new() - gizmo.auto_terrain_deform = false - gizmo.auto_terrain_paint = false - gizmo.auto_grass_modify = false - var d = get_curve_terrain_data(new_mcurve) - set_values(d) - - -func set_values(d:Dictionary): - $panle_open.set_pressed_no_signal(d["panel_open"]) ; panle_open_toggled(d["panel_open"]) - $tsv2/auto_deform.set_pressed_no_signal(d["auto_deform"]) ; gizmo.auto_terrain_deform = d["auto_deform"] - $tsv/tilt.set_pressed_no_signal(d["tilt"]) ; curve_terrain.apply_tilt = d["tilt"] - $tsv/scale.set_pressed_no_signal(d["scale"]) ; curve_terrain.apply_scale = d["scale"] - $tlv/tlayer.text = d["tlayer"] ; curve_terrain.terrain_layer_name = d["tlayer"] - $rv/dradius.set_value_no_signal(d["dradius"]) ; curve_terrain.deform_radius = d["dradius"] - $fv/dfalloff.set_value_no_signal(d["dfalloff"]) ; curve_terrain.deform_falloff = d["dfalloff"] - $ov/doffset.set_value_no_signal(d["doffset"]) ; curve_terrain.deform_offest = d["doffset"] - ############# Paint - $tsv3/auto_paint.set_pressed_no_signal(d["auto_paint"]) ; gizmo.auto_terrain_paint = d["auto_paint"] - $ov2/iname.text = d["iname"] ; curve_terrain.terrain_image_name = d["iname"] - $ov3/pradius.set_value_no_signal(d["pradius"]) ; curve_terrain.paint_radius = d["pradius"] - $ov5/pfalloff.set_value_no_signal(d["pfalloff"]) ; curve_terrain.paint_falloff = d["pfalloff"] - $ov4/pcolor.color = d["pcolor"] ; curve_terrain.paint_color = d["pcolor"] - $ov4/bgcolor.color = d["bgcolor"] ; curve_terrain.bg_color = d["bgcolor"] - $tsv2/deform_tools.set("popup/item_0/checked",d["donly_selected"]) - $tsv3/paint_tools.set("popup/item_0/checked",d["ponly_selected"]) - $g_container/gt/auto_g_modify.set_pressed_no_signal(d["auto_grass"]) ; gizmo.auto_grass_modify = d["auto_grass"] - -func get_curve_terrain_data(ct:MCurveTerrain)->Dictionary: - var d:Dictionary - d["panel_open"] = gizmo.is_curve_terrain_panel_open - d["auto_deform"] = gizmo.auto_terrain_deform - d["tilt"] = ct.apply_tilt - d["scale"] = ct.apply_scale - d["tlayer"] = ct.terrain_layer_name - d["doffset"] = ct.deform_offest - d["dradius"] = ct.deform_radius - d["dfalloff"] = ct.deform_falloff - d["auto_paint"] = gizmo.auto_terrain_paint - d["iname"] = ct.terrain_image_name - d["pcolor"] = ct.paint_color - d["bgcolor"] = ct.bg_color - d["pradius"] = ct.paint_radius - d["pfalloff"] = ct.paint_falloff - d["donly_selected"] = $tsv2/deform_tools.get("popup/item_0/checked") - d["ponly_selected"] = $tsv3/paint_tools.get("popup/item_0/checked") - d["auto_grass"] = gizmo.auto_grass_modify - return d - -func update_meta_values(): - var d = get_curve_terrain_data(curve_terrain) - path.set_meta("curve_terrain",d) - -func _on_panle_open_toggled(toggled_on): - var child_count = get_child_count() - gizmo.is_curve_terrain_panel_open = toggled_on - for c in range(2,child_count): - get_child(c).visible = toggled_on - update_meta_values() - -func panle_open_toggled(toggled_on): - var child_count = get_child_count() - for c in range(2,child_count): - get_child(c).visible = toggled_on - -func _on_auto_deform_toggled(toggled_on): - gizmo.auto_terrain_deform = toggled_on - update_meta_values() - -func _on_tilt_toggled(toggled_on): - curve_terrain.apply_tilt = toggled_on - update_meta_values() - -func _on_scale_toggled(toggled_on): - curve_terrain.apply_scale = toggled_on - update_meta_values() - -func _on_tlayer_text_changed(new_text): - curve_terrain.terrain_layer_name = new_text - update_meta_values() - -func _on_dradius_value_changed(value): - curve_terrain.deform_radius = value - update_meta_values() - -func _on_dfalloff_value_changed(value): - curve_terrain.deform_falloff = value - update_meta_values() - -func _on_doffset_value_changed(value): - curve_terrain.deform_offest = value - update_meta_values() - -func _on_auto_paint_toggled(toggled_on): - gizmo.auto_terrain_paint = toggled_on - update_meta_values() - -func _on_iname_text_changed(new_text): - curve_terrain.terrain_image_name = new_text - update_meta_values() - -func _on_pradius_value_changed(value): - curve_terrain.paint_radius = value - update_meta_values() - -func _on_pfalloff_value_changed(value): - curve_terrain.paint_falloff = value - update_meta_values() - -func _on_pcolor_color_changed(color): - curve_terrain.paint_color = color - update_meta_values() - -func _on_bgcolor_color_changed(color): - curve_terrain.bg_color = color - update_meta_values() - - -func deform_tool_index_pressed(index:int): - var only_selected:bool=$tsv2/deform_tools.get("popup/item_0/checked") - if index==0: - $tsv2/deform_tools.set("popup/item_0/checked",not only_selected) - $tsv2/deform_tools.call_deferred("show_popup") - update_meta_values() - return - if index==1: - gizmo.deform(only_selected) - return - if index == 2: - gizmo.clear_deform(only_selected) - return - if index == 3: - gizmo.clear_deform_large(only_selected) - return - -func paint_tool_index_pressed(index:int): - var only_selected:bool=$tsv3/paint_tools.get("popup/item_0/checked") - if index==0: - $tsv3/paint_tools.set("popup/item_0/checked",not only_selected) - $tsv3/paint_tools.call_deferred("show_popup") - update_meta_values() - return - if index==1: - gizmo.paint(only_selected) - return - if index == 2: - gizmo.clear_paint(only_selected) - return - if index == 3: - gizmo.clear_paint_large(only_selected) - return - -func _on_auto_g_modify_toggled(toggled_on): - gizmo.auto_grass_modify = toggled_on - update_meta_values() - -###### GRASS -func load_grass_settings(): - var grass_count:int = 0 - var terrain_children:Array = curve_terrain.terrain.get_children() - var settings:Dictionary - for grass in terrain_children: - if not(grass is MGrass): - continue - grass_count+=1 - $g_container/grass_list.add_item(grass.name,grass_icon_tex) - if grass.has_meta("curve_terrain"): - settings[grass.name] = grass.get_meta("curve_terrain") - set_grass_items_visibilty(grass_count!=0) - gizmo.grass_modify_settings = settings - if grass_count !=0 : - $g_container/grass_list.select(0) - _on_grass_list_item_selected(0) - -func _on_grass_list_item_selected(index): - ### This because of gradius_value_changed and goffset_value_changed - ### their siginal conflict this signal - ### but making this call_deferred correct that - ### I hope this does not break in future - call_deferred("change_active_grass",index) - -func change_active_grass(index): - var grass_name = $g_container/grass_list.get_item_text(index) - if not curve_terrain.terrain.has_node(grass_name): - printerr("Can not find "+grass_name) - return - active_grass = curve_terrain.terrain.get_node(grass_name) - if not gizmo.grass_modify_settings.has(grass_name): - ## restoring default setting - $g_container/gh/gactive.set_pressed_no_signal(false) - $g_container/gh/gadd.set_pressed_no_signal(false) - $g_container/ov7/gradius.set_value_no_signal(6.0) - $g_container/ov6/goffset.set_value_no_signal(0.0) - return - var g_setting:Dictionary= gizmo.grass_modify_settings[grass_name] - $g_container/gh/gactive.set_pressed_no_signal(g_setting["active"]) - $g_container/gh/gadd.set_pressed_no_signal(g_setting["add"]) - $g_container/ov7/gradius.set_value_no_signal(g_setting["radius"]) - $g_container/ov6/goffset.set_value_no_signal(g_setting["offset"]) - -func upate_grass_meta(): - if not active_grass: - printerr("No active grass") - return - if not is_instance_valid(active_grass): - printerr("Active grass is not valid") - return - var g_setting:Dictionary - g_setting["active"] = $g_container/gh/gactive.button_pressed - g_setting["add"] = $g_container/gh/gadd.button_pressed - g_setting["radius"] = $g_container/ov7/gradius.value - g_setting["offset"] = $g_container/ov6/goffset.value - gizmo.grass_modify_settings[active_grass.name] = g_setting - active_grass.set_meta("curve_terrain",g_setting) - print(active_grass.name ," update offset ",g_setting["offset"]) - -func set_grass_items_visibilty(input:bool): - ## change the visibilty of nodes not container - ## to not collaps with the main terrain visbilty - var childer:Array= $g_container.get_children() - for c in childer: - c.visible = input - -func _on_gradius_value_changed(value): - upate_grass_meta() - -func _on_goffset_value_changed(value): - upate_grass_meta() - - -func grass_tool_index_pressed(index:int): - var only_selected:bool=$g_container/gt/grass_tool.get("popup/item_0/checked") - if index==0: - $g_container/gt/grass_tool.set("popup/item_0/checked",not only_selected) - $g_container/gt/grass_tool.call_deferred("show_popup") - update_meta_values() - return - if index==1: - gizmo.modify_grass(only_selected) - return - if index == 2: - gizmo.clear_grass(only_selected) - return - if index == 3: - gizmo.clear_grass_large(only_selected) - return - - diff --git a/addons/m_terrain/inspector/gui/curve_terrain.tscn b/addons/m_terrain/inspector/gui/curve_terrain.tscn deleted file mode 100644 index 607ddac..0000000 --- a/addons/m_terrain/inspector/gui/curve_terrain.tscn +++ /dev/null @@ -1,287 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://br05oyiapuwpf"] - -[ext_resource type="Script" path="res://addons/m_terrain/inspector/gui/curve_terrain.gd" id="1_txmoh"] -[ext_resource type="Texture2D" uid="uid://bsdfn2yec6vtv" path="res://addons/m_terrain/icons/terrain_icon.png" id="2_n3lna"] -[ext_resource type="Texture2D" uid="uid://c08s0xlu8tted" path="res://addons/m_terrain/icons/brush_icon.png" id="3_bwp6e"] -[ext_resource type="Texture2D" uid="uid://d03ukmldfnxs3" path="res://addons/m_terrain/icons/foilage_icon.png" id="4_ftpdb"] - -[node name="curve_terrain" type="VBoxContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_txmoh") - -[node name="panle_open" type="CheckButton" parent="."] -layout_mode = 2 -text = "Terrain" - -[node name="HSeparator3" type="HSeparator" parent="."] -layout_mode = 2 - -[node name="tsv" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="tilt" type="CheckBox" parent="tsv"] -layout_mode = 2 -text = "Tilt" - -[node name="scale" type="CheckBox" parent="tsv"] -layout_mode = 2 -text = "Scale" - -[node name="tsv2" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="auto_deform" type="CheckBox" parent="tsv2"] -layout_mode = 2 -text = "Auto deform" - -[node name="deform_tools" type="MenuButton" parent="tsv2"] -custom_minimum_size = Vector2(30, 0) -layout_mode = 2 -text = "Deform Tools" -icon = ExtResource("2_n3lna") -flat = false -item_count = 4 -popup/item_0/text = "only selected" -popup/item_0/checkable = 1 -popup/item_0/checked = true -popup/item_0/id = 0 -popup/item_1/text = "Deform" -popup/item_1/id = 1 -popup/item_2/text = "clear" -popup/item_2/id = 2 -popup/item_3/text = "clear large" -popup/item_3/id = 3 - -[node name="tlv" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="tlv"] -layout_mode = 2 -text = "Terrain Layer " - -[node name="tlayer" type="LineEdit" parent="tlv"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="rv" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="rv"] -layout_mode = 2 -text = "Deform Radius " - -[node name="dradius" type="SpinBox" parent="rv"] -layout_mode = 2 -size_flags_horizontal = 3 -step = 0.01 - -[node name="fv" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="fv"] -layout_mode = 2 -text = "Deform Falloff " - -[node name="dfalloff" type="SpinBox" parent="fv"] -layout_mode = 2 -size_flags_horizontal = 3 -step = 0.01 - -[node name="ov" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="ov"] -layout_mode = 2 -text = "Deform Ofsset " - -[node name="doffset" type="SpinBox" parent="ov"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = -500.0 -max_value = 500.0 -step = 0.01 - -[node name="HSeparator" type="HSeparator" parent="."] -layout_mode = 2 - -[node name="tsv3" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="auto_paint" type="CheckBox" parent="tsv3"] -layout_mode = 2 -text = "Auto Paint" - -[node name="paint_tools" type="MenuButton" parent="tsv3"] -custom_minimum_size = Vector2(30, 0) -layout_mode = 2 -text = "Paint Tools" -icon = ExtResource("3_bwp6e") -flat = false -item_count = 4 -popup/item_0/text = "only selected" -popup/item_0/checkable = 1 -popup/item_0/checked = true -popup/item_0/id = 0 -popup/item_1/text = "Paint" -popup/item_1/id = 1 -popup/item_2/text = "clear" -popup/item_2/id = 2 -popup/item_3/text = "clear large" -popup/item_3/id = 3 - -[node name="ov2" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="ov2"] -layout_mode = 2 -text = "Image Name " - -[node name="iname" type="LineEdit" parent="ov2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="ov3" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="ov3"] -layout_mode = 2 -text = "Paint radius " - -[node name="pradius" type="SpinBox" parent="ov3"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = -500.0 -max_value = 500.0 -step = 0.01 - -[node name="ov5" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="ov5"] -layout_mode = 2 -text = "Paint Falloff " - -[node name="pfalloff" type="SpinBox" parent="ov5"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = -500.0 -max_value = 500.0 -step = 0.01 - -[node name="ov4" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="ov4"] -layout_mode = 2 -text = "Paint Color " - -[node name="pcolor" type="ColorPickerButton" parent="ov4"] -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 - -[node name="Label2" type="Label" parent="ov4"] -layout_mode = 2 -text = "BG Color " - -[node name="bgcolor" type="ColorPickerButton" parent="ov4"] -custom_minimum_size = Vector2(32, 0) -layout_mode = 2 - -[node name="grass_start" type="HSeparator" parent="."] -layout_mode = 2 - -[node name="g_container" type="VBoxContainer" parent="."] -layout_mode = 2 - -[node name="gt" type="HBoxContainer" parent="g_container"] -layout_mode = 2 - -[node name="auto_g_modify" type="CheckBox" parent="g_container/gt"] -layout_mode = 2 -text = "Auto Modify" - -[node name="grass_tool" type="MenuButton" parent="g_container/gt"] -layout_mode = 2 -text = "Grass Tool" -icon = ExtResource("4_ftpdb") -flat = false -item_count = 4 -popup/item_0/text = "Only Selected" -popup/item_0/checkable = 1 -popup/item_0/checked = true -popup/item_0/id = 0 -popup/item_1/text = "modify" -popup/item_1/id = 1 -popup/item_2/text = "clear" -popup/item_2/id = 2 -popup/item_3/text = "clear large" -popup/item_3/id = 3 - -[node name="grass_list" type="ItemList" parent="g_container"] -custom_minimum_size = Vector2(0, 72) -layout_mode = 2 -max_columns = 4 - -[node name="gh" type="HBoxContainer" parent="g_container"] -layout_mode = 2 - -[node name="gactive" type="CheckBox" parent="g_container/gh"] -layout_mode = 2 -text = "Active" - -[node name="gadd" type="CheckBox" parent="g_container/gh"] -layout_mode = 2 -text = "Add Grass" - -[node name="ov7" type="HBoxContainer" parent="g_container"] -layout_mode = 2 - -[node name="Label" type="Label" parent="g_container/ov7"] -layout_mode = 2 -text = "Radius " - -[node name="gradius" type="SpinBox" parent="g_container/ov7"] -layout_mode = 2 -size_flags_horizontal = 3 -max_value = 500.0 -step = 0.01 -update_on_text_changed = true - -[node name="ov6" type="HBoxContainer" parent="g_container"] -layout_mode = 2 - -[node name="Label" type="Label" parent="g_container/ov6"] -layout_mode = 2 -text = "Start Offset" - -[node name="goffset" type="SpinBox" parent="g_container/ov6"] -layout_mode = 2 -size_flags_horizontal = 3 -max_value = 500.0 -step = 0.01 -update_on_text_changed = true - -[connection signal="toggled" from="panle_open" to="." method="_on_panle_open_toggled"] -[connection signal="toggled" from="tsv/tilt" to="." method="_on_tilt_toggled"] -[connection signal="toggled" from="tsv/scale" to="." method="_on_scale_toggled"] -[connection signal="toggled" from="tsv2/auto_deform" to="." method="_on_auto_deform_toggled"] -[connection signal="text_changed" from="tlv/tlayer" to="." method="_on_tlayer_text_changed"] -[connection signal="value_changed" from="rv/dradius" to="." method="_on_dradius_value_changed"] -[connection signal="value_changed" from="fv/dfalloff" to="." method="_on_dfalloff_value_changed"] -[connection signal="value_changed" from="ov/doffset" to="." method="_on_doffset_value_changed"] -[connection signal="toggled" from="tsv3/auto_paint" to="." method="_on_auto_paint_toggled"] -[connection signal="text_changed" from="ov2/iname" to="." method="_on_iname_text_changed"] -[connection signal="value_changed" from="ov3/pradius" to="." method="_on_pradius_value_changed"] -[connection signal="value_changed" from="ov5/pfalloff" to="." method="_on_pfalloff_value_changed"] -[connection signal="color_changed" from="ov4/pcolor" to="." method="_on_pcolor_color_changed"] -[connection signal="color_changed" from="ov4/bgcolor" to="." method="_on_bgcolor_color_changed"] -[connection signal="toggled" from="g_container/gt/auto_g_modify" to="." method="_on_auto_g_modify_toggled"] -[connection signal="item_selected" from="g_container/grass_list" to="." method="_on_grass_list_item_selected"] -[connection signal="pressed" from="g_container/gh/gactive" to="." method="upate_grass_meta"] -[connection signal="pressed" from="g_container/gh/gadd" to="." method="upate_grass_meta"] -[connection signal="value_changed" from="g_container/ov7/gradius" to="." method="_on_gradius_value_changed"] -[connection signal="value_changed" from="g_container/ov6/goffset" to="." method="_on_goffset_value_changed"] diff --git a/addons/m_terrain/inspector/gui/mpath_inspector_gui.gd b/addons/m_terrain/inspector/gui/mpath_inspector_gui.gd deleted file mode 100644 index 8ba38b7..0000000 --- a/addons/m_terrain/inspector/gui/mpath_inspector_gui.gd +++ /dev/null @@ -1,182 +0,0 @@ -@tool -extends Control - - -@onready var point_count_lable:=$point_count_lable - -var is_started:=false - -var gizmo:EditorNode3DGizmoPlugin - -var current_path:MPath -var current_curve:MCurve -var current_curve_mesh:MCurveMesh=null - -var connection_mode :=true -var mesh_mode:=true - -var child_selector:OptionButton -var items:ItemList -var connection_tab:Button -var intersection_tab:Button -func start(): - if is_started: return - is_started = true - child_selector = $child_selctor - items = $itemlist - items.item_selected.connect(Callable(self,"item_selected")) - connection_tab = $HBoxContainer/connection_tab - intersection_tab = $HBoxContainer/intersection_tab - connection_tab.connect("pressed",Callable(self,"change_tab").bind(true)) - intersection_tab.connect("pressed",Callable(self,"change_tab").bind(false)) - $HBoxContainer2/clear_override.connect("button_up",Callable(self,"clear_override")) - $HBoxContainer2/Remove_mesh.connect("button_up",Callable(self,"remove_mesh")) - $mesh_mode_option.connect("item_selected",Callable(self,"mesh_mode_selected")) - if not gizmo: printerr("Gizmo is NULL") - gizmo.connect("selection_changed",Callable(self,"update_curve_item_selection")) - -func set_path(input:MPath)->void: - start() - current_path = input - current_curve = current_path.curve - child_selector.clear() - child_selector.add_item("ovveride") - if not input: return - var children = input.get_children() - for child in children: - if child is MCurveMesh: - child_selector.add_item(child.name) - -func _on_child_selctor_item_selected(index): - set_curve_mesh_gui_visible(false) - if index==0 or not current_path: - return - var cname = child_selector.get_item_text(index) - var child = current_path.get_node(cname) - if not child: return - if child is MCurveMesh: - set_curve_mesh_gui_visible(true) - current_curve_mesh = child - update_curve_mesh_items() - -func set_curve_mesh_gui_visible(input:bool): - $HBoxContainer.visible = input - $HBoxContainer2.visible = input - $mesh_mode_option.visible = input - $itemlist.visible = input - -func change_tab(_conn_mod:bool): - connection_tab.button_pressed = _conn_mod - intersection_tab.button_pressed = not _conn_mod - if _conn_mod == connection_mode: return - connection_mode = _conn_mod - update_curve_mesh_items() - -func update_curve_mesh_items(): - if not current_curve_mesh: return - items.clear() - var ed:=EditorScript.new() - var preview:EditorResourcePreview= ed.get_editor_interface().get_resource_previewer() - var count:int = 0 - if not mesh_mode: - for mat in current_curve_mesh.materials: - if not mat: - items.add_item("empty") - continue - var mname:String = mat.get_path().get_file().get_basename() - if mname.is_empty(): - mname = str(count) - items.add_item(mname) - preview.queue_edited_resource_preview(mat,self,"set_icon",count) - count+=1 - update_curve_item_selection() - return - if connection_mode:count = current_curve_mesh.meshes.size() - else:count = current_curve_mesh.intersections.size() - for i in range(count): - var mlod:MMeshLod - if connection_mode: mlod = current_curve_mesh.meshes[i] - else: mlod = current_curve_mesh.intersections[i].mesh - if not mlod: - items.add_item("empty") - continue - var m:Mesh = mlod.meshes[0] - if not m: - items.add_item("empty") - continue - var mname:String = m.get_path().get_file().get_basename() - if mname.is_empty(): - mname = str(i) - items.add_item(mname) - preview.queue_edited_resource_preview(m,self,"set_icon",i) - update_curve_item_selection() - -# must be called after update_curve_mesh_items() -func update_curve_item_selection(): - if not current_curve_mesh or not gizmo: return - var ids:PackedInt64Array = get_selected_ids() - var ov_index:int=-100 # some invalide number - for cid in ids: - var current_index:int - if mesh_mode: current_index = current_curve_mesh.override.get_mesh_override(cid) - else: current_index = current_curve_mesh.override.get_material_override(cid) - if ov_index == -100: ov_index = current_index - if current_index != ov_index: ## multiple connection is selected with multiple ovverride value - ov_index = -1 - break - ### Up to this point connection ovveride is same - ov_index = current_index - $HBoxContainer2/Remove_mesh.button_pressed = connection_mode and ov_index == -2 - if ov_index < 0: - items.deselect_all() - else: - items.select(ov_index) - -func set_icon(path:String,preview:Texture2D,thumnail_preview:Texture2D,index:int): - items.set_item_icon(index,preview) - -func item_selected(index:int): - if not is_instance_valid(current_curve_mesh) or not gizmo: return - var ids:PackedInt64Array = get_selected_ids() - for cid in ids: - if mesh_mode: - current_curve_mesh.override.set_mesh_override(cid,index) - else: - current_curve_mesh.override.set_material_override(cid,index) - update_curve_item_selection() - -func clear_override(): - if not is_instance_valid(current_curve_mesh) or not gizmo: return - var ids:PackedInt64Array = get_selected_ids() - if mesh_mode: - for cid in ids: - current_curve_mesh.override.clear_mesh_override(cid) - else: - for cid in ids: - current_curve_mesh.override.clear_material_override(cid) - update_curve_item_selection() - -func remove_mesh(): - if not is_instance_valid(current_curve_mesh) or not gizmo: return - var ids:PackedInt64Array = get_selected_ids() - - for cid in ids: - current_curve_mesh.override.set_mesh_override(cid,-2) - update_curve_item_selection() - -func get_selected_ids()->PackedInt64Array: - if connection_mode: - return gizmo.get_selected_connections() - else: - return gizmo.get_selected_points64() - -func mesh_mode_selected(index:int): - mesh_mode = index == 0 - update_curve_mesh_items() - - -func _on_update_info_timer_timeout(): - var point_count:int = 0 - if current_curve: - point_count = current_curve.get_points_count() - point_count_lable.text = "Point count " + str(point_count) diff --git a/addons/m_terrain/inspector/gui/mpath_inspector_gui.tscn b/addons/m_terrain/inspector/gui/mpath_inspector_gui.tscn deleted file mode 100644 index bf0abe5..0000000 --- a/addons/m_terrain/inspector/gui/mpath_inspector_gui.tscn +++ /dev/null @@ -1,93 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://d4l2pvir8hm8l"] - -[ext_resource type="Script" path="res://addons/m_terrain/inspector/gui/mpath_inspector_gui.gd" id="1_jv20c"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_jefn3"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_t7soo"] -bg_color = Color(0.6, 0, 0, 1) - -[node name="mpath_inspector_gui" type="VBoxContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_jv20c") - -[node name="point_count_lable" type="Label" parent="."] -layout_mode = 2 -text = "Point count: " - -[node name="HSeparator2" type="HSeparator" parent="."] -layout_mode = 2 - -[node name="child_selctor" type="OptionButton" parent="."] -layout_mode = 2 -item_count = 2 -popup/item_0/text = "None" -popup/item_0/id = 0 -popup/item_1/text = "Other_child" -popup/item_1/id = 1 - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -visible = false -layout_mode = 2 - -[node name="connection_tab" type="Button" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -theme_override_styles/normal = SubResource("StyleBoxFlat_jefn3") -toggle_mode = true -button_pressed = true -text = "Connection" - -[node name="intersection_tab" type="Button" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -theme_override_styles/normal = SubResource("StyleBoxFlat_jefn3") -toggle_mode = true -text = "Intersection" - -[node name="HSeparator" type="HSeparator" parent="."] -layout_mode = 2 - -[node name="mesh_mode_option" type="OptionButton" parent="."] -visible = false -layout_mode = 2 -item_count = 2 -selected = 0 -popup/item_0/text = "mesh" -popup/item_0/id = 0 -popup/item_1/text = "material" -popup/item_1/id = 1 - -[node name="HBoxContainer2" type="HBoxContainer" parent="."] -visible = false -layout_mode = 2 - -[node name="clear_override" type="Button" parent="HBoxContainer2"] -layout_mode = 2 -text = "restore default" - -[node name="Remove_mesh" type="Button" parent="HBoxContainer2"] -layout_mode = 2 -theme_override_styles/pressed = SubResource("StyleBoxFlat_t7soo") -toggle_mode = true -text = "Remove mesh" - -[node name="itemlist" type="ItemList" parent="."] -visible = false -custom_minimum_size = Vector2(0, 260) -layout_mode = 2 -allow_reselect = true - -[node name="update_info_timer" type="Timer" parent="."] -wait_time = 0.752 -autostart = true - -[node name="HSeparator4" type="HSeparator" parent="."] -layout_mode = 2 - -[connection signal="item_selected" from="child_selctor" to="." method="_on_child_selctor_item_selected"] -[connection signal="timeout" from="update_info_timer" to="." method="_on_update_info_timer_timeout"] diff --git a/addons/m_terrain/inspector/mpath.gd b/addons/m_terrain/inspector/mpath.gd deleted file mode 100644 index 7ddb618..0000000 --- a/addons/m_terrain/inspector/mpath.gd +++ /dev/null @@ -1,32 +0,0 @@ -extends EditorInspectorPlugin - -var gizmo:EditorNode3DGizmoPlugin - -var gui_res = preload("res://addons/m_terrain/inspector/gui/mpath_inspector_gui.tscn") -var gui -var curve_terrain_res = preload("res://addons/m_terrain/inspector/gui/curve_terrain.tscn") -var curve_terrain:Control - -func _can_handle(object): - return object is MPath - -func _parse_begin(object): - if not(object is MPath) or not object or not object.curve: - return - if not gui: - gui = gui_res.instantiate() - add_custom_control(gui) - gui.gizmo = gizmo - gui.set_path(object) - ## Curve terrain - if gizmo.tools.get_active_mterrain(): - if not curve_terrain: - curve_terrain = curve_terrain_res.instantiate() - add_custom_control(curve_terrain) - gizmo.curve_terrain.terrain = gizmo.tools.get_active_mterrain() - curve_terrain.start_curve_terrain(gizmo,object) - - - - - diff --git a/addons/m_terrain/libs/MTerrain.gdextension b/addons/m_terrain/libs/MTerrain.gdextension deleted file mode 100644 index 65faa1b..0000000 --- a/addons/m_terrain/libs/MTerrain.gdextension +++ /dev/null @@ -1,33 +0,0 @@ -[configuration] - -entry_symbol = "test_library_init" -compatibility_minimum = 4.1 - -[libraries] -macos.debug = "res://addons/m_terrain/libs/libMTerrain.macos.template_debug.universal.dylib" -macos.release = "res://addons/m_terrain/libs/libMTerrain.macos.template_release.universal.dylib" -linux.debug.x86_64 = "res://addons/m_terrain/libs/libMTerrain.linux.template_debug.x86_64.so" -linux.release.x86_64 = "res://addons/m_terrain/libs/libMTerrain.linux.template_release.x86_64.so" -linux.debug.x86_32 = "res://addons/m_terrain/libs/libMTerrain.linux.template_debug.x86_32.so" -linux.release.x86_32 = "res://addons/m_terrain/libs/libMTerrain.linux.template_release.x86_32.so" -windows.debug.x86_64 = "res://addons/m_terrain/libs/libMTerrain.windows.template_debug.x86_64.dll" -windows.release.x86_64 = "res://addons/m_terrain/libs/libMTerrain.windows.template_release.x86_64.dll" -windows.debug.x86_32 = "res://addons/m_terrain/libs/libMTerrain.windows.template_debug.x86_32.dll" -windows.release.x86_32 = "res://addons/m_terrain/libs/libMTerrain.windows.template_release.x86_32.dll" -android.debug.arm64 = "res://addons/m_terrain/libs/libMTerrain.android.template_debug.arm64.so" -android.release.arm64 = "res://addons/m_terrain/libs/libMTerrain.android.template_release.arm64.so" - - -[icons] - -MTerrain = "res://addons/m_terrain/icons/M-terrain_icon.png" -MGrass = "res://addons/m_terrain/icons/foilage_icon.png" -MNavigationRegion3D = "res://addons/m_terrain/icons/MNavigationRegion3D.png" -MObstacle = "res://addons/m_terrain/icons/obstacle_icon.png" -MOctMesh = "res://addons/m_terrain/icons/MOctMesh.svg" -MOctree = "res://addons/m_terrain/icons/MOctree.svg" -MPath = "res://addons/m_terrain/icons/MPath.svg" -MCurve = "res://addons/m_terrain/icons/MCurve.svg" -MMeshLod = "res://addons/m_terrain/icons/MMeshLod.svg" -MCurveMesh = "res://addons/m_terrain/icons/MCurveMesh.svg" -MIntersection = "res://addons/m_terrain/icons/MIntersection.svg" diff --git a/addons/m_terrain/libs/libMTerrain.android.template_debug.arm64.so b/addons/m_terrain/libs/libMTerrain.android.template_debug.arm64.so deleted file mode 100644 index a5554e1..0000000 Binary files a/addons/m_terrain/libs/libMTerrain.android.template_debug.arm64.so and /dev/null differ diff --git a/addons/m_terrain/libs/libMTerrain.android.template_release.arm64.so b/addons/m_terrain/libs/libMTerrain.android.template_release.arm64.so deleted file mode 100644 index 07a72e4..0000000 Binary files a/addons/m_terrain/libs/libMTerrain.android.template_release.arm64.so and /dev/null differ diff --git a/addons/m_terrain/libs/libMTerrain.linux.template_debug.x86_64.so b/addons/m_terrain/libs/libMTerrain.linux.template_debug.x86_64.so deleted file mode 100644 index ed62d2c..0000000 Binary files a/addons/m_terrain/libs/libMTerrain.linux.template_debug.x86_64.so and /dev/null differ diff --git a/addons/m_terrain/libs/libMTerrain.linux.template_release.x86_64.so b/addons/m_terrain/libs/libMTerrain.linux.template_release.x86_64.so deleted file mode 100644 index e3f5db0..0000000 Binary files a/addons/m_terrain/libs/libMTerrain.linux.template_release.x86_64.so and /dev/null differ diff --git a/addons/m_terrain/libs/libMTerrain.windows.template_debug.x86_64.dll b/addons/m_terrain/libs/libMTerrain.windows.template_debug.x86_64.dll deleted file mode 100644 index ee0bd48..0000000 Binary files a/addons/m_terrain/libs/libMTerrain.windows.template_debug.x86_64.dll and /dev/null differ diff --git a/addons/m_terrain/libs/libMTerrain.windows.template_release.x86_64.dll b/addons/m_terrain/libs/libMTerrain.windows.template_release.x86_64.dll deleted file mode 100644 index b5ff0bb..0000000 Binary files a/addons/m_terrain/libs/libMTerrain.windows.template_release.x86_64.dll and /dev/null differ diff --git a/addons/m_terrain/m_terrain.gd b/addons/m_terrain/m_terrain.gd deleted file mode 100644 index 20d62ab..0000000 --- a/addons/m_terrain/m_terrain.gd +++ /dev/null @@ -1,284 +0,0 @@ -@tool -extends EditorPlugin -var version:String="0.15.0" - -var tools= null - -var current_main_screen_name ="" - -var tsnap = null - -var action="" - -var current_window_info=null - -var gizmo_moctmesh -var gizmo_mpath - -var inspector_mpath - -var timer = Timer.new() -var needs_restart = false - -func check_restart(): - if GDExtensionManager.is_extension_loaded("res://addons/m_terrain/libs/MTerrain.gdextension"): - if needs_restart: - EditorInterface.restart_editor() - else: return true - else: - needs_restart = true - timer.start(0.5) - return false - -#region keyboard actions -var default_keyboard_actions - -const setting_path = 'addons/m_terrain/keymap/' - -func add_keymap(force_default = false): - set_default_keymap() - for action in default_keyboard_actions: - var path = setting_path + action.name - if force_default or not ProjectSettings.has_setting(path): - var a = InputEventKey.new() - a.keycode = action.keycode - a.pressed = action.pressed - if "shift" in action.keys(): - a.shift_pressed = action.shift - ProjectSettings.set_setting(path, a) - var e = ProjectSettings.get_setting(path) - if not InputMap.has_action(action.name): - InputMap.add_action(action.name) - for i in default_keyboard_actions.size(): - if default_keyboard_actions[i].name == action.name: - default_keyboard_actions[i].keycode = e.keycode - default_keyboard_actions[i].shift = e.shift_pressed - default_keyboard_actions[i].ctrl = e.ctrl_pressed - default_keyboard_actions[i].alt = e.alt_pressed - InputMap.action_add_event(action.name, e) - -func remove_keymap(): - for action in default_keyboard_actions: - InputMap.erase_action(action.name) -#endregion - -#region init and de-init -func _enter_tree(): - if Engine.is_editor_hint(): - timer.one_shot = true - timer.timeout.connect(check_restart) - add_child(timer) - timer.start(0.5) - if not check_restart(): return - - var main_screen = EditorInterface.get_editor_main_screen() - main_screen_changed.connect(_on_main_screen_changed) - - tools = load("res://addons/m_terrain/gui/mtools.tscn").instantiate() - tools.request_info_window.connect(show_info_window) - tools.request_import_window.connect(show_import_window) - tools.request_image_creator.connect(show_image_creator_window) - tools.edit_mode_changed.connect(select_object) - tools.undo_redo = get_undo_redo() - main_screen.add_child(tools) - - get_tree().node_added.connect(tools.on_node_modified) - get_tree().node_renamed.connect(tools.on_node_modified) - get_tree().node_removed.connect(tools.on_node_modified) - - tools.set_brush_decal( load("res://addons/m_terrain/gui/brush_decal.tscn").instantiate() ) - main_screen.add_child(tools.brush_decal) - - tools.set_mask_decal( load("res://addons/m_terrain/gui/mask_decal.tscn").instantiate() ) - main_screen.add_child(tools.mask_decal) - - tools.human_male = load("res://addons/m_terrain/gui/human_male.tscn").instantiate() - main_screen.add_child(tools.human_male) - tools.human_male.visible = false - - get_editor_interface().get_selection().selection_changed.connect(selection_changed) - - tsnap = load("res://addons/m_terrain/gui/tsnap.tscn").instantiate() - tsnap.pressed.connect(tsnap_pressed) - tsnap.visible = false - add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU,tsnap) - - ###### GIZMO - gizmo_moctmesh = load("res://addons/m_terrain/gizmos/moct_mesh_gizmo.gd").new() - gizmo_mpath = load("res://addons/m_terrain/gizmos/mpath_gizmo.gd").new() - add_node_3d_gizmo_plugin(gizmo_moctmesh) - gizmo_mpath.ur = get_undo_redo() - add_node_3d_gizmo_plugin(gizmo_mpath) - gizmo_mpath.set_gui(tools.mpath_gizmo_gui) - gizmo_mpath.tools = tools - #### Inspector - inspector_mpath = load("res://addons/m_terrain/inspector/mpath.gd").new() - inspector_mpath.gizmo = gizmo_mpath - add_inspector_plugin(inspector_mpath) - - add_keymap() - -func _ready() -> void: - EditorInterface.set_main_screen_editor("Script") - EditorInterface.set_main_screen_editor("3D") - -func _exit_tree(): - if Engine.is_editor_hint(): - timer.queue_free() - remove_keymap() - remove_tool_menu_item("MTerrain import/export") - remove_tool_menu_item("MTerrain image create/remove") - tools.brush_decal.queue_free() - tools.mask_decal.queue_free() - tsnap.queue_free() - tools.human_male.queue_free() - - get_tree().node_added.disconnect(tools.on_node_modified) - get_tree().node_renamed.disconnect(tools.on_node_modified) - get_tree().node_removed.disconnect(tools.on_node_modified) - tools.queue_free() - - ###### GIZMO - remove_node_3d_gizmo_plugin(gizmo_moctmesh) - remove_node_3d_gizmo_plugin(gizmo_mpath) - - ### Inspector - remove_inspector_plugin(inspector_mpath) -#endregion - -func _on_main_screen_changed(screen_name): - current_main_screen_name = screen_name - selection_changed() - -#select_object is called when tools changes edit mode -func select_object(object, mode): - EditorInterface.get_selection().clear() - EditorInterface.get_selection().add_node(object) - -func selection_changed(): - if not tools or not is_instance_valid(EditorInterface.get_edited_scene_root()): return - - var selection = get_editor_interface().get_selection().get_selected_nodes() - - if selection.size() != 1 or not current_main_screen_name == "3D": - tools.request_hide() - return - - tools.on_selection_changed(selection[0]) - - -func _handles(object): - if not Engine.is_editor_hint(): return false - if not current_main_screen_name == "3D": - tools.request_hide() - return false - - tsnap.visible = false - if tools.on_handles(object): - return true - tsnap.visible = is_instance_valid(tools.active_snap_object) - -func _forward_3d_gui_input(viewport_camera, event): - if not is_instance_valid(EditorInterface.get_edited_scene_root()): - return AFTER_GUI_INPUT_PASS - - if tools.forward_3d_gui_input(viewport_camera, event): - return AFTER_GUI_INPUT_STOP - else: - return AFTER_GUI_INPUT_PASS - -func tsnap_pressed(): - var terrains = tools.get_all_mterrain() - var active_terrain - for terrain in terrains: - if terrain.is_grid_created(): - active_terrain = terrain - break - if active_terrain and tools.active_snap_object: - var h:float = active_terrain.get_height(tools.active_snap_object.global_position) - tools.active_snap_object.global_position.y = h - -func show_import_window(): - var window = load("res://addons/m_terrain/gui/import_window.tscn").instantiate() - add_child(window) - window.init_export(tools.get_active_mterrain()) - -func show_image_creator_window(): - if tools.get_active_mterrain(): - var window = load("res://addons/m_terrain/gui/image_creator_window.tscn").instantiate() - add_child(window) - window.mterrain = tools.get_active_mterrain() - -func show_info_window(active_terrain = tools.get_active_mterrain()): - var is_grid_created = active_terrain.is_grid_created() - if is_instance_valid(current_window_info): - current_window_info.queue_free() - if not active_terrain is MTerrain: - push_error("no active mterrain for info window") - current_window_info = load("res://addons/m_terrain/gui/terrain_info.tscn").instantiate() - add_child(current_window_info) - if is_grid_created: - active_terrain.remove_grid() - current_window_info.generate_info(active_terrain,version, default_keyboard_actions) - current_window_info.mtools = tools - current_window_info.keymap_changed.connect(update_keymap) - current_window_info.restore_default_keymap_requested.connect(func(): - add_keymap(true) - current_window_info.create_keymapping_interface(default_keyboard_actions) - ) - if is_grid_created: - current_window_info.tree_exiting.connect(active_terrain.create_grid) - -func set_default_keymap(): - default_keyboard_actions = [ - {"name": "mterrain_brush_size_increase", "keycode": KEY_BRACKETRIGHT, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_brush_size_decrease", "keycode": KEY_BRACKETLEFT, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - - {"name": "mterrain_mask_size_increase", "keycode": KEY_PERIOD, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_mask_size_decrease", "keycode": KEY_COMMA, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_mask_rotate_clockwise", "keycode": KEY_L, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_mask_rotate_counter_clockwise", "keycode": KEY_K, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_mask_rotation_reset", "keycode": KEY_SEMICOLON, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - - {"name": "mterrain_walk_forward", "keycode": KEY_W, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_walk_backward", "keycode": KEY_S, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_walk_left", "keycode": KEY_A, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mterrain_walk_right", "keycode": KEY_D, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - - - {"name": "mpath_toggle_mode", "keycode": KEY_QUOTELEFT, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_toggle_mirror", "keycode": KEY_M, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_toggle_mirror_length", "keycode": KEY_L, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - - {"name": "mpath_validate", "keycode": KEY_P, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_select_linked", "keycode": KEY_L, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_swap_points", "keycode": KEY_T, "pressed": true, "shift": true, "ctrl": false, "alt": false}, - {"name": "mpath_toggle_connection", "keycode": KEY_T, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_remove_point", "keycode": KEY_BACKSPACE, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_disconnect_point", "keycode": KEY_B, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_connect_point", "keycode": KEY_C, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_tilt_mode", "keycode": KEY_R, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_scale_mode", "keycode": KEY_K, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_lock_zy", "keycode": KEY_X, "pressed": true, "shift": true, "ctrl": false, "alt": false}, - {"name": "mpath_lock_xz", "keycode": KEY_Y, "pressed": true, "shift": true, "ctrl": false, "alt": false}, - {"name": "mpath_lock_xy", "keycode": KEY_Z, "pressed": true, "shift": true, "ctrl": false, "alt": false}, - {"name": "mpath_lock_x", "keycode": KEY_X, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_lock_y", "keycode": KEY_Y, "pressed": true, "shift": false, "ctrl": false, "alt": false}, - {"name": "mpath_lock_z", "keycode": KEY_Z, "pressed": true, "shift": false, "ctrl": false, "alt": false }, - ] -func update_keymap(who, keycode, ctrl, alt, shift): - var a = InputEventKey.new() - a.keycode = keycode - a.pressed = true - a.ctrl_pressed = ctrl - a.alt_pressed = alt - a.shift_pressed = shift - ProjectSettings.set_setting(setting_path + who, a) - InputMap.action_erase_events(who) - InputMap.action_add_event(who, a) - for i in default_keyboard_actions.size(): - if default_keyboard_actions[i].name == who: - default_keyboard_actions[i].keycode = keycode - default_keyboard_actions[i].ctrl = ctrl - default_keyboard_actions[i].alt = alt - default_keyboard_actions[i].shift = shift diff --git a/addons/m_terrain/plugin.cfg b/addons/m_terrain/plugin.cfg deleted file mode 100644 index 6cad5cb..0000000 --- a/addons/m_terrain/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="MTerrain" -description="A simple terrain tool for Godot 4.1" -author="Mohsen Zare" -version="0.15.0" -script="m_terrain.gd" diff --git a/addons/m_terrain/shader_include/paint16.gdshaderinc b/addons/m_terrain/shader_include/paint16.gdshaderinc deleted file mode 100644 index a58c0a5..0000000 --- a/addons/m_terrain/shader_include/paint16.gdshaderinc +++ /dev/null @@ -1,21 +0,0 @@ -//Include this before Vertex function -vec4 get_indices16(in sampler2D _tex,out vec2 _weight){ - _weight = vec2(textureSize(_tex,0))*(region_uv - region_b); - ivec2 ipx_pos = ivec2(_weight); - _weight = fract(_weight); - vec4 o; - o.x = texelFetch(_tex,ipx_pos,0).r*15.0; - o.y = texelFetch(_tex,ipx_pos+ivec2(1,0),0).r*15.0; - o.z = texelFetch(_tex,ipx_pos+ivec2(0,1),0).r*15.0; - o.w = texelFetch(_tex,ipx_pos+ivec2(1,1),0).r*15.0; - return o; -} -vec4 get_texture16(in sampler2DArray _tex_arr,in lowp vec4 _indices,in vec2 _weight,in vec2 _uv){ - vec4 a00 = texture(_tex_arr,vec3(_uv,_indices.x)); - vec4 a01 = texture(_tex_arr,vec3(_uv,_indices.y)); - vec4 a10 = texture(_tex_arr,vec3(_uv,_indices.z)); - vec4 a11 = texture(_tex_arr,vec3(_uv,_indices.w)); - vec4 t = mix(a00,a01,_weight.x); - vec4 b = mix(a10,a11,_weight.x); - return mix(t,b,_weight.y); -} \ No newline at end of file diff --git a/addons/m_terrain/shader_include/paint256.gdshaderinc b/addons/m_terrain/shader_include/paint256.gdshaderinc deleted file mode 100644 index 131aed3..0000000 --- a/addons/m_terrain/shader_include/paint256.gdshaderinc +++ /dev/null @@ -1,21 +0,0 @@ -//Include this before Vertex function -vec4 get_indices256(in sampler2D _tex,out vec2 _weight){ - _weight = vec2(textureSize(_tex,0))*(region_uv - region_b); - ivec2 ipx_pos = ivec2(_weight); - _weight = fract(_weight); - vec4 o; - o.x = texelFetch(_tex,ipx_pos,0).r*255.0; - o.y = texelFetch(_tex,ipx_pos+ivec2(1,0),0).r*255.0; - o.z = texelFetch(_tex,ipx_pos+ivec2(0,1),0).r*255.0; - o.w = texelFetch(_tex,ipx_pos+ivec2(1,1),0).r*255.0; - return o; -} -vec4 get_texture256(in sampler2DArray _tex_arr,in lowp vec4 _indices,in vec2 _weight,in vec2 _uv){ - vec4 a00 = texture(_tex_arr,vec3(_uv,_indices.x)); - vec4 a01 = texture(_tex_arr,vec3(_uv,_indices.y)); - vec4 a10 = texture(_tex_arr,vec3(_uv,_indices.z)); - vec4 a11 = texture(_tex_arr,vec3(_uv,_indices.w)); - vec4 t = mix(a00,a01,_weight.x); - vec4 b = mix(a10,a11,_weight.x); - return mix(t,b,_weight.y); -} \ No newline at end of file diff --git a/addons/m_terrain/show_region.gdshader b/addons/m_terrain/show_region.gdshader deleted file mode 100644 index 12e839f..0000000 --- a/addons/m_terrain/show_region.gdshader +++ /dev/null @@ -1,35 +0,0 @@ -shader_type spatial; -render_mode unshaded; - - - -uniform sampler2D mterrain_heightmap:filter_nearest; -uniform sampler2D mterrain_normals:filter_nearest; - - -uniform vec3 region_world_position; -uniform float region_size; -uniform float region_a; -uniform float region_b; -uniform int min_lod; -varying vec3 world_pos; -varying vec2 region_uv; - -void vertex(){ - world_pos = (NODE_POSITION_WORLD + VERTEX); - region_uv = (world_pos.xz - region_world_position.xz)/region_size; - region_uv = region_uv*region_a + region_b; - VERTEX.y = texture(mterrain_heightmap, region_uv).r; - world_pos.y = VERTEX.y; - vec3 n = texture(mterrain_normals, region_uv).rgb; - n = fma(n,vec3(2.0),vec3(-1.0)); - NORMAL = n; - //Scale world uv for terrain texture - world_pos /= 100.0; - -} - -void fragment(){ - vec2 r = clamp(vec2(0.),vec2(1.),region_uv); - ALBEDO = vec3(r,0.0)*0.2; -} diff --git a/addons/m_terrain/start.gdshader b/addons/m_terrain/start.gdshader deleted file mode 100644 index 9f2952b..0000000 --- a/addons/m_terrain/start.gdshader +++ /dev/null @@ -1,32 +0,0 @@ -shader_type spatial; - - - -uniform sampler2D mterrain_heightmap:filter_nearest; -uniform sampler2D mterrain_normals:filter_nearest; - -uniform vec3 region_world_position; -uniform float region_size; -uniform float region_a; -uniform float region_b; -uniform int min_lod; -varying vec3 world_pos; -varying vec2 region_uv; - -void vertex(){ - world_pos = (NODE_POSITION_WORLD + VERTEX); - region_uv = (world_pos.xz - region_world_position.xz)/region_size; - region_uv = region_uv*region_a + region_b; - VERTEX.y = texture(mterrain_heightmap, region_uv).r; - world_pos.y = VERTEX.y; - vec3 n = texture(mterrain_normals, region_uv).rgb; - n.rb=fma(n.rb,vec2(2.0),vec2(-1.0)); - NORMAL = n; - //Scale world uv for terrain texture - world_pos /= 10.0; - -} - -void fragment(){ - ALBEDO = vec3(0.4); -} diff --git a/addons/m_terrain/start_material.res b/addons/m_terrain/start_material.res deleted file mode 100644 index a98abcf..0000000 Binary files a/addons/m_terrain/start_material.res and /dev/null differ diff --git a/addons/m_terrain/start_material_opengl.res b/addons/m_terrain/start_material_opengl.res deleted file mode 100644 index 73fdf3d..0000000 Binary files a/addons/m_terrain/start_material_opengl.res and /dev/null differ diff --git a/addons/m_terrain/start_opengl.gdshader b/addons/m_terrain/start_opengl.gdshader deleted file mode 100644 index d211f86..0000000 --- a/addons/m_terrain/start_opengl.gdshader +++ /dev/null @@ -1,32 +0,0 @@ -shader_type spatial; - - - -uniform sampler2D mterrain_heightmap:filter_nearest; -uniform sampler2D mterrain_normals:filter_nearest; - -uniform vec3 region_world_position; -uniform float region_size; -uniform float region_a; -uniform float region_b; -uniform int min_lod; -varying vec3 world_pos; -varying vec2 region_uv; - -void vertex(){ - world_pos = (NODE_POSITION_WORLD + VERTEX); - region_uv = (world_pos.xz - region_world_position.xz)/region_size; - region_uv = region_uv*region_a + region_b; - VERTEX.y = texture(mterrain_heightmap, region_uv).r; - world_pos.y = VERTEX.y; - vec3 n = texture(mterrain_normals, region_uv).rgb; - n.rb=n.rb*2.0 - 1.0; - NORMAL = n; - //Scale world uv for terrain texture - world_pos /= 10.0; - -} - -void fragment(){ - ALBEDO = vec3(0.4); -} diff --git a/addons/zylann.hterrain/LICENSE.md b/addons/zylann.hterrain/LICENSE.md deleted file mode 100644 index a71a954..0000000 --- a/addons/zylann.hterrain/LICENSE.md +++ /dev/null @@ -1,11 +0,0 @@ -HeightMap terrain for Godot Engine ------------------------------------- - -Copyright (c) 2016-2023 Marc Gilleron - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/addons/zylann.hterrain/doc/.gdignore b/addons/zylann.hterrain/doc/.gdignore deleted file mode 100644 index e69de29..0000000 diff --git a/addons/zylann.hterrain/doc/docs/images/alpha_blending_and_depth_blending.png b/addons/zylann.hterrain/doc/docs/images/alpha_blending_and_depth_blending.png deleted file mode 100644 index e26ecfa..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/alpha_blending_and_depth_blending.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/bad_array_blending.png b/addons/zylann.hterrain/doc/docs/images/bad_array_blending.png deleted file mode 100644 index 7cf6d49..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/bad_array_blending.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/brush_editor.png b/addons/zylann.hterrain/doc/docs/images/brush_editor.png deleted file mode 100644 index 6641352..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/brush_editor.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/channel_packer.png b/addons/zylann.hterrain/doc/docs/images/channel_packer.png deleted file mode 100644 index 1edd264..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/channel_packer.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/choose_bullet_physics.png b/addons/zylann.hterrain/doc/docs/images/choose_bullet_physics.png deleted file mode 100644 index 0ee70ae..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/choose_bullet_physics.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/color_painting.png b/addons/zylann.hterrain/doc/docs/images/color_painting.png deleted file mode 100644 index c8f7ad1..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/color_painting.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/data_directory_property.png b/addons/zylann.hterrain/doc/docs/images/data_directory_property.png deleted file mode 100644 index 29ecfc7..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/data_directory_property.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/default_terrain.png b/addons/zylann.hterrain/doc/docs/images/default_terrain.png deleted file mode 100644 index 106cedf..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/default_terrain.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/detail_layers.png b/addons/zylann.hterrain/doc/docs/images/detail_layers.png deleted file mode 100644 index c0e3975..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/detail_layers.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/dilation.png b/addons/zylann.hterrain/doc/docs/images/dilation.png deleted file mode 100644 index 820dbd2..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/dilation.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/erosion_slope.png b/addons/zylann.hterrain/doc/docs/images/erosion_slope.png deleted file mode 100644 index 698ac62..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/erosion_slope.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/erosion_steps.png b/addons/zylann.hterrain/doc/docs/images/erosion_steps.png deleted file mode 100644 index 9498f70..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/erosion_steps.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/generator.png b/addons/zylann.hterrain/doc/docs/images/generator.png deleted file mode 100644 index 44012b6..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/generator.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/gimp_png_preserve_colors.png b/addons/zylann.hterrain/doc/docs/images/gimp_png_preserve_colors.png deleted file mode 100644 index c1a1729..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/gimp_png_preserve_colors.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/grass_models.png b/addons/zylann.hterrain/doc/docs/images/grass_models.png deleted file mode 100644 index 2e9370f..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/grass_models.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/hole_painting.png b/addons/zylann.hterrain/doc/docs/images/hole_painting.png deleted file mode 100644 index c9ad329..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/hole_painting.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/ignore_tools_on_export.png b/addons/zylann.hterrain/doc/docs/images/ignore_tools_on_export.png deleted file mode 100644 index 702facd..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/ignore_tools_on_export.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/importer.png b/addons/zylann.hterrain/doc/docs/images/importer.png deleted file mode 100644 index 84f372f..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/importer.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/inspector_texture_set.png b/addons/zylann.hterrain/doc/docs/images/inspector_texture_set.png deleted file mode 100644 index 3cca8f8..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/inspector_texture_set.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/inspector_texture_set_save.png b/addons/zylann.hterrain/doc/docs/images/inspector_texture_set_save.png deleted file mode 100644 index e4c48a1..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/inspector_texture_set_save.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/lod_geometry.png b/addons/zylann.hterrain/doc/docs/images/lod_geometry.png deleted file mode 100644 index 4b898be..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/lod_geometry.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/lookdev_grass.png b/addons/zylann.hterrain/doc/docs/images/lookdev_grass.png deleted file mode 100644 index 3c5c939..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/lookdev_grass.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/lookdev_menu.png b/addons/zylann.hterrain/doc/docs/images/lookdev_menu.png deleted file mode 100644 index 17b61c8..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/lookdev_menu.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/lots_of_textures_blending.png b/addons/zylann.hterrain/doc/docs/images/lots_of_textures_blending.png deleted file mode 100644 index 0ef702b..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/lots_of_textures_blending.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/low_poly.png b/addons/zylann.hterrain/doc/docs/images/low_poly.png deleted file mode 100644 index d518309..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/low_poly.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/normalmap_conventions.png b/addons/zylann.hterrain/doc/docs/images/normalmap_conventions.png deleted file mode 100644 index ef9e4b1..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/normalmap_conventions.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/overview.png b/addons/zylann.hterrain/doc/docs/images/overview.png deleted file mode 100644 index b84815a..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/overview.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/panel_import_button.png b/addons/zylann.hterrain/doc/docs/images/panel_import_button.png deleted file mode 100644 index d0eb5b7..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/panel_import_button.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/panel_textures_edit_button.png b/addons/zylann.hterrain/doc/docs/images/panel_textures_edit_button.png deleted file mode 100644 index 58b48b1..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/panel_textures_edit_button.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/pbr_textures.png b/addons/zylann.hterrain/doc/docs/images/pbr_textures.png deleted file mode 100644 index ffc3188..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/pbr_textures.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/resize_tool.png b/addons/zylann.hterrain/doc/docs/images/resize_tool.png deleted file mode 100644 index c78350e..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/resize_tool.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/sculpting_tools.png b/addons/zylann.hterrain/doc/docs/images/sculpting_tools.png deleted file mode 100644 index dcfddf3..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/sculpting_tools.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/single_sampling_and_triplanar_sampling.png b/addons/zylann.hterrain/doc/docs/images/single_sampling_and_triplanar_sampling.png deleted file mode 100644 index 1eb05e9..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/single_sampling_and_triplanar_sampling.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/slope_limit_tool.png b/addons/zylann.hterrain/doc/docs/images/slope_limit_tool.png deleted file mode 100644 index 1320d58..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/slope_limit_tool.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/splatmap_and_textured_result.png b/addons/zylann.hterrain/doc/docs/images/splatmap_and_textured_result.png deleted file mode 100644 index 5c9f008..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/splatmap_and_textured_result.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_array_import_dock.png b/addons/zylann.hterrain/doc/docs/images/texture_array_import_dock.png deleted file mode 100644 index 17e0ea1..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_array_import_dock.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_atlas_example.png b/addons/zylann.hterrain/doc/docs/images/texture_atlas_example.png deleted file mode 100644 index 6a04498..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_atlas_example.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_dialog.png b/addons/zylann.hterrain/doc/docs/images/texture_dialog.png deleted file mode 100644 index 431b5c9..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_dialog.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_set_editor.png b/addons/zylann.hterrain/doc/docs/images/texture_set_editor.png deleted file mode 100644 index f80d478..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_set_editor.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool.png b/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool.png deleted file mode 100644 index bf5daf0..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_directory.png b/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_directory.png deleted file mode 100644 index 1ce61f0..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_directory.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_success.png b/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_success.png deleted file mode 100644 index 5a75cf8..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_success.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_texture_types.png b/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_texture_types.png deleted file mode 100644 index 55ce92a..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_texture_types.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/texture_slots.png b/addons/zylann.hterrain/doc/docs/images/texture_slots.png deleted file mode 100644 index cfebe7b..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/texture_slots.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/tiling_artifacts.png b/addons/zylann.hterrain/doc/docs/images/tiling_artifacts.png deleted file mode 100644 index 37b9d2c..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/tiling_artifacts.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/tiling_reduction.png b/addons/zylann.hterrain/doc/docs/images/tiling_reduction.png deleted file mode 100644 index af36cb3..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/tiling_reduction.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/transition_array_blending.png b/addons/zylann.hterrain/doc/docs/images/transition_array_blending.png deleted file mode 100644 index 45d2c8e..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/transition_array_blending.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/update_editor_collider.png b/addons/zylann.hterrain/doc/docs/images/update_editor_collider.png deleted file mode 100644 index 7c58aa5..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/update_editor_collider.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/images/warped_checker_variations.png b/addons/zylann.hterrain/doc/docs/images/warped_checker_variations.png deleted file mode 100644 index 4e756f6..0000000 Binary files a/addons/zylann.hterrain/doc/docs/images/warped_checker_variations.png and /dev/null differ diff --git a/addons/zylann.hterrain/doc/docs/index.md b/addons/zylann.hterrain/doc/docs/index.md deleted file mode 100644 index 07f41b2..0000000 --- a/addons/zylann.hterrain/doc/docs/index.md +++ /dev/null @@ -1,1166 +0,0 @@ -HTerrain plugin documentation -=============================== - -Overview ----------- - -This plugin allows to create heightmap-based terrains in Godot Engine. This kind of terrain uses 2D images, such as for heights or texturing information, which makes it cheap to implement while covering most use cases. - -It is entirely built on top of the `VisualServer` scripting API, which means it should be expected to work on all platforms supported by Godot's `GLES3` renderer. - -![Screenshot of the editor with the plugin enabled and arrows showing where UIs are](images/overview.png) - - -### Video tutorials - -This written doc should be the most up to date and precise information, but video tutorials exist for a quick start. - -- [Kasper's tutorial](https://www.youtube.com/watch?v=Af1f2JPvSIs) about version 1.5.2 (16 Jan 2021) -- [GamesFromScratch presentation](https://www.youtube.com/watch?v=jYVO0-_sXZs), also featuring the [WaterWays](https://github.com/Arnklit/WaterGenGodot) plugin (23 dec 2020) -- [qubodupDev's Tutorial](https://www.youtube.com/watch?v=k_ISq6JyVSs) about version 1.3.3 (27 aug 2020) -- [Old tutorial](https://www.youtube.com/watch?v=eZuvfIHDeT4&) about version 0.8 (10 aug 2018! A lot is outdated in it but let's keep it here for the record) - -### How to install - -You will need to use Godot 4.1 or later. - -To get the last version that supported Godot 3.x, checkout the `godot3` branch in the Git repository. - -#### Automatically - -In Godot, go to the Asset Library tab, search for the terrain plugin, download it and then install it. -Then you need to activate the plugin in your `ProjectSettings`. - -#### Manually - -The plugin can be found on the [Asset Library website](https://godotengine.org/asset-library/asset/231). The download will give you a `.zip` file. Decompress it at the root of your project. This should make it so the following hierarchy is respected: - -``` -addons/ - zylann.hterrain/ - -``` - -Then you need to activate the plugin in your `ProjectSettings`. - - -### How to update - -When a new version of the plugin comes up, you may want to update. If you re-run the same installation steps, it should work most of the time. However this is not a clean way to update, because files might have been renamed, moved or deleted, and they won't be cleaned up. This is an issue with Godot's plugin management in general (TODO: [make a proposal](https://github.com/godotengine/godot-proposals/issues)). - -So a cleaner way would be: - -- Turn off the plugin -- Close all your scenes (or close Godot entirely) -- Delete the `addons/zylann.hterrain` folder -- Then install the new version and enable it - - -### Development versions - -The latest development version of the plugin can be found on [Github](https://github.com/Zylann/godot_heightmap_plugin). -It is the most recently developed version, but might also have some bugs. - - -Creating a terrain --------------------- - -### Creating a HTerrain node - -Features of this plugin are mainly available from the `HTerrain` node. To create one, click the `+` icon at the top of the scene tree dock, and navigate to this node type to select it. - -There is one last step until you can work on the terrain: you need to specify a folder in which all the data will be stored. The reason is that terrain data is very heavy, and it's a better idea to store it separately from the scene. -Select the `HTerrain` node, and click on the folder icon to choose that folder. - -![Screenshot of the data dir property](images/data_directory_property.png) - -Once the folder is set, a default terrain should show up, ready to be edited. - -![Screenshot of the default terrain](images/default_terrain.png) - -!!! note - If you don't have a default environment, it's possible that you won't see anything, so make sure you either have one, or add a light to the scene to see it. Also, because terrains are pretty large (513 units by default), it is handy to change the view distance of the editor camera so that you can see further: go to `View`, `Options`, and then increase `far distance`. - -### Terrain dimensions - -By default, the terrain is a bit small, so if you want to make it bigger, there are two ways: - -- Modify `map_scale`, which will scale the ground without modifying the scale of all child nodes while using the same memory. As the scale cannot be equal or less than `0`, the limit of `0.01` (1 cm per cell) was set as an arbitrary safety guard. This value is still high enough to not run into precision floating-point problems. -- Use the `resize` tool in the `Terrain` menu, which will increase the resolution instead and take more memory. - -![Screenshot of the resize tool](images/resize_tool.png) - -If you use the `resize` tool, you can also choose to either stretch the existing terrain, or crop it by selecting an anchor point. Currently, this operation is permanent and cannot be undone, so if you want to go back, you should make a backup. - -!!! note - The resolution of the terrain is limited to powers of two + 1, mainly because of the way LOD was implemented. The reason why there is an extra 1 is down to the fact that to make 1 quad, you need 2x2 vertices. If you need LOD, you must have an even number of quads that you can divide by 2, and so on. However there is a possibility to tweak that in the future because this might not play well with the way older graphics cards store textures. - - -Sculpting ------------ - -### Brush types - -The default terrain is flat, but you may want to create hills and mountains. Because it uses a heightmap, editing this terrain is equivalent to editing an image. Because of this, the main tool is a brush with a configurable size and shape. You can see which area will be affected inside a 3D red circle appearing under your mouse, and you can choose how strong painting is by changing the `Brush opacity` slider. - -![Screenshot of the brush widget](images/brush_editor.png) - -To modify the heightmap, you can use the following brush modes, available at the top of the viewport: - -![Screenshot of the sculpting tools](images/sculpting_tools.png) - -- **Raise**: raises the height of the terrain to produce hills -- **Lower**: digs down to create crevices -- **Smooth**: smoothes heights locally -- **Level**: averages the heights within the radius of the brush until ground eventually becomes flat -- **Flatten**: directly sets the height to a given value, which can be useful as an eraser or to make plateaux. It is also possible to pick a height from the viewport using the picking button. -- **Erode**: smoothes the landscape by simulating erosion. When used on noisy terrain, it often produces characteristic shapes found in nature. - -!!! note - Heightmaps work best for hills and large mountains. Making sharp cliffs or walls are not recommended because it stretches geometry too much, and might cause issues with collisions. To make cliffs it's a better idea to place actual meshes on top. - -### Normals - -As you sculpt, the plugin automatically recomputes normals of the terrain, and saves it in a texture. This way, it can be used directly in ground shaders, grass shaders and previews at a smaller cost. Also, it allows to keep the same amount of details in the distance independently from geometry, which allows for levels of detail to work without affecting perceived quality too much. - - -### Collisions - -You can enable or disable collisions by checking the `Collisions enabled` property in the inspector. - -Heightmap-based terrains usually implement collisions directly using the heightmap, which saves a lot of computations compared to a classic mesh collider. - -![Screenshot of the option to choose physics engines in project settings](images/choose_bullet_physics.png) - -Some editor tools rely on colliders to work, such as snapping to ground or plugins like Scatter or other prop placement utilities. To make sure the collider is up to date, you can force it to update after sculpting with the `Terrain -> Update Editor Collider` menu: - -![Screenshot of the menu to update the collider](images/update_editor_collider.png) - -Note: if you use Godot 3.3, you need to make sure to use the Bullet physics engine in your project settings. - - -#### Known issues - -- **Updating the collider**: In theory, Bullet allows us to specify a direct reference to the image data. This would allow the collider to automatically update for free. However, we still had to duplicate the heightmap for safety, to avoid potential crashes if it gets mis-used. Even if we didn't copy it, the link could be broken anytime because of internal Copy-on-Write behavior in Godot. This is why the collider update is manual, because copying the heightmap results in an expensive operation. It can't be threaded as well because in Godot physics engines are not thread-safe yet. It might be improved in the future, hopefully. - -- **Misaligned collider in editor**: At time of writing, the Bullet integration has an issue about colliders in the editor if the terrain is translated, which does not happen in game: [Godot issue #37337](https://github.com/godotengine/godot/issues/37337) - - -### Holes - -It is possible to cut holes in the terrain by using the `Holes` brush. Use it with `draw holes` checked to cut them, and uncheck it to erase them. This can be useful if you want to embed a cave mesh or a well on the ground. You can still use the brush because holes are also a texture covering the whole terrain, and the ground shader will basically discard pixels that are over an area where pixels have a value of zero. - -![Screenshot with holes](images/hole_painting.png) - -At the moment, this brush uses the alpha channel of the color map to store where the holes are. - -!!! note - This brush only produces holes visually. In order to have holes in the collider too, you have to do some tricks with collision layers because the collision shape this plugin uses (Bullet heightfield) cannot have holes. It might be added in the future, because it can be done by editing the C++ code and drop collision triangles in the main heightmap collision routine. - - See [issue 125](https://github.com/Zylann/godot_heightmap_plugin/issues/125) - - -### Level of detail - -This terrain supports level of details on the geometry using a quad tree. It is divided in chunks of 32x32 (or 16x16 depending on your settings), which can be scaled by a power of two depending on the distance from the camera. If a group of 4 chunks are far enough, they will join into a single one. If a chunk is close enough, it will split in 4 smaller ones. Having chunks also improves culling because if you had a single big mesh for the whole terrain, that would be a lot of vertices for the GPU to go through. -Care is also taken to make sure transitions between LODs are seamless, so if you toggle wireframe rendering in the editor you can see variants of the same meshes being used depending on which LOD their neighbors are using. - -![Screenshot of how LOD vertices decimate in the distance](images/lod_geometry.png) - -LOD can be mainly tweaked in two ways: - -- `lod scale`: this is a factor determining at which distance chunks will split or join. The higher it is, the more details there will be, but the slower the game will be. The lower it is, the faster quality will decrease over distance, but will increase speed. -- `chunk size`: this is the base size of a chunk. There aren't many values that it can be, and it has a similar relation as `lod scale`. The difference is, it affects how many geometry instances will need to be culled and drawn, so higher values will actually reduce the number of draw calls. But if it's too big, it will take more memory due to all chunk variants that are precalculated. - -In the future, this technique could be improved by using GPU tessellation, once the Godot rendering engine supports it. GPU clipmaps are also a possibility, because at the moment the quad tree is updated on the CPU. - -!!! note - Due to limitations of the Godot renderer's scripting API, LOD only works around one main camera, so it's not possible to have two cameras with split-screen for example. Also, in the editor, LOD only works while the `HTerrain` node is selected, because it's the only time the EditorPlugin is able to obtain camera information (but it should work regardless when you launch the game). - - -Texturing ------------ - -### Overview - -Applying textures to terrains is a bit different than single models, because they are very large and a more optimal approach needs to be taken to keep memory and performance to an acceptable level. One very common way of doing it is by using a splatmap. A splatmap is another texture covering the whole terrain, whose role is to store which detail textures should be blended, and these textures may repeat seamlessly. - -![Screenshot showing splatmap and textured result](images/splatmap_and_textured_result.png) - -This magic is done with a single shader, i.e a single `ShaderMaterial` in Godot's terminology. This material is handled internally by the plugin, but you can customize it in several ways. - -There are mainly 3 families of shaders this plugin supports: - -- `CLASSIC4`: simple shaders where each texture may be a separate resource. They are limited to 4 textures. -- `MULTISPLAT16`: more advanced shader using more splatmaps and texture arrays. It's expensive but supports up to 16 textures. -- `ARRAY`: experimental shader also using texture arrays, which comes with constraints, but allows to paint a lot more different textures. -- Other shaders don't need textures, like `LOW_POLY`, which only uses colors. - -On the `HTerrain` node, there is a property called `shader_type`, which lets you choose among built-in shaders. The one you choose will define which workflow to follow: textures, or texture arrays. - -At time of writing, `CLASSIC4` shaders are better supported, and are the default choice. -Texture array shaders may be used more in the future. - - -### Getting PBR textures - -*If you only plan to use simple color textures, you can skip to [Texture Sets](#texture-sets).* - -Before you can paint textures, you have to set them up. It is recommended to pick textures which can tile infinitely, and preferably use "organic" ones, because terrains are best-suited for exterior natural environments. -For each texture, you may find the following types of images, common in PBR shading: - -- Albedo, color, or diffuse (required) -- Bump, height, or displacement (optional) -- Normal, or normalmap (optional) -- Roughness (optional) - -![Screenshot of PBR textures](images/pbr_textures.png) - -You can find some of these textures for free at [cc0textures.com](http://cc0textures.com). - -!!! note: Some shaders have a `Lite` and non-lite versions. One main difference between them is that `Lite` versions don't require normal maps, but the others require them. If you use a non-lite shader and forget to assign normal maps, shading will look wrong. - -It is preferable to place those source images under a specific directory. Also, since the images will only serve as an input to generate the actual game resources, it is better to place a `.gdignore` file inside that directory. This way, Godot will not include those source files in the exported game: - -``` -terrain_test/ - terrain_data/ - height.res - data.hterrain - ... - textures_src/ - .gdignore - grass_albedo.png - grass_bump.png - grass_normal.png - grass_roughness.png - rocks_albedo.png - rocks_bump.png - rocks_normal.png - rocks_roughness.png - ... - terrain_scene.tscn - ... -``` - -!!! note - While bump might not be used often, this plugin actually uses it to achieve [better blending effects](#depth-blending). - - -### Using the import tool - -Ground textures are stored in a `HTerrainTextureSet` resource. All terrains come with a default one. However, it can be tedious to setup every texture and pack them, especially if you need PBR. - -This plugin comes with an optional import tool. Select your `HTerrain` node, and in the bottom panel, click the `Import...` button: - -![Screenshot of bottom panel import button](images/panel_import_button.png) - -This brings up the import tool dialog: - -![Screenshot of the texture set import tool](images/texture_set_import_tool.png) - -#### Import mode - -One of the first important things is to decide which import mode you want to use: - -- `Textures`: For simple terrains with up to 4 textures (in use with `CLASSIC4` shaders) -- `TextureArrays`: For more complex terrains with up to 16 textures (in use with `MULTISPLAT16` and `ARRAY` shaders) - -This choice depends on the shader you will use for the terrain. Some shaders expect individual textures and others expect texture arrays. - -#### Smart file pick - -If you use PBR textures, there might be a lot of files to assign. If you use a naming convention, you can start loading an albedo texture, and the tool will attempt to find all the other maps automatically by recognizing other image file names. For example, using this convention may allow this shortcut to work: - -- `grass_albedo.png` -- `grass_bump.png` -- `grass_normal.png` -- `grass_roughness.png` - -![Screenshot of texture types in import tool](images/texture_set_import_tool_texture_types.png) - - -#### Normal maps - -As indicated in the [Godot documentation](https://docs.godotengine.org/en/stable/tutorials/3d/spatial_material.html#normal-map), normal maps are expected to use OpenGL convention (X+, Y+, Z+). So it is possible that normalmaps you find online use a different convention. - -To help with this, the import tool allows you to flip Y, in case the normalmap uses DirectX convention. - -![Examples of normalmap conventions](images/normalmap_conventions.png) - - -#### Importing - -When importing, this tool will need to generate a few files representing intermediate Godot resources. You may have to choose the directory where those resources will be created, otherwise they will be placed at the root of your project. - -![Screenshot of directory option in import tool](images/texture_set_import_tool_directory.png) - -Once everything is ready, you can click `Import`. This can take a little while. -If all goes well, a popup will tell you when it's done, and your terrain's texture set will be filled up with the imported textures. - -![Screenshot of import success](images/texture_set_import_tool_success.png) - -If importing goes wrong, most of the time an error will show up and the `HTerrainTextureSet` will not be modified. -If it succeeded but you are unhappy with the result, it is possible to undo the changes done to the terrain using `Ctrl+Z`. - -!!! note - - If you need to change something after the first import, you can go back to the importing tool and change settings, then click `Import` again. - - Importing with this tool will overwrite the whole set each time. - - The tool does not store the settings anywhere, but it should fill them up as much as it can from existing sets so you shouldn't need to fill everything up again. - - Custom importers are used as backend in order to support these features automatically, instead of default Godot importers. If you need more tinkering, you can take a look at [packed texture importers](#packed-texture-importers). - - -### Texture Sets - -#### Description - -`HTerrainTextureSet` is a custom resource which contains all textures a terrain can blend on the ground (grass, dirt, rocks, leaves, snow, sand...). All terrains come with an empty one assigned by default. - -The import tool seen earlier is the quickest way to fill one up from base textures, but it is not mandatory if you prefer to do things manually. - -You can inspect and edit the current set by selecting your `HTerrain` node, and in the bottom panel "Textures" section, click `Edit...`: - -![Screenshot of the bottom panel edit button](images/panel_textures_edit_button.png) - -This opens the following dialog: - -![Screenshot of the texture set editor](images/texture_set_editor.png) - -Unlike the import tool, this dialog shows you the actual resources used by the terrain. They may be either pairs of two packed textures for each slot, or two `TextureArray` resources. - -If you are using a `CLASSIC4` shader, you should be able to add and remove slots using the `+` and `-` buttons, and directly load color textures in the `Albedo` channel. -For using texture arrays or PBR textures, it might be better to use the [import tool](#getting-pbr-textures). - -Actions done in this dialog behave like an extension of the inspector, and can be undone with `Ctrl+Z`. - - -#### Re-using a texture set - -Texture sets are embedded in terrains by default, but it is possible to use the same set on another terrain. To do this, the `HTerrainTextureSet` must be saved as a `.tres` file. - -![Screenshot of texture set in the inspector](images/inspector_texture_set.png) - -- Select your `HTerrain` node -- In the inspector, right-click on the value of the `texture_set` property -- A HUGE menu will open (this is a Godot issue). Scroll all the way down with mouse wheel. -- Click the `Edit...` menu item to edit the resource -- On top of the inspector, a floppy disk icon should appear. You can click on it and choose `Save As...` - -![Screenshot of saving a texture set from inspector](images/inspector_texture_set_save.png) - -- A file dialog will prompt you for the location you want to put the resource file. Once you're done, click `Save`. - -Once you have a `.tres` file, you will be able to pick it up in your other terrain, by clicking on the `texture_set` property, but choosing `Load` this time. -You can also navigate to the `.tres` file in the `FileSystem` dock, then drag and drop to the property. - - -### Shader types - -#### Classic4 - -The `CLASSIC4` shader is a simple splatmap technique, where R, G, B, A match the weight of 4 respective textures. Then are all blended together in every pixel of the ground. Here is how it looks when applied: - -![Screenshot showing splatmap and textured result](images/splatmap_and_textured_result.png) - -It comes in two variants: - -- `CLASSIC4`: full-featured shader, however it requires your textures to have normal maps. If you don't assign them, shading will look wrong. -- `CLASSIC4_LITE`: simpler shader with less features. It only requires albedo textures. - - -#### MultiSplat16 - -the `MULTISPLAT16` shader is an extension of the splatmap technique, but uses 4 splatmaps instead of 1. It also uses `TextureArrays` instead of individual textures. It allows to support up to 16 textures at once, and can blend up to 4 in the same pixel. It dynamically chooses the 4 most-representative textures to blend them. - -It also comes in two variants: - -- `MULTISPLAT16`: full-featured shader, however it requires your texture arrays to have normal maps. -- `MULTISPLAT16_LITE`: simpler shader with less features. It only requires albedo texture arrays. - -It is the recommended choice if you need more than 4 textures, because it is much easier to use than the `ARRAY` shader and produces less artifacts. - -One downside is performance: it is about twice slower than `CLASSIC4` (on an nVidia 1060, a fullscreen `CLASSIC4` is 0.8 ms, while `MULTISPLAT16` is 1.8 ms). -Although, considering objects placed on the terrain should usually occlude ground pixels, the cost might be lower in a real game scenario. - - -#### LowPoly - -The `LOWPOLY` shader is the simplest shader. It produces a faceted look with only simple colors, and no textures. You will need to use the color brush to paint it. - -![Screenshot of the lowpoly shader](images/low_poly.png) - -!!! note - If you need faceted visuals with other shaders using textures, you can obtain the same result by [customizing the shader](#custom-shaders), and adding this line at the end of `fragment()`: - `NORMAL = normalize(cross(dFdx(VERTEX), dFdy(VERTEX)));` - - -#### Array - -**WARNING: this shader is still experimental. It's not ideal and has known flaws, so it may change in the future.** - -The `ARRAY` shader uses a more advanced technique to render ground textures. Instead of one splatmap and many individual textures, it uses a weightmap, an index map, and a `TextureArray`. - -The two maps are different from the classic one: - -- `SPLAT_INDEX`: this one stores the indexes of the textures to blend in every pixel of the ground. Indexes are stored respectively in R, G and B, and correspond to layers of the `TextureArray`. -- `SPLAT_WEIGHT`: this one stores the weight of the 3 textures to blend on each pixel. It only has R and G channels, because the third one can be inferred (their sum must be 1). - -This allows to paint up to 256 different textures, however it introduces an important constraint: you cannot blend more than 3 textures at a given pixel. - -Painting the proper indexes and weights can be a challenge, so for now, the plugin comes with a compromise. Each texture is assigned a fixed color component, R, G or B. So for a given texture, all textures that have an index separated by a multiple of 3 from this texture will not always be able to blend with it. For example, texture `2` might not blend with texture `5`, `8`, `11`, `14` etc. So choosing where you place textures in the `TextureArray` can be important. - -Here is a close-up on an area where some textures are not totally blending, because they use the same color component: - -![Bad transition](images/bad_array_blending.png) - -In this situation, another workaround is to use a transition texture: if A and B cannot blend, use texture C which can blend with A and B: - -![Fixed transition](images/transition_array_blending.png) - -You may see this pop up quite often when using this shader, but it can often be worked around. -The brush for this isn't perfect. This limitation can be smoothed out in the future, if a better algorithm is found which can work in real-time. - - -### Creating a `TextureArray` manually - -!!! note - It is now possible to use the [import tool](#using-the-import-tool) to set this up automatically. The following description explains how to do it manually. - -Contrary to `CLASSIC4` shaders, you cannot directly assign individual textures with a shader that requires `TextureArray`. Instead, you'll have to import one. - -1) With an image editor, create an image, which you subdivide in square tiles, like an atlas. I each of them, place one ground texture, like so: - -![Example of an atlas for creating a Texture Array](images/texture_atlas_example.png) - -2) Place that atlas in your Godot project. The editor will attempt to import it a first time, it can take a while if it's big. - -3) Select the atlas, and go to the `Import` dock. Change the import type to `TextureArray`. - -![Texture Array import dock](images/texture_array_import_dock.png) - -4) Make sure the `Repeat` mode is enabled. Then, change the tile counts below to match your grid. Once you're done, click `Re-import`. Godot will ask you to restart the editor, do that (I have no idea why). - -5) Once the editor has restarted, select your terrain node, and make sure it uses the `ARRAY` shader type (or a similar custom shader). In the bottom panel, click on the `Edit...` button to edit the `HTerrainTextureSet` used by the terrain. - -6) In the dialog, click on the `Load Array...` button under `Albedo` to load your texture array. You can do the same process with normal maps if needed. - -7) The bottom panel should now update to show much more texture slots. They will appear in the same order they are in the atlas, from left-to-right. If the panel doesn't update, select another node and click the terrain again. You should now be able to paint. - -![Lots of textures blending](images/lots_of_textures_blending.png) - - - -### Packing textures manually - -!!! note - It is now possible to use the [import tool](#using-the-import-tool) to set this up automatically. The following description explains how to do it manually. - -The main ground shaders provided by the plugin should work fine with only regular albedo, but it supports a few features to make the ground look more realistic, such as normal maps, bump and roughness. To achieve this, shaders expects packed textures. The main reason is that more than one texture has to be sampled at a time, to allow them to blend. With a classic splatmap, it's 4 at once. If we want normalmaps, it becomes 8, and if we want roughness it becomes 12 etc, which is already a lot, in addition to internal textures Godot uses in the background. Not all GPUs allow that many textures in the shader, so a better approach is to combine them as much as possible into single images. This reduces the number of texture units, and reduces the number of fetches to do in the pixel shader. - -![Screenshot of the channel packer plugin](images/channel_packer.png) - -For this reason, the plugin uses the following convention in ground textures: - -- `Albedo` in RGB, `Bump` in A -- `Normal` in RGB, `Roughness` in A - -This operation can be done in an image editing program such as Gimp, or with a Godot plugin such as [Channel Packer](https://godotengine.org/asset-library/asset/230). -It can also be done using [packed texture importers](packed-texture-importers), which are now included in the plugin. - -!!! note - Normal maps must follow the OpenGL convention, where Y goes up. They are recognizable by being "brighter" on the top of bumpy features (because Y is green, which is the most energetic color to the human eye): - - ![Examples of normalmap conventions](images/normalmap_conventions.png) - - See also [Godot's documentation notes about normal maps](https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_images.html#normal-map) - -!!! note - Because Godot would strip out the alpha channel if a packed texture was imported as a normal map, you should not make your texture import as "Normal Map" in the importer dock. - - -### Packed texture importers - -In order to support the [import tool](#using-the-import-tool), this plugin defines two special texture importers, which allow to pack multiple input textures into one. They otherwise behave the same as Godot's default importers. - -The type of file they import are JSON files, which refer to the source image files you wish to pack together, along with a few other options. - -#### Packed textures - -File extension: `.packed_tex` - -Example for an albedo+bump texture: -```json -{ - "contains_albedo": true, - "src": { - "rgb": "res://textures/src/grass_albedo.png", - "a": "res://textures/src/grass_bump.png", - } -} -``` - -Example for a normal+roughness texture, with conversion from DirectX to OpenGL (optional): -```json -{ - "src": { - "rgb": "res://textures/src/rocks_normal.png", - "a": "res://textures/src/rocks_roughness.png", - "normalmap_flip_y": true - } -} -``` - -You can also specify a plain color instead of a path, if you don't need a texture. It will act as if the source texture was filled with this color. The expected format is ARGB. - -``` - "rgb": "#ff888800" -``` - -#### Packed texture arrays - -File extension: `.packed_texarr` - -This one requires you to specify a `resolution`, because each layer of the texture array must have the same size and be square. The resolution is a single integer number. -What you can put in each layer is the same as for [packed textures](#packed-textures). - -```json -{ - "contains_albedo": true, - "resolution": 1024, - "layers": [ - { - "rgb": "res://textures/src/grass_albedo.png", - "a": "res://textures/src/grass_bump.png" - }, - { - "rgb": "res://textures/src/rocks_albedo.png", - "a": "res://textures/src/rocks_bump.png" - }, - { - "rgb": "res://textures/src/sand_albedo.png", - "a": "res://textures/src/sand_bump.png" - } - ] -} -``` - -#### Limitations - -Such importers support most of the features needed for terrain textures, however some features found in Godot's importers are not implemented. This is because Godot does not have any API to extend the existing importers, so they had to be re-implemented from scratch in GDScript. For example, lossy compression to save disk space is not supported, because it requires access to WebP compression API which is not exposed. - -See [Godot proposal](https://github.com/godotengine/godot-proposals/issues/1943) - - -### Depth blending - -`Bump` textures holds a particular usage in this plugin: -You may have noticed that when you paint multiple textures, the terrain blends them together to produce smooth transitions. Usually, a classic way is to do a "transparency" transition using the splatmap. However, this rarely gives realistic visuals, so an option is to enable `depth blending` under `Shader Params`. - -![Screenshot of depth blending VS alpha blending](images/alpha_blending_and_depth_blending.png) - -This feature changes the way blending operates by taking the bump of the ground textures into account. For example, if you have sand blending with pebbles, at the transition you will see sand infiltrate between the pebbles because the pixels between pebbles have lower bump than the pebbles. You can see this technique illustrated in a [Gamasutra article](https://www.gamasutra.com/blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php). -It was tweaked a bit to work with 3 or 4 textures, and works best with fairly low brush opacity, around 10%. - - -### Triplanar mapping - -Making cliffs with a heightmap terrain is not recommended, because it stretches the geometry too much and makes textures look bad. Nevertheless, you can enable triplanar mapping on such texture in order for it to not look stretched. This option is in the shader section in the inspector. - -![Screenshot of triplanar mapping VS no triplanar](images/single_sampling_and_triplanar_sampling.png) - -In the case of the `CLASSIC4` shader, cliffs usually are made of the same ground texture, so it is only available for textures setup in the 4th slot, called `cliff`. It could be made to work on all slots, however it involves modifying the shader to add more options, which you may see in a later article. - -The `ARRAY` shader does not have triplanar mapping yet, but it may be added in the future. - - -### Tiling reduction - -The fact repeating textures are used for the ground also means they will not look as good at medium to far distance, due to the pattern it produces: - -![Screenshot of tiling artifacts](images/tiling_artifacts.png) - -On shaders supporting it, the `tile_reduction` parameter allows to break the patterns a bit to attenuate the effect: - -![Screenshot of reduced tiling artifacts](images/tiling_reduction.png) - -This option is present under the form of a `vec4`, where each component correspond to a texture, so you can enable it for some of them and not the others. Set a component to `1` to enable it, and `0` to disable it. - -This algorithm makes the shader sample the texture a second time, at a different orientation and scale, at semi-random areas of the ground: - -![Screenshot of the warped checker pattern used to break repetitions](images/warped_checker_variations.png) - -Here you can see where each of the two texture variants are being rendered. The pattern is a warped checker, which is simple enough to be procedural (avoiding the use of a noise texture), but organic enough so it shouldn't create artifacts itself. The result is made seamless by using depth blending (see [Depth blending](#depth-blending)). - -Although it's still possible to notice repetition over larger distances, this can be better covered by using a fade to global map (see [Global map](#global-map)). -In addition, many games don't present a naked terrain to players: there are usually many props on top of it, such as grass, vegetation, trees, rocks, buildings, fog etc. so overall tiling textures should not really be a big deal. - - -### Painting only on slopes - -The texture painting tool has a special option to limit the brush based on the slope of the terrain. This helps painting cliffs only or flat grounds only, without having to aim. It can even be used to paint a big area in one go, by increasing the brush size. - -![Screenshot of the slope limit tool](images/slope_limit_tool.png) - -The control consists in a two-ways slider. You can drag two handles. The left handle controls minimum slope, the right handle controls maximum slope. The range between the two handles determines which slopes the brush will paint on. - - -### Color tint - -You can color the terrain using the `Color` brush. This is pretty much modulating the albedo, which can help adding a touch of variety to the landscape. If you make custom shader tweaks, color can also be used for your own purpose if you need to. - -![Screenshot with color painting](images/color_painting.png) - -Depending on the shader, you may be able to choose which textures are affected by the colormap. - - -### Global map - -For shading purposes, it can be useful to bake a global map of the terrain. A global map takes the average albedo of the ground all over the terrain, which allows other elements of the scene to use that without having to recompute the full blending process that the ground shader goes through. The current use cases for a global map is to tint grass, and use it as a distance fade in order to hide texture tiling in the very far distance. Together with the terrain's normal map it could also be used to make minimap previews. - -To bake a global map, select the `HTerrain` node, go to the `Terrain` menu and click `Bake global map`. This will produce a texture in the terrain data directory which will be used by the default shaders automatically, depending on your settings. - -If you use a custom shader, you can define a specific one to use for the global map, by assigning the `custom_globalmap_shader` property. This is usually a stripped-down version of the main ground shader, where only `ALBEDO` is important. - -!!! note - The globalmap is also used in the minimap to show the color of the terrain. - - -Terrain generator -------------------- - -Basic sculpting tools can be useful to get started or tweaking, but it's cumbersome to make a whole terrain only using them. For larger scale terrain modeling, procedural techniques are often preferred, and then adjusted later on. - -This plugin provides a simple procedural generator. To open it, click on the `HTerrain` node to see the `Terrain` menu, in which you select `generate...`. Note that you should have a properly setup terrain node before you can use it. - -![Screenshot of the terrain generator](images/generator.png) - -The generator is quite simple and combines a few common techniques to produce a heightmap. You can see a 3D preview which can be zoomed in with the mouse wheel and rotated by dragging holding middle click. - -### Height range - -`height range` and `base height` define which is the minimum and maximum heights of the terrain. The result might not be exactly reaching these boundaries, but it is useful to determine in which region the generator has to work in. - -### Perlin noise - -Perlin noise is very common in terrain generation, and this one is no exception. Multiple octaves (or layers) of noise are added together at varying strength, forming a good base that already looks like a good environment. - -The usual parameters are available: - -- `seed`: this chooses the random seed the perlin noise will be based on. Same number gives the same landscape. -- `offset`: this chooses where in the landscape the terrain will be cropped into. You can also change that setting by panning the preview with the right mouse button held. -- `scale`: expands or shrinks the length of the patterns. Higher scale gives lower-frequency relief. -- `octaves`: how many layers of noise to use. The more octaves, the more details there will be. -- `roughness`: this controls the strength of each octave relatively to the previous. The more you increase it, the more rough the terrain will be, as high-frequency octaves get a higher weight. - -Try to tweak each of them to get an idea of how they affect the final shape. - -### Erosion - -The generator features morphological erosion. Behind this barbaric name hides a simple image processing algorithm, ![described here](https://en.wikipedia.org/wiki/Erosion_(morphology)). -In the context of terrains, what it does is to quickly fake real-life erosion, where rocks might slide along the slopes of the mountains over time, giving them a particular appearance. Perlin noise alone is nice, but with erosion it makes the result look much more realistic. - -![Screenshot with the effect of erosion](images/erosion_steps.png) - -It's also possible to use dilation, which gives a mesa-like appearance. - -![Screenshot with the effect of dilation](images/dilation.png) - -There is also a slope direction parameter, this one is experimental but it has a tendency to simulate wind, kind of "pushing" the ground in the specified direction. It can be tricky to find a good value for this one but I left it because it can give interesting results, like sand-like ripples, which are an emergent behavior. - -![Screenshot of slope erosion](images/erosion_slope.png) - -!!! note - Contrary to previous options, erosion is calculated over a bunch of shader passes. In Godot 3, it is only possible to wait for one frame to be rendered every 16 milliseconds, so the more erosion steps you have, the slower the preview will be. In the future it would be nice if Godot allowed multiple frames to be rendered on demand so the full power of the GPU could be used. - -### Applying - -Once you are happy with the result, you can click "Apply", which will calculate the generated terrain at full scale on your scene. This operation currently can't be undone, so if you want to go back you should make a backup. - - -Import an existing terrain ------------------------------ - -Besides using built-in tools to make your landscape, it can be convenient to import an existing one, which you might have made in specialized software such as WorldMachine, Scape or Lithosphere. - -### Import dialog - -To do this, select the `HTerrain` node, click on the `Terrain` menu and chose `Import`. -This window allows you to import several kinds of data, such as heightmap but also splatmap or color map. - -![Screenshot of the importer](images/importer.png) - -There are a few things to check before you can successfully import a terrain though: - -- The resolution should be power of two + 1, and square. If it isn't, the plugin will attempt to crop it, which might be OK or not if you can deal with map borders that this will produce. -- If you import a RAW heightmap, it has to be encoded using 16-bit unsigned integer format. -- If you import a PNG heightmap, Godot can only load it as 8-bit depth, so it is not recommended for high-range terrains because it doesn't have enough height precision. - -This feature also can't be undone when executed, as all terrain data will be overwritten with the new one. If anything isn't correct, the tool will warn you before to prevent data loss. - -It is possible that the height range you specify doesn't works out that well after you see the result, so for now it is possible to just re-open the importer window, change the height scale and apply again. - - -### 4-channel splatmaps caveat - -Importing a 4-channel splatmap requires an RGBA image, where each channel will be used to represent the weight of a texture. However, if you are creating a splatmap by going through an image editor, *you must make sure the color data is preserved*. - -Most image editors assume you create images to be seen. When you save a PNG, they assume fully-transparent areas don't need to store any color data, because they are invisible. The RGB channels are then compressed away, which can cause blocky artifacts when imported as a splatmap. - -To deal with this, make sure your editor has an option to turn this off. In Gimp, for example, this option is here: - -![Screenshot of the importer](images/gimp_png_preserve_colors.png) - - -Detail layers ---------------- - -Once you have textured ground, you may want to add small detail objects to it, such as grass and small rocks. - -![Screenshot of two grass layers under the terrain node](images/detail_layers.png) - -### Painting details - -Grass is supported through `HTerrainDetailLayer` node. They can be created as children of the `HTerrain` node. Each layer represents one kind of detail, so you may have one layer for grass, and another for flowers, for example. - -Detail layers come in two parts: - -- A 8-bit density texture covering the whole terrain, also called a "detail map" at the moment. You can see how many maps the terrain has in the bottom panel after selecting the terrain. -- A `HTerrainDetailLayer` node, which uses one of the detail maps to render instanced models based on the density. - -You can paint detail maps just like you paint anything else, using the same brush system. It uses opacity to either add more density, or act as an eraser with an opacity of zero. -`HTerrainDetailLayer` nodes will then update in realtime, rendering more or less instances in places you painted. - -!!! note - A detail map can be used by more than one node (by setting the same index in their `layer_index` property), so you can have one for grass, another for flowers, and paint on the shared map to see both nodes update at the same time. - - -### Shading options - -At the moment, detail layers only come with a single shader type, which is made for grass. More may be added in the future. - -You can choose which texture will be used, and it will be rendered using alpha-scissor. It is done that way because it allows drawing grass in the opaque render pass, which is cheaper than treating every single quad like a transparent object which would have to be depth-sorted to render properly. Alpha-to-coverage would look better, but isn't supported in Godot 3. - -Like the ground, detail layers use a custom shader that takes advantage of the heightmap to displace each instanced object at a proper position. Also, hardware instancing is used under the hood to allow for a very high number of items with low cost. Multimeshes are generated in chunks, and then instances are hidden from the vertex shader depending on density. For grass, it also uses the normal of the ground so there is no need to provide it. There are also shader options to tint objects with the global map, which can help a lot making grass to blend better with the environment. - -Finally, the shader fades in the distance by increasing the threshold of alpha scissor. This works better with a transparent texture. An alternative is to make it sink in the ground, but that's left to customization. - -For writing custom shaders, see [Custom detail shaders](#grass-shaders). - -### Meshes - -By default, detail layers draw simple quads on top of the ground. But it is possible to choose another kind of geometry, by assigning the `instance_mesh` property. -Several meshes are bundled with the plugin, which you can find in `res://addons/zylann.hterrain/models/`. - -![Bundled grass models](images/grass_models.png) - -They are all thought for grass rendering. You can make your own for things that aren't grass, however there is no built-in shader for conventional objects at the moment (rocks, bits and bobs). So if you want normal shading you need to write a custom shader. That may be bundled too in the future. - -!!! note - Detail meshes must be `Mesh` resources, so the easiest way is to use the `OBJ` format. If you use `GLTF` or `FBX`, Godot will import it as a scene by default, so you may have to configure it to import as single mesh if possible. - - -Custom shaders ------------------ - -This plugin comes with default shaders, but you are allowed to modify them and change things to match your needs. The plugin does not expose materials directly because it needs to set built-in parameters that are always necessary, and some of them cannot be properly saved as material properties, if at all. - -### Ground shaders - -In order to write your own ground shader, select the `HTerrain` node, and change the shader type to `Custom`. Then, select the `custom shader` property and choose `New Shader`. This will create a new shader which is pre-filled with the same source code as the last built-in shader you had selected. Doing it this way can help seeing how every feature is done and find your own way into implementing customizations. - -The plugin does not actually hardcode its features based on its built-in shaders. Instead, it looks at which `uniform` parameters your shader defines, and adapts in consequence. -A list of `uniform` parameters are recognized, some of which are required for heightmap rendering to work: - -Parameter name | Type | Format | Description -------------------------------------|------------------|---------|-------------- -`u_terrain_heightmap` | `sampler2D` | `RH` | The heightmap, a 32-bit float texture which can be sampled in the red channel. Like the other following maps, you have to access it using cell coordinates, which can be computed as seen in the built-in shader. -`u_terrain_normalmap` | `sampler2D` | `RGB8` | The precalculated normalmap of the terrain, which you can use instead of computing it from the heightmap -`u_terrain_colormap` | `sampler2D` | `RGBA8` | The color map, which is the one modified by the color brush. The alpha channel is used for holes. -`u_terrain_splatmap` | `sampler2D` | `RGBA8` | The classic 4-component splatmap, where each channel determines the weight of a given texture. The sum of each channel across all splatmaps must be 1.0. -`u_terrain_splatmap_1` | `sampler2D` | `RGBA8` | Additional splatmap -`u_terrain_splatmap_2` | `sampler2D` | `RGBA8` | Additional splatmap -`u_terrain_splatmap_3` | `sampler2D` | `RGBA8` | Additional splatmap -`u_terrain_globalmap` | `sampler2D` | `RGB8` | The global albedo map. -`u_terrain_splat_index_map` | `sampler2D` | `RGB8` | An index map, used for texturing based on a `TextureArray`. the R, G and B components multiplied by 255.0 will provide the index of the texture. -`u_terrain_splat_weight_map` | `sampler2D` | `RG8` | A 2-component weight map where a 3rd component can be obtained with `1.0 - r - g`, used for texturing based on a `TextureArray`. The sum of R and G must be 1.0. -`u_ground_albedo_bump_0`...`3` | `sampler2D` | `RGBA8` | These are up to 4 albedo textures for the ground, which you have to blend using the splatmap. Their alpha channel can contain bump. -`u_ground_normal_roughness_0`...`3` | `sampler2D` | `RGBA8` | Similar to albedo, these are up to 4 normal textures to blend using the splatmap. Their alpha channel can contain roughness. -`u_ground_albedo_bump_array` | `sampler2DArray` | `RGBA8` | Equivalent of the previous individual albedo textures, as an array. The plugin knows you use this texturing technique by checking the existence of this parameter. -`u_ground_normal_roughness_array` | `sampler2DArray` | `RGBA8` | Equivalent of the previous individual normalmap textures, as an array. -`u_terrain_inverse_transform` | `mat4x4` | | A 4x4 matrix containing the inverse transform of the terrain. This is useful if you need to calculate the position of the current vertex in world coordinates in the vertex shader, as seen in the builtin shader. -`u_terrain_normal_basis` | `mat3x3` | | A 3x3 matrix containing the basis used for transforming normals. It is not always needed, but if you use `map scale` it is required to keep them correct. - -You don't have to declare them all. It's fine if you omit some of them, which is good because it frees a slot in the limited amount of `uniforms`, especially for texture units. -Other parameters are not used by the plugin, and are shown procedurally under the `Shader params` section of the `HTerrain` node. - - -### Grass shaders - -Detail layers follow the same design as ground shaders. In order to make your own, select the `custom shader` property and assign it a new empty shader. This will also fork the built-in shader, which at the moment is specialized into rendering grass quads. - -They share the following parameters with ground shaders: - -- `u_terrain_heightmap` -- `u_terrain_normalmap` -- `u_terrain_globalmap` -- `u_terrain_inverse_transform` - -And there also have specific parameters which you can use: - -Parameter name | Type | Format | Description -------------------------------------|------------------|---------|-------------- -`u_terrain_detailmap` | `sampler2D` | `R8` | This one contains the grass density, from 0 to 1. Depending on this, you may hide instances by outputting degenerate triangles, or let them pass through. The builtin shader contains an example. -`u_albedo_alpha` | `sampler2D` | `RGBA8` | This is the texture applied to the whole model, typically transparent grass. -`u_view_distance` | `float` | | How far details are supposed to render. Beyond this range, the plugin will cull chunks away, so it is a good idea to use this in the shader to smoothly fade pixels in the distance to hide this process. -`u_ambient_wind` | `vec2` | | Combined `vec2` parameter for ambient wind. `x` is the amplitude, and `y` is a time value. It is better to use it instead of directly `TIME` because it allows to animate speed without causing stutters. - - -### Lookdev - -The plugin features an experimental debugging feature in the `Terrain` menu called "Lookdev". It temporarily replaces the ground shader with a simpler one which displays the raw value of a specific map. For example, you can see the actual values taken by a detail map by choosing one of them in the menu: - -![Screenshot of detail map seen with lookdev shader](images/lookdev_grass.png) - -It is very simple at the moment but it can also be used to display data maps which are not necessarily used for rendering. So you could also use it to paint them, even if they don't translate into a visual element in the game. - -To turn it off, select `Disabled` in the menu. - -![Screenshot of detail map seen with lookdev shader](images/lookdev_menu.png) - -!!! note - The heightmap cannot be seen with this feature because its values extend beyond usual color ranges. - - -Scripting --------------- - -### Overview - -Scripts relevant to in-game functionality are located under the plugin's root folder, `res://addons/zylann.hterrain/`. - -``` -res:// -- addons/ - - zylann.hterrain/ - - doc/ - - models/ <-- Models used for grass - - native/ <-- GDNative library - - shaders/ - - tools/ <-- Editor-specific stuff, don't use in game - - util/ <-- Various helper scripts - - - hterrain.gd <-- The HTerrain node - - hterrain_data.gd <-- The HTerrainData resource - - hterrain_detail_layer.gd <-- The HTerrainDetailLayer node - - - (other stuff used internally) -``` - -This plugin does not use global class names, so to use or hint one of these types, you may want to "const-import" them on top of your script, like so: - -```gdscript -const HTerrain = preload("res://addons/zylann.hterrain/hterrain.gd") -``` - -There is no API documentation yet, so if you want to see which functions and properties are available, take a look at the source code in the editor. -Functions and properties beginning with a `_` are private and should not be used directly. - - -### Creating the terrain from script - -You can decide to create the terrain from a script. Here is an example: - -```gdscript -extends Node - -const HTerrain = preload("res://addons/zylann.hterrain/hterrain.gd") -const HTerrainData = preload("res://addons/zylann.hterrain/hterrain_data.gd") - -func _ready(): - var data = HTerrainData.new() - data.resize(513) - - var terrain = HTerrain.new() - terrain.set_data(data) - add_child(terrain) -``` - -### Modifying terrain from script - -The terrain is described by several types of large textures, such as heightmap, normal map, grass maps, color map and so on. Modifying the terrain boils down to modifying them using the `Image` API. - -For example, this code will tint the ground red at a specific position (in pixels, not world space): - -```gdscript -const HTerrainData = preload("res://addons/zylann.hterrain/hterrain_data.gd") - -onready var _terrain = $Path/To/Terrain - -func test(): - # Get the image - var data : HTerrainData = _terrain.get_data() - var colormap : Image = data.get_image(HTerrainData.CHANNEL_COLOR) - - # Modify the image - var position = Vector2(42, 36) - colormap.lock() - colormap.set_pixel(position, Color(1, 0, 0)) - colormap.unlock() - - # Notify the terrain of our change - data.notify_region_changed(Rect2(position.x, position.y, 1, 1), HTerrainData.CHANNEL_COLOR) -``` - -The same goes for the heightmap and grass maps, however at time of writing, there are several issues with editing it in game: - -- Normals of the terrain don't automatically update, you have to calculate them yourself by also modifying the normalmap. This is a bit tedious and expensive, however it may be improved in the future. Alternatively you could compute them in shader, but it makes rendering a bit more expensive. -- The collider won't update either, for the same reason mentioned in the [section about collisions in the editor](#Collisions). You can force it to update by calling `update_collider()` but it can cause a hiccup. - - -### Procedural generation - -It is possible to generate the terrain data entirely from script. It may be quite slow if you don't take advantage of GPU techniques (such as using a compute viewport), but it's still useful to copy results to the terrain or editing it like the plugin does in the editor. - -Again, we can use the `Image` resource to modify pixels. -Here is a full GDScript example generating a terrain from noise and 3 textures: - -```gdscript -extends Node - -# Import classes -const HTerrain = preload("res://addons/zylann.hterrain/hterrain.gd") -const HTerrainData = preload("res://addons/zylann.hterrain/hterrain_data.gd") -const HTerrainTextureSet = preload("res://addons/zylann.hterrain/hterrain_texture_set.gd") - -# You may want to change paths to your own textures -var grass_texture = load("res://addons/zylann.hterrain_demo/textures/ground/grass_albedo_bump.png") -var sand_texture = load("res://addons/zylann.hterrain_demo/textures/ground/sand_albedo_bump.png") -var leaves_texture = load("res://addons/zylann.hterrain_demo/textures/ground/leaves_albedo_bump.png") - - -func _ready(): - # Create terrain resource and give it a size. - # It must be either 513, 1025, 2049 or 4097. - var terrain_data = HTerrainData.new() - terrain_data.resize(513) - - var noise = OpenSimplexNoise.new() - var noise_multiplier = 50.0 - - # Get access to terrain maps - var heightmap: Image = terrain_data.get_image(HTerrainData.CHANNEL_HEIGHT) - var normalmap: Image = terrain_data.get_image(HTerrainData.CHANNEL_NORMAL) - var splatmap: Image = terrain_data.get_image(HTerrainData.CHANNEL_SPLAT) - - heightmap.lock() - normalmap.lock() - splatmap.lock() - - # Generate terrain maps - # Note: this is an example with some arbitrary formulas, - # you may want to come up with your owns - for z in heightmap.get_height(): - for x in heightmap.get_width(): - # Generate height - var h = noise_multiplier * noise.get_noise_2d(x, z) - - # Getting normal by generating extra heights directly from noise, - # so map borders won't have seams in case you stitch them - var h_right = noise_multiplier * noise.get_noise_2d(x + 0.1, z) - var h_forward = noise_multiplier * noise.get_noise_2d(x, z + 0.1) - var normal = Vector3(h - h_right, 0.1, h_forward - h).normalized() - - # Generate texture amounts - var splat = splatmap.get_pixel(x, z) - var slope = 4.0 * normal.dot(Vector3.UP) - 2.0 - # Sand on the slopes - var sand_amount = clamp(1.0 - slope, 0.0, 1.0) - # Leaves below sea level - var leaves_amount = clamp(0.0 - h, 0.0, 1.0) - splat = splat.linear_interpolate(Color(0,1,0,0), sand_amount) - splat = splat.linear_interpolate(Color(0,0,1,0), leaves_amount) - - heightmap.set_pixel(x, z, Color(h, 0, 0)) - normalmap.set_pixel(x, z, HTerrainData.encode_normal(normal)) - splatmap.set_pixel(x, z, splat) - - heightmap.unlock() - normalmap.unlock() - splatmap.unlock() - - # Commit modifications so they get uploaded to the graphics card - var modified_region = Rect2(Vector2(), heightmap.get_size()) - terrain_data.notify_region_change(modified_region, HTerrainData.CHANNEL_HEIGHT) - terrain_data.notify_region_change(modified_region, HTerrainData.CHANNEL_NORMAL) - terrain_data.notify_region_change(modified_region, HTerrainData.CHANNEL_SPLAT) - - # Create texture set - # NOTE: usually this is not made from script, it can be built with editor tools - var texture_set = HTerrainTextureSet.new() - texture_set.set_mode(HTerrainTextureSet.MODE_TEXTURES) - texture_set.insert_slot(-1) - texture_set.set_texture(0, HTerrainTextureSet.TYPE_ALBEDO_BUMP, grass_texture) - texture_set.insert_slot(-1) - texture_set.set_texture(1, HTerrainTextureSet.TYPE_ALBEDO_BUMP, sand_texture) - texture_set.insert_slot(-1) - texture_set.set_texture(2, HTerrainTextureSet.TYPE_ALBEDO_BUMP, leaves_texture) - - # Create terrain node - var terrain = HTerrain.new() - terrain.set_shader_type(HTerrain.SHADER_CLASSIC4_LITE) - terrain.set_data(terrain_data) - terrain.set_texture_set(texture_set) - add_child(terrain) - - # No need to call this, but you may need to if you edit the terrain later on - #terrain.update_collider() -``` - - -Export ----------- - -The plugin should work normally in exported games, but there are some files you should be able to remove because they are editor-specific. This allows to reduce the size from the executable a little. - -Everything under `res://addons/zylann.hterrain/tools/` folder is required for the plugin to work in the editor, but it can be removed in exported games. You can specify this folder in your export presets: - -![Screenshot of the export window with tools folder ignored](images/ignore_tools_on_export.png) - -The documentation in `res://addons/zylann.hterrain/doc/` can also be removed, but this one contains a `.gdignore` file so hopefully Godot will automatically ignore it even in the editor. - - -GDNative ------------ - -This plugin contains an optional native component, which speeds up some operations such as sculpting the terrain. However, at time of writing, a prebuilt binary is built-in only on `Windows` and `Linux`, I'm not yet able to build for other platforms so you may need to do it yourself, until I can provide an official one. - -Before doing this, it's preferable to close the Godot editor so it won't lock the library files. -Note that these steps are very similar to GDNative C++ development, which repeats parts of [Godot's documentation](https://docs.godotengine.org/en/3.2/tutorials/plugins/gdnative/gdnative-cpp-example.html). - -### Building instructions - -To build the library, you will need to install the following: - -- Python 3.6 or later -- The SCons build system -- A C++ compiler -- The Git version control system - -#### If you got the plugin from the asset library - -You will need to download C++ bindings for Godot. Go to `res://addons/zylann.hterrain/native`, open a command prompt, and run the following commands: - -``` -git clone https://github.com/GodotNativeTools/godot-cpp -cd godot-cpp -git submodule update --init --recursive -``` - -#### If you cloned the plugin using Git - -In this case the C++ bindings submodule will already be there, and will need to be updated. Go to `res://addons/zylann.hterrain/native`, open a command prompt, and run the following commands: - -``` -git submodule update --init --recursive target=release -``` - -#### Build C++ bindings - -Now go to `res://addons/zylann.hterrain/native/cpp-bindings`, open a command prompt (or re-use the one you have already), and run this command: - -``` -scons platform= generate_bindings=yes target=release -``` - -`yourplatform` must match the platform you want to build for. It should be one of the following: - -- `windows` -- `linux` -- `osx` - -#### Build the HTerrain library - -Go back to `res://addons/zylann.hterrain/native`, and run this command, which has similar options as the one we saw before: - -``` -scons platform= target=release -``` - -This will produce a library file under the `bin/` folder. - -### Register the library - -Now the last step is to tell the plugin the library is available. In the `native/` folder, open the `hterrain.gdnlib` resource in a text editor, and add the path to the library under the `[entry]` category. Here is an example of how it should look like for several platforms: - -``` -[general] - -singleton=false -load_once=true -symbol_prefix="godot_" -reloadable=false - -[entry] - -OSX.64 = "res://addons/zylann.hterrain/native/bin/osx64/libhterrain_native.dylib" -OSX.32 = "res://addons/zylann.hterrain/native/bin/osx32/libhterrain_native.dylib" -Windows.64 = "res://addons/zylann.hterrain/native/bin/win64/libhterrain_native.dll" -X11.64 = "res://addons/zylann.hterrain/native/bin/linux/libhterrain_native.so" - -[dependencies] - -Windows.64=[ ] -X11.64=[ ] -``` - -Finally, open the `factory.gd` script, and add an OS entry for your platform. The plugin should now be ready to use the native library. - -### Debugging - -If you get a crash or misbehavior, check logs first to make sure Godot was able to load the library. If you want to use a C++ debugger, you can repeat this setup, only replacing `release` with `debug` when running SCons. This will then allow you to attach to Godot and place breakpoints (which works best if you also use a debug Godot version). - - -Troubleshooting ------------------ - -We do the best we can on our free time to make this plugin usable, but it's possible bugs appear. Some of them are known issues. If you have a problem, please refer to the [issue tracker](https://github.com/Zylann/godot_heightmap_plugin/issues). - - -### Before reporting any bug - -- Make sure you have the latest version of the plugin -- Make sure it hasn't been reported already (including closed issues) -- Check your Godot version. This plugin only works starting from Godot 3.1, and does not support 4.x yet. It is also possible that some issues exist in Godot 3.1 but could only be fixed in later versions. -- Make sure you are using the GLES3 renderer. GLES2 is not supported. -- Make sure your addons folder is located at `res://addons`, and does not contain uppercase letters. This might work on Windows but it will break after export. - - -### If you report a new bug - -If none of the initial checks help and you want to post a new issue, do the following: - -- Check the console for messages, warnings and errors. These are helpful to diagnose the issue. -- Try to reproduce the bug with precise reproduction steps, and indicate them -- Provide a test project with those steps (unless it's reproducible from an empty project), so that we can reproduce the bug and fix it more easily. Github allows you to drag-and-drop zip files. -- Indicate your OS, Godot version and graphics card model. Those are present in logs as well. - - -### Terrain not saving / not up to date / not showing - -This issue happened a few times and had various causes so if the checks mentioned before don't help: - -- Check the contents of your terrain's data folder. It must contain a `.hterrain` file and a few textures. -- If they are present, make sure Godot has imported those textures. If it didn't, unfocus the editor, and focus it back (you should see a short progress bar as it does it) -- Check if you used Ctrl+Z (undo) after a non-undoable action, like described in [issue #101](https://github.com/Zylann/godot_heightmap_plugin/issues/101) -- Make sure your `res://addons` folder is named `addons` *exactly lowercase*. It should not be named `Addons`. Plugins can fail if this convention is not respected. -- If your problem relates to collisions in editor, update the collider using `Terrain -> Update Editor Collider`, because this one does not update automatically yet -- Godot seems to randomly forget where the terrain saver is, but I need help to find out why because I could never reproduce it. See [issue #120](https://github.com/Zylann/godot_heightmap_plugin/issues/120) - - -### Temporary files - -The plugin creates temporary files to avoid cluttering memory. They are necessary for some functionalities to work. Those files should be cleaned up automatically when you close the editor or if you turn off the plugin. However, if a crash occurs or something else goes wrong, they might not get removed. If you want to check them out, they are located in `user://hterrain_image_cache`. - -On Windows, that directory corresponds to `C:\Users\Username\AppData\Roaming\Godot\app_userdata\ProjectName\hterrain_image_cache`. - -See [Godot's documentation](https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html#editor-data-paths) for other platforms. diff --git a/addons/zylann.hterrain/doc/mkdocs.yml b/addons/zylann.hterrain/doc/mkdocs.yml deleted file mode 100644 index 17a6625..0000000 --- a/addons/zylann.hterrain/doc/mkdocs.yml +++ /dev/null @@ -1,11 +0,0 @@ -site_name: HTerrain plugin documentation -theme: readthedocs - -markdown_extensions: - # Makes permalinks appear on headings - - toc: - permalink: True - # Makes boxes for notes and warnings - - admonition - # Better highlighter which supports GDScript - - codehilite diff --git a/addons/zylann.hterrain/doc/requirements.txt b/addons/zylann.hterrain/doc/requirements.txt deleted file mode 100644 index 3143080..0000000 --- a/addons/zylann.hterrain/doc/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -mkdocs>=1.1.2 \ No newline at end of file diff --git a/addons/zylann.hterrain/hterrain.gd b/addons/zylann.hterrain/hterrain.gd deleted file mode 100644 index 4a186a7..0000000 --- a/addons/zylann.hterrain/hterrain.gd +++ /dev/null @@ -1,1665 +0,0 @@ -@tool -extends Node3D - -const HT_NativeFactory = preload("./native/factory.gd") -const HT_Mesher = preload("./hterrain_mesher.gd") -const HT_Grid = preload("./util/grid.gd") -const HTerrainData = preload("./hterrain_data.gd") -const HTerrainChunk = preload("./hterrain_chunk.gd") -const HTerrainChunkDebug = preload("./hterrain_chunk_debug.gd") -const HT_Util = preload("./util/util.gd") -const HTerrainCollider = preload("./hterrain_collider.gd") -const HTerrainTextureSet = preload("./hterrain_texture_set.gd") -const HT_Logger = preload("./util/logger.gd") - -const SHADER_CLASSIC4 = "Classic4" -const SHADER_CLASSIC4_LITE = "Classic4Lite" -const SHADER_LOW_POLY = "LowPoly" -const SHADER_ARRAY = "Array" -const SHADER_MULTISPLAT16 = "MultiSplat16" -const SHADER_MULTISPLAT16_LITE = "MultiSplat16Lite" -const SHADER_CUSTOM = "Custom" - -const MIN_MAP_SCALE = 0.01 - -# Note, the `str()` syntax is no longer accepted in constants in Godot 4 -const _SHADER_TYPE_HINT_STRING = \ - "Classic4," + \ - "Classic4Lite," + \ - "LowPoly," + \ - "Array," + \ - "MultiSplat16," + \ - "MultiSplat16Lite," + \ - "Custom" - -# TODO Had to downgrade this to support Godot 3.1. -# Referring to other constants with this syntax isn't working... -#const _SHADER_TYPE_HINT_STRING = str( -# SHADER_CLASSIC4, ",", -# SHADER_CLASSIC4_LITE, ",", -# SHADER_LOW_POLY, ",", -# SHADER_ARRAY, ",", -# SHADER_CUSTOM -#) - -const _builtin_shaders = { - SHADER_CLASSIC4: { - path = "res://addons/zylann.hterrain/shaders/simple4.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/simple4_global.gdshader" - }, - SHADER_CLASSIC4_LITE: { - path = "res://addons/zylann.hterrain/shaders/simple4_lite.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/simple4_global.gdshader" - }, - SHADER_LOW_POLY: { - path = "res://addons/zylann.hterrain/shaders/low_poly.gdshader", - global_path = "" # Not supported - }, - SHADER_ARRAY: { - path = "res://addons/zylann.hterrain/shaders/array.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/array_global.gdshader" - }, - SHADER_MULTISPLAT16: { - path = "res://addons/zylann.hterrain/shaders/multisplat16.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/multisplat16_global.gdshader" - }, - SHADER_MULTISPLAT16_LITE: { - path = "res://addons/zylann.hterrain/shaders/multisplat16_lite.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/multisplat16_global.gdshader" - } -} - -const _NORMAL_BAKER_PATH = "res://addons/zylann.hterrain/tools/normalmap_baker.gd" -const _LOOKDEV_SHADER_PATH = "res://addons/zylann.hterrain/shaders/lookdev.gdshader" - -const SHADER_PARAM_INVERSE_TRANSFORM = "u_terrain_inverse_transform" -const SHADER_PARAM_NORMAL_BASIS = "u_terrain_normal_basis" - -const SHADER_PARAM_GROUND_PREFIX = "u_ground_" # + name + _0, _1, _2, _3... - -# Those parameters are filtered out in the inspector, -# because they are not supposed to be set through it -const _api_shader_params = { - "u_terrain_heightmap": true, - "u_terrain_normalmap": true, - "u_terrain_colormap": true, - "u_terrain_splatmap": true, - "u_terrain_splatmap_1": true, - "u_terrain_splatmap_2": true, - "u_terrain_splatmap_3": true, - "u_terrain_splat_index_map": true, - "u_terrain_splat_weight_map": true, - "u_terrain_globalmap": true, - - "u_terrain_inverse_transform": true, - "u_terrain_normal_basis": true, - - "u_ground_albedo_bump_0": true, - "u_ground_albedo_bump_1": true, - "u_ground_albedo_bump_2": true, - "u_ground_albedo_bump_3": true, - - "u_ground_normal_roughness_0": true, - "u_ground_normal_roughness_1": true, - "u_ground_normal_roughness_2": true, - "u_ground_normal_roughness_3": true, - - "u_ground_albedo_bump_array": true, - "u_ground_normal_roughness_array": true -} - -const _api_shader_ground_albedo_params = { - "u_ground_albedo_bump_0": true, - "u_ground_albedo_bump_1": true, - "u_ground_albedo_bump_2": true, - "u_ground_albedo_bump_3": true -} - -const _ground_texture_array_shader_params = [ - "u_ground_albedo_bump_array", - "u_ground_normal_roughness_array" -] - -const _splatmap_shader_params = [ - "u_terrain_splatmap", - "u_terrain_splatmap_1", - "u_terrain_splatmap_2", - "u_terrain_splatmap_3" -] - -const MIN_CHUNK_SIZE = 16 -const MAX_CHUNK_SIZE = 64 - -# Same as HTerrainTextureSet.get_texture_type_name, used for shader parameter names. -# Indexed by HTerrainTextureSet.TYPE_* -const _ground_enum_to_name = [ - "albedo_bump", - "normal_roughness" -] - -const _DEBUG_AABB = false - -signal transform_changed(global_transform) - -@export_range(0.0, 1.0) var ambient_wind : float: - get: - return ambient_wind - set(amplitude): - if ambient_wind == amplitude: - return - ambient_wind = amplitude - for layer in _detail_layers: - layer.update_material() - - -@export_range(2, 5) var lod_scale := 2.0: - get: - return lod_scale - set(value): - _lodder.set_split_scale(value) - - -# Prefer using this instead of scaling the node's transform. -# Node3D.scale isn't used because it's not suitable for terrains, -# it would scale grass too and other environment objects. -# TODO Replace with `size` in world units? -@export var map_scale := Vector3(1, 1, 1): - get: - return map_scale - set(p_map_scale): - if map_scale == p_map_scale: - return - p_map_scale.x = maxf(p_map_scale.x, MIN_MAP_SCALE) - p_map_scale.y = maxf(p_map_scale.y, MIN_MAP_SCALE) - p_map_scale.z = maxf(p_map_scale.z, MIN_MAP_SCALE) - map_scale = p_map_scale - _on_transform_changed() - - -@export var centered := false: - get: - return centered - set(p_centered): - if p_centered == centered: - return - centered = p_centered - _on_transform_changed() - - -var _custom_shader : Shader = null -var _custom_globalmap_shader : Shader = null -var _shader_type := SHADER_CLASSIC4_LITE -var _shader_uses_texture_array := false -var _material := ShaderMaterial.new() -var _material_params_need_update := false -# Possible values are the same as the enum `GeometryInstance.SHADOW_CASTING_SETTING_*`. -var _cast_shadow_setting := GeometryInstance3D.SHADOW_CASTING_SETTING_ON - -var _render_layer_mask := 1 - -# Actual number of textures supported by the shader currently selected -var _ground_texture_count_cache := 0 - -var _used_splatmaps_count_cache := 0 -var _is_using_indexed_splatmap := false - -var _texture_set := HTerrainTextureSet.new() -var _texture_set_migration_textures = null - -var _data: HTerrainData = null - -var _mesher := HT_Mesher.new() -var _lodder = HT_NativeFactory.get_quad_tree_lod() -var _viewer_pos_world := Vector3() - -# [lod][z][x] -> chunk -# This container owns chunks -var _chunks := [] -var _chunk_size: int = 32 -var _pending_chunk_updates := [] - -var _detail_layers := [] - -var _collision_enabled := true -var _collider: HTerrainCollider = null -var _collision_layer := 1 -var _collision_mask := 1 - -# Stats & debug -var _updated_chunks := 0 -var _logger = HT_Logger.get_for(self) - -# Editor-only -var _normals_baker = null - -var _lookdev_enabled := false -var _lookdev_material : ShaderMaterial - - -func _init(): - _logger.debug("Create HeightMap") - # This sets up the defaults. They may be overridden shortly after by the scene loader. - - _lodder.set_callbacks(_cb_make_chunk, _cb_recycle_chunk, _cb_get_vertical_bounds) - - set_notify_transform(true) - - # TODO Temporary! - # This is a workaround for https://github.com/godotengine/godot/issues/24488 - _material.set_shader_parameter("u_ground_uv_scale", 20) - _material.set_shader_parameter("u_ground_uv_scale_vec4", Color(20, 20, 20, 20)) - _material.set_shader_parameter("u_depth_blending", true) - - _material.shader = load(_builtin_shaders[_shader_type].path) - - _texture_set.changed.connect(_on_texture_set_changed) - - if _collision_enabled: - if _check_heightmap_collider_support(): - _collider = HTerrainCollider.new(self, _collision_layer, _collision_mask) - - -func _get_property_list(): - # A lot of properties had to be exported like this instead of using `export`, - # because Godot 3 does not support easy categorization and lacks some hints - var props = [ - { - # Terrain data is exposed only as a path in the editor, - # because it can only be saved if it has a directory selected. - # That property is not used in scene saving (data is instead). - "name": "data_directory", - "type": TYPE_STRING, - "usage": PROPERTY_USAGE_EDITOR, - "hint": PROPERTY_HINT_DIR - }, - { - # The actual data resource is only exposed for storage. - # I had to name it so that Godot won't try to assign _data directly - # instead of using the setter I made... - "name": "_terrain_data", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - # This actually triggers `ERROR: Cannot get class`, - # if it were to be shown in the inspector. - # See https://github.com/godotengine/godot/pull/41264 - "hint_string": "HTerrainData" - }, - { - "name": "chunk_size", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - #"hint": PROPERTY_HINT_ENUM, - "hint_string": "16, 32" - }, - { - "name": "Collision", - "type": TYPE_NIL, - "usage": PROPERTY_USAGE_GROUP - }, - { - "name": "collision_enabled", - "type": TYPE_BOOL, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE - }, - { - "name": "collision_layer", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_LAYERS_3D_PHYSICS - }, - { - "name": "collision_mask", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_LAYERS_3D_PHYSICS - }, - { - "name": "Rendering", - "type": TYPE_NIL, - "usage": PROPERTY_USAGE_GROUP - }, - { - "name": "shader_type", - "type": TYPE_STRING, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_ENUM, - "hint_string": _SHADER_TYPE_HINT_STRING - }, - { - "name": "custom_shader", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - "hint_string": "Shader" - }, - { - "name": "custom_globalmap_shader", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - "hint_string": "Shader" - }, - { - "name": "texture_set", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - "hint_string": "Resource" - # TODO Cannot properly hint the type of the resource in the inspector. - # This triggers `ERROR: Cannot get class 'HTerrainTextureSet'` - # See https://github.com/godotengine/godot/pull/41264 - #"hint_string": "HTerrainTextureSet" - }, - { - "name": "render_layers", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_LAYERS_3D_RENDER - }, - { - "name": "cast_shadow", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_ENUM, - "hint_string": "Off,On,DoubleSided,ShadowsOnly" - } - ] - - if _material.shader != null: - var shader_params := RenderingServer.get_shader_parameter_list(_material.shader.get_rid()) - for p in shader_params: - if _api_shader_params.has(p.name): - continue - var cp := {} - for k in p: - cp[k] = p[k] - cp.name = str("shader_params/", p.name) - props.append(cp) - - return props - - -func _get(key: StringName): - if key == &"data_directory": - return _get_data_directory() - - if key == &"_terrain_data": - if _data == null or _data.resource_path == "": - # Consider null if the data is not set or has no path, - # because in those cases we can't save the terrain properly - return null - else: - return _data - - if key == &"texture_set": - return get_texture_set() - - elif key == &"shader_type": - return get_shader_type() - - elif key == &"custom_shader": - return get_custom_shader() - - elif key == &"custom_globalmap_shader": - return _custom_globalmap_shader - - elif key.begins_with("shader_params/"): - var param_name := key.substr(len("shader_params/")) - return get_shader_param(param_name) - - elif key == &"chunk_size": - return _chunk_size - - elif key == &"collision_enabled": - return _collision_enabled - - elif key == &"collision_layer": - return _collision_layer - - elif key == &"collision_mask": - return _collision_mask - - elif key == &"render_layers": - return get_render_layer_mask() - - elif key == &"cast_shadow": - return _cast_shadow_setting - - -func _set(key: StringName, value): - if key == &"data_directory": - _set_data_directory(value) - - # Can't use setget when the exported type is custom, - # because we were also are forced to use _get_property_list... - elif key == &"_terrain_data": - set_data(value) - - elif key == &"texture_set": - set_texture_set(value) - - # Legacy, left for migration from 1.4 - var key_str := String(key) - if key_str.begins_with("ground/"): - for ground_texture_type in HTerrainTextureSet.TYPE_COUNT: - var type_name = _ground_enum_to_name[ground_texture_type] - if key_str.begins_with(str("ground/", type_name, "_")): - var i = key_str.substr(len(key_str) - 1).to_int() - if _texture_set_migration_textures == null: - _texture_set_migration_textures = [] - while i >= len(_texture_set_migration_textures): - _texture_set_migration_textures.append([null, null]) - var texs = _texture_set_migration_textures[i] - texs[ground_texture_type] = value - - elif key == &"shader_type": - set_shader_type(value) - - elif key == &"custom_shader": - set_custom_shader(value) - - elif key == &"custom_globalmap_shader": - _custom_globalmap_shader = value - - elif key.begins_with("shader_params/"): - var param_name := String(key).substr(len("shader_params/")) - set_shader_param(param_name, value) - - elif key == &"chunk_size": - set_chunk_size(value) - - elif key == &"collision_enabled": - set_collision_enabled(value) - - elif key == &"collision_layer": - _collision_layer = value - if _collider != null: - _collider.set_collision_layer(value) - - elif key == &"collision_mask": - _collision_mask = value - if _collider != null: - _collider.set_collision_mask(value) - - elif key == &"render_layers": - return set_render_layer_mask(value) - - elif key == &"cast_shadow": - set_cast_shadow(value) - - -func get_texture_set() -> HTerrainTextureSet: - return _texture_set - - -func set_texture_set(new_set: HTerrainTextureSet): - if _texture_set == new_set: - return - - if _texture_set != null: - # TODO This causes `ERROR: Nonexistent signal 'changed' in [Resource:36653]` for some reason - _texture_set.changed.disconnect(_on_texture_set_changed) - - _texture_set = new_set - - if _texture_set != null: - _texture_set.changed.connect(_on_texture_set_changed) - - _material_params_need_update = true - - -func _on_texture_set_changed(): - _material_params_need_update = true - HT_Util.update_configuration_warning(self, false) - - -func get_shader_param(param_name: String): - return _material.get_shader_parameter(param_name) - - -func set_shader_param(param_name: String, v): - _material.set_shader_parameter(param_name, v) - - -func set_render_layer_mask(mask: int): - _render_layer_mask = mask - _for_all_chunks(HT_SetRenderLayerMaskAction.new(mask)) - - -func get_render_layer_mask() -> int: - return _render_layer_mask - - -func set_cast_shadow(setting: int): - if setting == _cast_shadow_setting: - return - _cast_shadow_setting = setting - _for_all_chunks(HT_SetCastShadowSettingAction.new(setting)) - - -func get_cast_shadow() -> int: - return _cast_shadow_setting - - -func _set_data_directory(dirpath: String): - if dirpath != _get_data_directory(): - if dirpath == "": - set_data(null) - else: - var fpath := dirpath.path_join(HTerrainData.META_FILENAME) - if FileAccess.file_exists(fpath): - # Load existing - var d = load(fpath) - set_data(d) - else: - # Create new - var d := HTerrainData.new() - d.resource_path = fpath - set_data(d) - else: - _logger.warn("Setting twice the same terrain directory??") - - -func _get_data_directory() -> String: - if _data != null: - return _data.resource_path.get_base_dir() - return "" - - -func _check_heightmap_collider_support() -> bool: - return true - # var v = Engine.get_version_info() - # if v.major == 3 and v.minor == 0 and v.patch < 4: - # _logger.error("Heightmap collision shape not supported in this version of Godot," - # + " please upgrade to 3.0.4 or later") - # return false - # return true - - -func set_collision_enabled(enabled: bool): - if _collision_enabled != enabled: - _collision_enabled = enabled - if _collision_enabled: - if _check_heightmap_collider_support(): - _collider = HTerrainCollider.new(self, _collision_layer, _collision_mask) - # Collision is not updated with data here, - # because loading is quite a mess at the moment... - # 1) This function can be called while no data has been set yet - # 2) I don't want to update the collider more times than necessary - # because it's expensive - # 3) I would prefer not defer that to the moment the terrain is - # added to the tree, because it would screw up threaded loading - else: - # Despite this object being a Reference, - # this should free it, as it should be the only reference - _collider = null - - -func _for_all_chunks(action): - for lod in len(_chunks): - var grid = _chunks[lod] - for y in len(grid): - var row = grid[y] - for x in len(row): - var chunk = row[x] - if chunk != null: - action.exec(chunk) - - -func get_chunk_size() -> int: - return _chunk_size - - -func set_chunk_size(p_cs: int): - assert(typeof(p_cs) == TYPE_INT) - _logger.debug(str("Setting chunk size to ", p_cs)) - var cs := HT_Util.next_power_of_two(p_cs) - if cs < MIN_CHUNK_SIZE: - cs = MIN_CHUNK_SIZE - if cs > MAX_CHUNK_SIZE: - cs = MAX_CHUNK_SIZE - if p_cs != cs: - _logger.debug(str("Chunk size snapped to ", cs)) - if cs == _chunk_size: - return - _chunk_size = cs - _reset_ground_chunks() - - -# Compat -func set_map_scale(p_map_scale: Vector3): - map_scale = p_map_scale - - -# Compat -func set_centered(p_centered: bool): - centered = p_centered - - -# Gets the global transform to apply to terrain geometry, -# which is different from Node3D.global_transform gives. -# global_transform must only have translation and rotation. Scale support is undefined. -func get_internal_transform() -> Transform3D: - var gt := global_transform - var it := Transform3D(gt.basis * Basis().scaled(map_scale), gt.origin) - if centered and _data != null: - var half_size := 0.5 * (_data.get_resolution() - 1.0) - it.origin += it.basis * (-Vector3(half_size, 0, half_size)) - return it - - -func get_internal_transform_unscaled(): - var gt := global_transform - if centered and _data != null: - var half_size := 0.5 * (_data.get_resolution() - 1.0) - gt.origin += gt.basis * (-Vector3(half_size, 0, half_size)) - return gt - - -# Converts a world-space position into a map-space position. -# Map space X and Z coordinates correspond to pixel coordinates of the heightmap. -func world_to_map(world_pos: Vector3) -> Vector3: - return get_internal_transform().affine_inverse() * world_pos - - -func _notification(what: int): - match what: - NOTIFICATION_PREDELETE: - _logger.debug("Destroy HTerrain") - # Note: might get rid of a circular ref in GDScript port - _clear_all_chunks() - - NOTIFICATION_ENTER_WORLD: - _logger.debug("Enter world") - - if _texture_set_migration_textures != null and _texture_set.get_slots_count() == 0: - # Convert from 1.4 textures properties to HTerrainTextureSet - # TODO Unfortunately this might not always work, - # once again because Godot wants the editor's UndoRedo to have modified the - # resource for it to be saved... which sucks, sucks, and sucks. - # I'll never say it enough. - _texture_set.set_mode(HTerrainTextureSet.MODE_TEXTURES) - while _texture_set.get_slots_count() < len(_texture_set_migration_textures): - _texture_set.insert_slot(-1) - for slot_index in len(_texture_set_migration_textures): - var texs = _texture_set_migration_textures[slot_index] - for type in len(texs): - _texture_set.set_texture(slot_index, type, texs[type]) - _texture_set_migration_textures = null - - _for_all_chunks(HT_EnterWorldAction.new(get_world_3d())) - if _collider != null: - _collider.set_world(get_world_3d()) - _collider.set_transform(get_internal_transform()) - - NOTIFICATION_EXIT_WORLD: - _logger.debug("Exit world") - _for_all_chunks(HT_ExitWorldAction.new()) - if _collider != null: - _collider.set_world(null) - - NOTIFICATION_TRANSFORM_CHANGED: - _on_transform_changed() - - NOTIFICATION_VISIBILITY_CHANGED: - _logger.debug("Visibility changed") - _for_all_chunks(HT_VisibilityChangedAction.new(is_visible_in_tree())) - - -func _on_transform_changed(): - _logger.debug("Transform changed") - - if not is_inside_tree(): - # The transform and other properties can be set by the scene loader, - # before we enter the tree - return - - var gt = get_internal_transform() - - _for_all_chunks(HT_TransformChangedAction.new(gt)) - - _material_params_need_update = true - - if _collider != null: - _collider.set_transform(gt) - - transform_changed.emit(gt) - - -func _enter_tree(): - _logger.debug("Enter tree") - - if Engine.is_editor_hint() and _normals_baker == null: - _normals_baker = load(_NORMAL_BAKER_PATH).new() - add_child(_normals_baker) - _normals_baker.set_terrain_data(_data) - - set_process(true) - - -func _clear_all_chunks(): - # The lodder has to be cleared because otherwise it will reference dangling pointers - _lodder.clear() - - #_for_all_chunks(DeleteChunkAction.new()) - - for i in len(_chunks): - _chunks[i].clear() - - -func _get_chunk_at(pos_x: int, pos_y: int, lod: int) -> HTerrainChunk: - if lod < len(_chunks): - return HT_Grid.grid_get_or_default(_chunks[lod], pos_x, pos_y, null) - return null - - -func get_data() -> HTerrainData: - return _data - - -func has_data() -> bool: - return _data != null - - -func set_data(new_data: HTerrainData): - assert(new_data == null or new_data is HTerrainData) - - _logger.debug(str("Set new data ", new_data)) - - if _data == new_data: - return - - if has_data(): - _logger.debug("Disconnecting old HeightMapData") - _data.resolution_changed.disconnect(_on_data_resolution_changed) - _data.region_changed.disconnect(_on_data_region_changed) - _data.map_changed.disconnect(_on_data_map_changed) - _data.map_added.disconnect(_on_data_map_added) - _data.map_removed.disconnect(_on_data_map_removed) - - if _normals_baker != null: - _normals_baker.set_terrain_data(null) - _normals_baker.queue_free() - _normals_baker = null - - _data = new_data - - # Note: the order of these two is important - _clear_all_chunks() - - if has_data(): - _logger.debug("Connecting new HeightMapData") - - # This is a small UX improvement so that the user sees a default terrain - if is_inside_tree() and Engine.is_editor_hint(): - if _data.get_resolution() == 0: - _data._edit_load_default() - - if _collider != null: - _collider.create_from_terrain_data(_data) - - _data.resolution_changed.connect(_on_data_resolution_changed) - _data.region_changed.connect(_on_data_region_changed) - _data.map_changed.connect(_on_data_map_changed) - _data.map_added.connect(_on_data_map_added) - _data.map_removed.connect(_on_data_map_removed) - - if _normals_baker != null: - _normals_baker.set_terrain_data(_data) - - _on_data_resolution_changed() - - _material_params_need_update = true - - HT_Util.update_configuration_warning(self, true) - - _logger.debug("Set data done") - - -# The collider might be used in editor for other tools (like snapping to floor), -# so the whole collider can be updated in one go. -# It may be slow for ingame use, so prefer calling it when appropriate. -func update_collider(): - assert(_collision_enabled) - assert(_collider != null) - _collider.create_from_terrain_data(_data) - - -func _on_data_resolution_changed(): - _reset_ground_chunks() - - -func _reset_ground_chunks(): - if _data == null: - return - - _clear_all_chunks() - - _pending_chunk_updates.clear() - - _lodder.create_from_sizes(_chunk_size, _data.get_resolution()) - - _chunks.resize(_lodder.get_lod_count()) - - var cres := _data.get_resolution() / _chunk_size - var csize_x := cres - var csize_y := cres - - for lod in _lodder.get_lod_count(): - _logger.debug(str("Create grid for lod ", lod, ", ", csize_x, "x", csize_y)) - var grid = HT_Grid.create_grid(csize_x, csize_y) - _chunks[lod] = grid - csize_x /= 2 - csize_y /= 2 - - _mesher.configure(_chunk_size, _chunk_size, _lodder.get_lod_count()) - - -func _on_data_region_changed(min_x, min_y, size_x, size_y, channel): - # Testing only heights because it's the only channel that can impact geometry and LOD - if channel == HTerrainData.CHANNEL_HEIGHT: - set_area_dirty(min_x, min_y, size_x, size_y) - - if _normals_baker != null: - _normals_baker.request_tiles_in_region(Vector2(min_x, min_y), Vector2(size_x, size_y)) - - -func _on_data_map_changed(type: int, index: int): - if type == HTerrainData.CHANNEL_DETAIL \ - or type == HTerrainData.CHANNEL_HEIGHT \ - or type == HTerrainData.CHANNEL_NORMAL \ - or type == HTerrainData.CHANNEL_GLOBAL_ALBEDO: - - for layer in _detail_layers: - layer.update_material() - - if type != HTerrainData.CHANNEL_DETAIL: - _material_params_need_update = true - - -func _on_data_map_added(type: int, index: int): - if type == HTerrainData.CHANNEL_DETAIL: - for layer in _detail_layers: - # Shift indexes up since one was inserted - if layer.layer_index >= index: - layer.layer_index += 1 - layer.update_material() - else: - _material_params_need_update = true - HT_Util.update_configuration_warning(self, true) - - -func _on_data_map_removed(type: int, index: int): - if type == HTerrainData.CHANNEL_DETAIL: - for layer in _detail_layers: - # Shift indexes down since one was removed - if layer.layer_index > index: - layer.layer_index -= 1 - layer.update_material() - else: - _material_params_need_update = true - HT_Util.update_configuration_warning(self, true) - - -func get_shader_type() -> String: - return _shader_type - - -func set_shader_type(type: String): - if type == _shader_type: - return - _shader_type = type - - if _shader_type == SHADER_CUSTOM: - _material.shader = _custom_shader - else: - _material.shader = load(_builtin_shaders[_shader_type].path) - - _material_params_need_update = true - - if Engine.is_editor_hint(): - notify_property_list_changed() - - -func get_custom_shader() -> Shader: - return _custom_shader - - -func set_custom_shader(shader: Shader): - if _custom_shader == shader: - return - - if _custom_shader != null: - _custom_shader.changed.disconnect(_on_custom_shader_changed) - - if Engine.is_editor_hint() and shader != null and is_inside_tree(): - # When the new shader is empty, allow to fork from the previous shader - if shader.code.is_empty(): - _logger.debug("Populating custom shader with default code") - var src := _material.shader - if src == null: - src = load(_builtin_shaders[SHADER_CLASSIC4].path) - shader.code = src.code - # TODO If code isn't empty, - # verify existing parameters and issue a warning if important ones are missing - - _custom_shader = shader - - if _shader_type == SHADER_CUSTOM: - _material.shader = _custom_shader - - if _custom_shader != null: - _custom_shader.changed.connect(_on_custom_shader_changed) - if _shader_type == SHADER_CUSTOM: - _material_params_need_update = true - - if Engine.is_editor_hint(): - notify_property_list_changed() - - -func _on_custom_shader_changed(): - _material_params_need_update = true - - -func _update_material_params(): - assert(_material != null) - _logger.debug("Updating terrain material params") - - var terrain_textures := {} - var res := Vector2(-1, -1) - - var lookdev_material : ShaderMaterial - if _lookdev_enabled: - lookdev_material = _get_lookdev_material() - - # TODO Only get textures the shader supports - - if has_data(): - for map_type in HTerrainData.CHANNEL_COUNT: - var count := _data.get_map_count(map_type) - for i in count: - var param_name: String = HTerrainData.get_map_shader_param_name(map_type, i) - terrain_textures[param_name] = _data.get_texture(map_type, i) - res.x = _data.get_resolution() - res.y = res.x - - # Set all parameters from the terrain system. - - if is_inside_tree(): - var gt := get_internal_transform() - var t := gt.affine_inverse() - _material.set_shader_parameter(SHADER_PARAM_INVERSE_TRANSFORM, t) - - # This is needed to properly transform normals if the terrain is scaled - var normal_basis = gt.basis.inverse().transposed() - _material.set_shader_parameter(SHADER_PARAM_NORMAL_BASIS, normal_basis) - - if lookdev_material != null: - lookdev_material.set_shader_parameter(SHADER_PARAM_INVERSE_TRANSFORM, t) - lookdev_material.set_shader_parameter(SHADER_PARAM_NORMAL_BASIS, normal_basis) - - for param_name in terrain_textures: - var tex = terrain_textures[param_name] - _material.set_shader_parameter(param_name, tex) - if lookdev_material != null: - lookdev_material.set_shader_parameter(param_name, tex) - - if _texture_set != null: - match _texture_set.get_mode(): - HTerrainTextureSet.MODE_TEXTURES: - var slots_count := _texture_set.get_slots_count() - for type in HTerrainTextureSet.TYPE_COUNT: - for slot_index in slots_count: - var texture := _texture_set.get_texture(slot_index, type) - var shader_param := _get_ground_texture_shader_param_name(type, slot_index) - _material.set_shader_parameter(shader_param, texture) - - HTerrainTextureSet.MODE_TEXTURE_ARRAYS: - for type in HTerrainTextureSet.TYPE_COUNT: - var texture_array := _texture_set.get_texture_array(type) - var shader_params := _get_ground_texture_array_shader_param_name(type) - _material.set_shader_parameter(shader_params, texture_array) - - _shader_uses_texture_array = false - _is_using_indexed_splatmap = false - _used_splatmaps_count_cache = 0 - - var shader := _material.shader - if shader != null: - var param_list := RenderingServer.get_shader_parameter_list(shader.get_rid()) - _ground_texture_count_cache = 0 - for p in param_list: - if _api_shader_ground_albedo_params.has(p.name): - _ground_texture_count_cache += 1 - elif p.name == "u_ground_albedo_bump_array": - _shader_uses_texture_array = true - elif p.name == "u_terrain_splat_index_map": - _is_using_indexed_splatmap = true - elif p.name in _splatmap_shader_params: - _used_splatmaps_count_cache += 1 - - -# TODO Rename is_shader_using_texture_array() -# Tells if the current shader is using a texture array. -# This will only be valid once the material has been updated internally. -# (for example it won't be valid before the terrain is added to the SceneTree) -func is_using_texture_array() -> bool: - return _shader_uses_texture_array - - -# Gets how many splatmaps the current shader is using. -# This will only be valid once the material has been updated internally. -# (for example it won't be valid before the terrain is added to the SceneTree) -func get_used_splatmaps_count() -> int: - return _used_splatmaps_count_cache - - -# Tells if the current shader is using a splatmap type based on indexes and weights. -# This will only be valid once the material has been updated internally. -# (for example it won't be valid before the terrain is added to the SceneTree) -func is_using_indexed_splatmap() -> bool: - return _is_using_indexed_splatmap - - -static func _get_common_shader_params(shader1: Shader, shader2: Shader) -> Array: - var shader1_param_names := {} - var common_params := [] - - var shader1_params := RenderingServer.get_shader_parameter_list(shader1.get_rid()) - var shader2_params := RenderingServer.get_shader_parameter_list(shader2.get_rid()) - - for p in shader1_params: - shader1_param_names[p.name] = true - - for p in shader2_params: - if shader1_param_names.has(p.name): - common_params.append(p.name) - - return common_params - - -# Helper used for globalmap baking -func setup_globalmap_material(mat: ShaderMaterial): - mat.shader = get_globalmap_shader() - if mat.shader == null: - _logger.error("Could not find a shader to use for baking the global map.") - return - # Copy all parameters shaders have in common - var common_params = _get_common_shader_params(mat.shader, _material.shader) - for param_name in common_params: - var v = _material.get_shader_parameter(param_name) - mat.set_shader_parameter(param_name, v) - - -# Gets which shader will be used to bake the globalmap -func get_globalmap_shader() -> Shader: - if _shader_type == SHADER_CUSTOM: - if _custom_globalmap_shader != null: - return _custom_globalmap_shader - _logger.warn("The terrain uses a custom shader but doesn't have one for baking the " - + "global map. Will attempt to use a built-in shader.") - if is_using_texture_array(): - return load(_builtin_shaders[SHADER_ARRAY].global_path) as Shader - return load(_builtin_shaders[SHADER_CLASSIC4].global_path) as Shader - return load(_builtin_shaders[_shader_type].global_path) as Shader - - -# Compat -func set_lod_scale(p_lod_scale: float): - lod_scale = p_lod_scale - - -# Compat -func get_lod_scale() -> float: - return lod_scale - - -func get_lod_count() -> int: - return _lodder.get_lod_count() - - -# 3 -# o---o -# 0 | | 1 -# o---o -# 2 -# Directions to go to neighbor chunks -const s_dirs = [ - [-1, 0], # SEAM_LEFT - [1, 0], # SEAM_RIGHT - [0, -1], # SEAM_BOTTOM - [0, 1] # SEAM_TOP -] - -# 7 6 -# o---o---o -# 0 | | 5 -# o o -# 1 | | 4 -# o---o---o -# 2 3 -# -# Directions to go to neighbor chunks of higher LOD -const s_rdirs = [ - [-1, 0], - [-1, 1], - [0, 2], - [1, 2], - [2, 1], - [2, 0], - [1, -1], - [0, -1] -] - - -func _edit_update_viewer_position(camera: Camera3D): - _update_viewer_position(camera) - - -func _update_viewer_position(camera: Camera3D): - if camera == null: - var viewport := get_viewport() - if viewport != null: - camera = viewport.get_camera_3d() - - if camera == null: - return - - if camera.projection == Camera3D.PROJECTION_ORTHOGONAL: - # In this mode, due to the fact Godot does not allow negative near plane, - # users have to pull the camera node very far away, but it confuses LOD - # into very low detail, while the seen area remains the same. - # So we need to base LOD on a different metric. - var cam_pos := camera.global_transform.origin - var cam_dir := -camera.global_transform.basis.z - var max_distance := camera.far * 1.2 - var hit_cell_pos = cell_raycast(cam_pos, cam_dir, max_distance) - - if hit_cell_pos != null: - var cell_to_world := get_internal_transform() - var h := _data.get_height_at(hit_cell_pos.x, hit_cell_pos.y) - _viewer_pos_world = cell_to_world * Vector3(hit_cell_pos.x, h, hit_cell_pos.y) - - else: - _viewer_pos_world = camera.global_transform.origin - - -func _process(delta: float): - if not Engine.is_editor_hint(): - # In editor, the camera is only accessible from an editor plugin - _update_viewer_position(null) - - if has_data(): - if _data.is_locked(): - # Can't use the data for now - return - - if _data.get_resolution() != 0: - var gt := get_internal_transform() - # Viewer position such that 1 unit == 1 pixel in the heightmap - var viewer_pos_heightmap_local := gt.affine_inverse() * _viewer_pos_world - #var time_before = OS.get_ticks_msec() - _lodder.update(viewer_pos_heightmap_local) - #var time_elapsed = OS.get_ticks_msec() - time_before - #if Engine.get_frames_drawn() % 60 == 0: - # _logger.debug(str("Lodder time: ", time_elapsed)) - - if _data.get_map_count(HTerrainData.CHANNEL_DETAIL) > 0: - # Note: the detail system is not affected by map scale, - # so we have to send viewer position in world space - for layer in _detail_layers: - layer.process(delta, _viewer_pos_world) - - _updated_chunks = 0 - - # Add more chunk updates for neighboring (seams): - # This adds updates to higher-LOD chunks around lower-LOD ones, - # because they might not needed to update by themselves, but the fact a neighbor - # chunk got joined or split requires them to create or revert seams - var precount = _pending_chunk_updates.size() - for i in precount: - var u: HT_PendingChunkUpdate = _pending_chunk_updates[i] - - # In case the chunk got split - for d in 4: - var ncpos_x = u.pos_x + s_dirs[d][0] - var ncpos_y = u.pos_y + s_dirs[d][1] - - var nchunk := _get_chunk_at(ncpos_x, ncpos_y, u.lod) - if nchunk != null and nchunk.is_active(): - # Note: this will append elements to the array we are iterating on, - # but we iterate only on the previous count so it should be fine - _add_chunk_update(nchunk, ncpos_x, ncpos_y, u.lod) - - # In case the chunk got joined - if u.lod > 0: - var cpos_upper_x := u.pos_x * 2 - var cpos_upper_y := u.pos_y * 2 - var nlod := u.lod - 1 - - for rd in 8: - var ncpos_upper_x = cpos_upper_x + s_rdirs[rd][0] - var ncpos_upper_y = cpos_upper_y + s_rdirs[rd][1] - - var nchunk := _get_chunk_at(ncpos_upper_x, ncpos_upper_y, nlod) - if nchunk != null and nchunk.is_active(): - _add_chunk_update(nchunk, ncpos_upper_x, ncpos_upper_y, nlod) - - # Update chunks - var lvisible := is_visible_in_tree() - for i in len(_pending_chunk_updates): - var u: HT_PendingChunkUpdate = _pending_chunk_updates[i] - var chunk := _get_chunk_at(u.pos_x, u.pos_y, u.lod) - assert(chunk != null) - _update_chunk(chunk, u.lod, lvisible) - _updated_chunks += 1 - - _pending_chunk_updates.clear() - - if _material_params_need_update: - _update_material_params() - HT_Util.update_configuration_warning(self, false) - _material_params_need_update = false - - # DEBUG -# if(_updated_chunks > 0): -# _logger.debug(str("Updated {0} chunks".format(_updated_chunks))) - - -func _update_chunk(chunk: HTerrainChunk, lod: int, p_visible: bool): - assert(has_data()) - - # Check for my own seams - var seams := 0 - var cpos_x := chunk.cell_origin_x / (_chunk_size << lod) - var cpos_y := chunk.cell_origin_y / (_chunk_size << lod) - var cpos_lower_x := cpos_x / 2 - var cpos_lower_y := cpos_y / 2 - - # Check for lower-LOD chunks around me - for d in 4: - var ncpos_lower_x = (cpos_x + s_dirs[d][0]) / 2 - var ncpos_lower_y = (cpos_y + s_dirs[d][1]) / 2 - if ncpos_lower_x != cpos_lower_x or ncpos_lower_y != cpos_lower_y: - var nchunk := _get_chunk_at(ncpos_lower_x, ncpos_lower_y, lod + 1) - if nchunk != null and nchunk.is_active(): - seams |= (1 << d) - - var mesh := _mesher.get_chunk(lod, seams) - chunk.set_mesh(mesh) - - # Because chunks are rendered using vertex shader displacement, - # the renderer cannot rely on the mesh's AABB. - var s := _chunk_size << lod - var aabb := _data.get_region_aabb(chunk.cell_origin_x, chunk.cell_origin_y, s, s) - aabb.position.x = 0 - aabb.position.z = 0 - chunk.set_aabb(aabb) - - chunk.set_visible(p_visible) - chunk.set_pending_update(false) - - -func _add_chunk_update(chunk: HTerrainChunk, pos_x: int, pos_y: int, lod: int): - if chunk.is_pending_update(): - #_logger.debug("Chunk update is already pending!") - return - - assert(lod < len(_chunks)) - assert(pos_x >= 0) - assert(pos_y >= 0) - assert(pos_y < len(_chunks[lod])) - assert(pos_x < len(_chunks[lod][pos_y])) - - # No update pending for this chunk, create one - var u := HT_PendingChunkUpdate.new() - u.pos_x = pos_x - u.pos_y = pos_y - u.lod = lod - _pending_chunk_updates.push_back(u) - - chunk.set_pending_update(true) - - # TODO Neighboring chunks might need an update too - # because of normals and seams being updated - - -# Used when editing an existing terrain -func set_area_dirty(origin_in_cells_x: int, origin_in_cells_y: int, \ - size_in_cells_x: int, size_in_cells_y: int): - - var cpos0_x := origin_in_cells_x / _chunk_size - var cpos0_y := origin_in_cells_y / _chunk_size - var csize_x := (size_in_cells_x - 1) / _chunk_size + 1 - var csize_y := (size_in_cells_y - 1) / _chunk_size + 1 - - # For each lod - for lod in _lodder.get_lod_count(): - # Get grid and chunk size - var grid = _chunks[lod] - var s : int = _lodder.get_lod_factor(lod) - - # Convert rect into this lod's coordinates: - # Pick min and max (included), divide them, then add 1 to max so it's excluded again - var min_x := cpos0_x / s - var min_y := cpos0_y / s - var max_x := (cpos0_x + csize_x - 1) / s + 1 - var max_y := (cpos0_y + csize_y - 1) / s + 1 - - # Find which chunks are within - for cy in range(min_y, max_y): - for cx in range(min_x, max_x): - var chunk = HT_Grid.grid_get_or_default(grid, cx, cy, null) - if chunk != null and chunk.is_active(): - _add_chunk_update(chunk, cx, cy, lod) - - -# Called when a chunk is needed to be seen -func _cb_make_chunk(cpos_x: int, cpos_y: int, lod: int): - # TODO What if cpos is invalid? _get_chunk_at will return NULL but that's still invalid - var chunk := _get_chunk_at(cpos_x, cpos_y, lod) - - if chunk == null: - # This is the first time this chunk is required at this lod, generate it - - var lod_factor : int = _lodder.get_lod_factor(lod) - var origin_in_cells_x := cpos_x * _chunk_size * lod_factor - var origin_in_cells_y := cpos_y * _chunk_size * lod_factor - - var material = _material - if _lookdev_enabled: - material = _get_lookdev_material() - - if _DEBUG_AABB: - chunk = HTerrainChunkDebug.new( - self, origin_in_cells_x, origin_in_cells_y, material) - else: - chunk = HTerrainChunk.new(self, origin_in_cells_x, origin_in_cells_y, material) - chunk.parent_transform_changed(get_internal_transform()) - - chunk.set_render_layer_mask(_render_layer_mask) - chunk.set_cast_shadow_setting(_cast_shadow_setting) - - var grid = _chunks[lod] - var row = grid[cpos_y] - row[cpos_x] = chunk - - # Make sure it gets updated - _add_chunk_update(chunk, cpos_x, cpos_y, lod) - - chunk.set_active(true) - return chunk - - -# Called when a chunk is no longer seen -func _cb_recycle_chunk(chunk: HTerrainChunk, cx: int, cy: int, lod: int): - chunk.set_visible(false) - chunk.set_active(false) - - -func _cb_get_vertical_bounds(cpos_x: int, cpos_y: int, lod: int): - var chunk_size : int = _chunk_size * _lodder.get_lod_factor(lod) - var origin_in_cells_x := cpos_x * chunk_size - var origin_in_cells_y := cpos_y * chunk_size - # This is a hack for speed, - # because the proper algorithm appears to be too slow for GDScript. - # It should be good enough for most common cases, unless you have super-sharp cliffs. - return _data.get_point_aabb( - origin_in_cells_x + chunk_size / 2, - origin_in_cells_y + chunk_size / 2) -# var aabb = _data.get_region_aabb( -# origin_in_cells_x, origin_in_cells_y, chunk_size, chunk_size) -# return Vector2(aabb.position.y, aabb.end.y) - - -# static func _get_height_or_default(im: Image, pos_x: int, pos_y: int): -# if pos_x < 0 or pos_y < 0 or pos_x >= im.get_width() or pos_y >= im.get_height(): -# return 0.0 -# return im.get_pixel(pos_x, pos_y).r - - -# Performs a raycast to the terrain without using the collision engine. -# This is mostly useful in the editor, where the collider can't be updated in realtime. -# Returns cell hit position as Vector2, or null if there was no hit. -# TODO Cannot type hint nullable return value -func cell_raycast(origin_world: Vector3, dir_world: Vector3, max_distance: float): - assert(typeof(origin_world) == TYPE_VECTOR3) - assert(typeof(dir_world) == TYPE_VECTOR3) - if not has_data(): - return null - # Transform to local (takes map scale into account) - var to_local := get_internal_transform().affine_inverse() - var origin = to_local * origin_world - var dir = to_local.basis * dir_world - return _data.cell_raycast(origin, dir, max_distance) - - -static func _get_ground_texture_shader_param_name(ground_texture_type: int, slot: int) -> String: - assert(typeof(slot) == TYPE_INT and slot >= 0) - _check_ground_texture_type(ground_texture_type) - return str(SHADER_PARAM_GROUND_PREFIX, _ground_enum_to_name[ground_texture_type], "_", slot) - - -# @obsolete -func get_ground_texture(slot: int, type: int) -> Texture: - _logger.error( - "HTerrain.get_ground_texture is obsolete, " + - "use HTerrain.get_texture_set().get_texture(slot, type) instead") - var shader_param = _get_ground_texture_shader_param_name(type, slot) - return _material.get_shader_parameter(shader_param) - - -# @obsolete -func set_ground_texture(slot: int, type: int, tex: Texture): - _logger.error( - "HTerrain.set_ground_texture is obsolete, " + - "use HTerrain.get_texture_set().set_texture(slot, type, texture) instead") - assert(tex == null or tex is Texture) - var shader_param := _get_ground_texture_shader_param_name(type, slot) - _material.set_shader_parameter(shader_param, tex) - - -func _get_ground_texture_array_shader_param_name(type: int) -> String: - return _ground_texture_array_shader_params[type] as String - - -# @obsolete -func get_ground_texture_array(type: int) -> TextureLayered: - _logger.error( - "HTerrain.get_ground_texture_array is obsolete, " + - "use HTerrain.get_texture_set().get_texture_array(type) instead") - var param_name := _get_ground_texture_array_shader_param_name(type) - return _material.get_shader_parameter(param_name) - - -# @obsolete -func set_ground_texture_array(type: int, texture_array: TextureLayered): - _logger.error( - "HTerrain.set_ground_texture_array is obsolete, " + - "use HTerrain.get_texture_set().set_texture_array(type, texarray) instead") - var param_name := _get_ground_texture_array_shader_param_name(type) - _material.set_shader_parameter(param_name, texture_array) - - -func _internal_add_detail_layer(layer): - assert(_detail_layers.find(layer) == -1) - _detail_layers.append(layer) - - -func _internal_remove_detail_layer(layer): - assert(_detail_layers.find(layer) != -1) - _detail_layers.erase(layer) - - -# Returns a list copy of all child HTerrainDetailLayer nodes. -# The order in that list has no relevance. -func get_detail_layers() -> Array: - return _detail_layers.duplicate() - - -# @obsolete -func set_detail_texture(slot, tex): - _logger.error( - "HTerrain.set_detail_texture is obsolete, use HTerrainDetailLayer.texture instead") - - -# @obsolete -func get_detail_texture(slot): - _logger.error( - "HTerrain.get_detail_texture is obsolete, use HTerrainDetailLayer.texture instead") - - -# Compat -func set_ambient_wind(amplitude: float): - ambient_wind = amplitude - - -static func _check_ground_texture_type(ground_texture_type: int): - assert(typeof(ground_texture_type) == TYPE_INT) - assert(ground_texture_type >= 0 and ground_texture_type < HTerrainTextureSet.TYPE_COUNT) - - -# @obsolete -func get_ground_texture_slot_count() -> int: - _logger.error("get_ground_texture_slot_count is obsolete, " \ - + "use get_cached_ground_texture_slot_count instead") - return get_max_ground_texture_slot_count() - -# @obsolete -func get_max_ground_texture_slot_count() -> int: - _logger.error("get_ground_texture_slot_count is obsolete, " \ - + "use get_cached_ground_texture_slot_count instead") - return get_cached_ground_texture_slot_count() - - -# This is a cached value based on the actual number of texture parameters -# in the current shader. It won't update immediately when the shader changes, -# only after a frame. This is mostly used in the editor. -func get_cached_ground_texture_slot_count() -> int: - return _ground_texture_count_cache - - -func _edit_debug_draw(ci: CanvasItem): - _lodder.debug_draw_tree(ci) - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings := PackedStringArray() - - if _data == null: - warnings.append("The terrain is missing data.\n" \ - + "Select the `Data Directory` property in the inspector to assign it.") - - if _texture_set == null: - warnings.append("The terrain does not have a HTerrainTextureSet assigned\n" \ - + "This is required if you want to paint textures on it.") - - else: - var mode := _texture_set.get_mode() - - if mode == HTerrainTextureSet.MODE_TEXTURES and is_using_texture_array(): - warnings.append("The current shader needs texture arrays,\n" \ - + "but the current HTerrainTextureSet is setup with individual textures.\n" \ - + "You may need to switch it to TEXTURE_ARRAYS mode,\n" \ - + "or re-import images in this mode with the import tool.") - - elif mode == HTerrainTextureSet.MODE_TEXTURE_ARRAYS and not is_using_texture_array(): - warnings.append("The current shader needs individual textures,\n" \ - + "but the current HTerrainTextureSet is setup with texture arrays.\n" \ - + "You may need to switch it to TEXTURES mode,\n" \ - + "or re-import images in this mode with the import tool.") - - # TODO Warn about unused data maps, have a tool to clean them up - return warnings - - -func set_lookdev_enabled(enable: bool): - if _lookdev_enabled == enable: - return - _lookdev_enabled = enable - _material_params_need_update = true - if _lookdev_enabled: - _for_all_chunks(HT_SetMaterialAction.new(_get_lookdev_material())) - else: - _for_all_chunks(HT_SetMaterialAction.new(_material)) - - -func set_lookdev_shader_param(param_name: String, value): - var mat = _get_lookdev_material() - mat.set_shader_parameter(param_name, value) - - -func is_lookdev_enabled() -> bool: - return _lookdev_enabled - - -func _get_lookdev_material() -> ShaderMaterial: - if _lookdev_material == null: - _lookdev_material = ShaderMaterial.new() - _lookdev_material.shader = load(_LOOKDEV_SHADER_PATH) - return _lookdev_material - - -class HT_PendingChunkUpdate: - var pos_x := 0 - var pos_y := 0 - var lod := 0 - - -class HT_EnterWorldAction: - var world : World3D = null - func _init(w): - world = w - func exec(chunk): - chunk.enter_world(world) - - -class HT_ExitWorldAction: - func exec(chunk): - chunk.exit_world() - - -class HT_TransformChangedAction: - var transform : Transform3D - func _init(t): - transform = t - func exec(chunk): - chunk.parent_transform_changed(transform) - - -class HT_VisibilityChangedAction: - var visible := false - func _init(v): - visible = v - func exec(chunk): - chunk.set_visible(visible and chunk.is_active()) - - -#class HT_DeleteChunkAction: -# func exec(chunk): -# pass - - -class HT_SetMaterialAction: - var material : Material = null - func _init(m): - material = m - func exec(chunk): - chunk.set_material(material) - - -class HT_SetRenderLayerMaskAction: - var mask: int = 0 - func _init(m: int): - mask = m - func exec(chunk): - chunk.set_render_layer_mask(mask) - - -class HT_SetCastShadowSettingAction: - var setting := 0 - func _init(s: int): - setting = s - func exec(chunk): - chunk.set_cast_shadow_setting(setting) diff --git a/addons/zylann.hterrain/hterrain_chunk.gd b/addons/zylann.hterrain/hterrain_chunk.gd deleted file mode 100644 index 400a057..0000000 --- a/addons/zylann.hterrain/hterrain_chunk.gd +++ /dev/null @@ -1,125 +0,0 @@ -@tool - -var cell_origin_x := 0 -var cell_origin_y := 0 - -var _visible : bool -# This is true when the chunk is meant to be displayed. -# A chunk can be active and hidden (due to the terrain being hidden). -var _active : bool - -var _pending_update : bool - -var _mesh_instance : RID -# Need to keep a reference so that the mesh RID doesn't get freed -# TODO Use RID directly, no need to keep all those meshes in memory -var _mesh : Mesh = null - - -# TODO p_parent is HTerrain, can't add type hint due to cyclic reference -func _init(p_parent: Node3D, p_cell_x: int, p_cell_y: int, p_material: Material): - assert(p_parent is Node3D) - assert(typeof(p_cell_x) == TYPE_INT) - assert(typeof(p_cell_y) == TYPE_INT) - assert(p_material is Material) - - cell_origin_x = p_cell_x - cell_origin_y = p_cell_y - - var rs := RenderingServer - - _mesh_instance = rs.instance_create() - - if p_material != null: - rs.instance_geometry_set_material_override(_mesh_instance, p_material.get_rid()) - - var world := p_parent.get_world_3d() - if world != null: - rs.instance_set_scenario(_mesh_instance, world.get_scenario()) - - _visible = true - # TODO Is this needed? - rs.instance_set_visible(_mesh_instance, _visible) - - _active = true - _pending_update = false - - -func _notification(p_what: int): - if p_what == NOTIFICATION_PREDELETE: - if _mesh_instance != RID(): - RenderingServer.free_rid(_mesh_instance) - _mesh_instance = RID() - - -func is_active() -> bool: - return _active - - -func set_active(a: bool): - _active = a - - -func is_pending_update() -> bool: - return _pending_update - - -func set_pending_update(p: bool): - _pending_update = p - - -func enter_world(world: World3D): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, world.get_scenario()) - - -func exit_world(): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, RID()) - - -func parent_transform_changed(parent_transform: Transform3D): - assert(_mesh_instance != RID()) - var local_transform := Transform3D(Basis(), Vector3(cell_origin_x, 0, cell_origin_y)) - var world_transform := parent_transform * local_transform - RenderingServer.instance_set_transform(_mesh_instance, world_transform) - - -func set_mesh(mesh: Mesh): - assert(_mesh_instance != RID()) - if mesh == _mesh: - return - RenderingServer.instance_set_base(_mesh_instance, mesh.get_rid() if mesh != null else RID()) - _mesh = mesh - - -func set_material(material: Material): - assert(_mesh_instance != RID()) - RenderingServer.instance_geometry_set_material_override( \ - _mesh_instance, material.get_rid() if material != null else RID()) - - -func set_visible(visible: bool): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_visible(_mesh_instance, visible) - _visible = visible - - -func is_visible() -> bool: - return _visible - - -func set_aabb(aabb: AABB): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_custom_aabb(_mesh_instance, aabb) - - -func set_render_layer_mask(mask: int): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_layer_mask(_mesh_instance, mask) - - -func set_cast_shadow_setting(setting: int): - assert(_mesh_instance != RID()) - RenderingServer.instance_geometry_set_cast_shadows_setting(_mesh_instance, setting) - diff --git a/addons/zylann.hterrain/hterrain_chunk_debug.gd b/addons/zylann.hterrain/hterrain_chunk_debug.gd deleted file mode 100644 index 7bf3d41..0000000 --- a/addons/zylann.hterrain/hterrain_chunk_debug.gd +++ /dev/null @@ -1,67 +0,0 @@ -@tool -extends "hterrain_chunk.gd" - -# I wrote this because Godot has no debug option to show AABBs. -# https://github.com/godotengine/godot/issues/20722 - - -const HT_DirectMeshInstance = preload("./util/direct_mesh_instance.gd") -const HT_Util = preload("./util/util.gd") - - -var _debug_cube : HT_DirectMeshInstance = null -var _aabb := AABB() -var _parent_transform := Transform3D() - - -func _init(p_parent: Node3D, p_cell_x: int, p_cell_y: int, p_material: Material): - super(p_parent, p_cell_x, p_cell_y, p_material) - - var wirecube : Mesh - if not p_parent.has_meta("debug_wirecube_mesh"): - wirecube = HT_Util.create_wirecube_mesh() - var mat := StandardMaterial3D.new() - mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - wirecube.surface_set_material(0, mat) - # Cache the debug cube in the parent node to avoid re-creating each time - p_parent.set_meta("debug_wirecube_mesh", wirecube) - else: - wirecube = p_parent.get_meta("debug_wirecube_mesh") - - _debug_cube = HT_DirectMeshInstance.new() - _debug_cube.set_mesh(wirecube) - _debug_cube.set_world(p_parent.get_world_3d()) - - -func enter_world(world: World3D): - super(world) - _debug_cube.enter_world(world) - - -func exit_world(): - super() - _debug_cube.exit_world() - - -func parent_transform_changed(parent_transform: Transform3D): - super(parent_transform) - _parent_transform = parent_transform - _debug_cube.set_transform(_compute_aabb()) - - -func set_visible(visible: bool): - super(visible) - _debug_cube.set_visible(visible) - - -func set_aabb(aabb: AABB): - super(aabb) - #aabb.position.y += 0.2*randf() - _aabb = aabb - _debug_cube.set_transform(_compute_aabb()) - - -func _compute_aabb(): - var pos = Vector3(cell_origin_x, 0, cell_origin_y) - return _parent_transform * Transform3D(Basis().scaled(_aabb.size), pos + _aabb.position) - diff --git a/addons/zylann.hterrain/hterrain_collider.gd b/addons/zylann.hterrain/hterrain_collider.gd deleted file mode 100644 index 7abb95f..0000000 --- a/addons/zylann.hterrain/hterrain_collider.gd +++ /dev/null @@ -1,118 +0,0 @@ -@tool - -const HT_Logger = preload("./util/logger.gd") -const HTerrainData = preload("./hterrain_data.gd") - -var _shape_rid := RID() -var _body_rid := RID() -var _terrain_transform := Transform3D() -var _terrain_data : HTerrainData = null -var _logger = HT_Logger.get_for(self) - - -func _init(attached_node: Node, initial_layer: int, initial_mask: int): - _logger.debug("HTerrainCollider: creating body") - assert(attached_node != null) - _shape_rid = PhysicsServer3D.heightmap_shape_create() - _body_rid = PhysicsServer3D.body_create() - PhysicsServer3D.body_set_mode(_body_rid, PhysicsServer3D.BODY_MODE_STATIC) - - PhysicsServer3D.body_set_collision_layer(_body_rid, initial_layer) - PhysicsServer3D.body_set_collision_mask(_body_rid, initial_mask) - - # TODO This is an attempt to workaround https://github.com/godotengine/godot/issues/24390 - PhysicsServer3D.body_set_ray_pickable(_body_rid, false) - - # Assigng dummy data - # TODO This is a workaround to https://github.com/godotengine/godot/issues/25304 - PhysicsServer3D.shape_set_data(_shape_rid, { - "width": 2, - "depth": 2, - "heights": PackedFloat32Array([0, 0, 0, 0]), - "min_height": -1, - "max_height": 1 - }) - - PhysicsServer3D.body_add_shape(_body_rid, _shape_rid) - - # This makes collision hits report the provided object as `collider` - PhysicsServer3D.body_attach_object_instance_id(_body_rid, attached_node.get_instance_id()) - - -func set_collision_layer(layer: int): - PhysicsServer3D.body_set_collision_layer(_body_rid, layer) - - -func set_collision_mask(mask: int): - PhysicsServer3D.body_set_collision_mask(_body_rid, mask) - - -func _notification(what: int): - if what == NOTIFICATION_PREDELETE: - _logger.debug("Destroy HTerrainCollider") - PhysicsServer3D.free_rid(_body_rid) - # The shape needs to be freed after the body, otherwise the engine crashes - PhysicsServer3D.free_rid(_shape_rid) - - -func set_transform(transform: Transform3D): - assert(_body_rid != RID()) - _terrain_transform = transform - _update_transform() - - -func set_world(world: World3D): - assert(_body_rid != RID()) - PhysicsServer3D.body_set_space(_body_rid, world.get_space() if world != null else RID()) - - -func create_from_terrain_data(terrain_data: HTerrainData): - assert(terrain_data != null) - assert(not terrain_data.is_locked()) - _logger.debug("HTerrainCollider: setting up heightmap") - - _terrain_data = terrain_data - - var aabb := terrain_data.get_aabb() - - var width := terrain_data.get_resolution() - var depth := terrain_data.get_resolution() - var height := aabb.size.y - - var shape_data = { - "width": terrain_data.get_resolution(), - "depth": terrain_data.get_resolution(), - "heights": terrain_data.get_all_heights(), - "min_height": aabb.position.y, - "max_height": aabb.end.y - } - - PhysicsServer3D.shape_set_data(_shape_rid, shape_data) - - _update_transform(aabb) - - -func _update_transform(aabb=null): - if _terrain_data == null: - _logger.debug("HTerrainCollider: terrain data not set yet") - return - -# if aabb == null: -# aabb = _terrain_data.get_aabb() - - var width := _terrain_data.get_resolution() - var depth := _terrain_data.get_resolution() - #var height = aabb.size.y - - #_terrain_transform - - var trans := Transform3D(Basis(), 0.5 * Vector3(width - 1, 0, depth - 1)) - - # And then apply the terrain transform - trans = _terrain_transform * trans - - PhysicsServer3D.body_set_state(_body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM, trans) - # Cannot use shape transform when scaling is involved, - # because Godot is undoing that scale for some reason. - # See https://github.com/Zylann/godot_heightmap_plugin/issues/70 - #PhysicsServer.body_set_shape_transform(_body_rid, 0, trans) diff --git a/addons/zylann.hterrain/hterrain_data.gd b/addons/zylann.hterrain/hterrain_data.gd deleted file mode 100644 index 8e9ec1e..0000000 --- a/addons/zylann.hterrain/hterrain_data.gd +++ /dev/null @@ -1,1846 +0,0 @@ - -# Holds data of the terrain. -# This is mostly a set of textures using specific formats, some precalculated, and metadata. - -@tool -extends Resource - -const HT_Grid = preload("./util/grid.gd") -const HT_Util = preload("./util/util.gd") -const HT_Errors = preload("./util/errors.gd") -const HT_Logger = preload("./util/logger.gd") -const HT_ImageFileCache = preload("./util/image_file_cache.gd") -const HT_XYZFormat = preload("./util/xyz_format.gd") - -# Note: indexes matters for saving, don't re-order -# TODO Rename "CHANNEL" to "MAP", makes more sense and less confusing with RGBA channels -const CHANNEL_HEIGHT = 0 -const CHANNEL_NORMAL = 1 -const CHANNEL_SPLAT = 2 -const CHANNEL_COLOR = 3 -const CHANNEL_DETAIL = 4 -const CHANNEL_GLOBAL_ALBEDO = 5 -const CHANNEL_SPLAT_INDEX = 6 -const CHANNEL_SPLAT_WEIGHT = 7 -const CHANNEL_COUNT = 8 - -const _map_types = { - CHANNEL_HEIGHT: { - name = "height", - shader_param_name = "u_terrain_heightmap", - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RF, - default_fill = Color(0, 0, 0, 1), - default_count = 1, - can_be_saved_as_png = false, - authored = true, - srgb = false - }, - CHANNEL_NORMAL: { - name = "normal", - shader_param_name = "u_terrain_normalmap", - filter = true, - mipmaps = false, - # TODO RGB8 is a lie, we should use RGBA8 and pack something in A I guess - texture_format = Image.FORMAT_RGB8, - default_fill = Color(0.5, 0.5, 1.0), - default_count = 1, - can_be_saved_as_png = true, - authored = false, - srgb = false - }, - CHANNEL_SPLAT: { - name = "splat", - shader_param_name = [ - "u_terrain_splatmap", # not _0 for compatibility - "u_terrain_splatmap_1", - "u_terrain_splatmap_2", - "u_terrain_splatmap_3" - ], - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RGBA8, - default_fill = [Color(1, 0, 0, 0), Color(0, 0, 0, 0)], - default_count = 1, - can_be_saved_as_png = true, - authored = true, - srgb = false - }, - CHANNEL_COLOR: { - name = "color", - shader_param_name = "u_terrain_colormap", - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RGBA8, - default_fill = Color(1, 1, 1, 1), - default_count = 1, - can_be_saved_as_png = true, - authored = true, - srgb = true - }, - CHANNEL_DETAIL: { - name = "detail", - shader_param_name = "u_terrain_detailmap", - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_R8, - default_fill = Color(0, 0, 0), - default_count = 0, - can_be_saved_as_png = true, - authored = true, - srgb = false - }, - CHANNEL_GLOBAL_ALBEDO: { - name = "global_albedo", - shader_param_name = "u_terrain_globalmap", - filter = true, - mipmaps = true, - texture_format = Image.FORMAT_RGB8, - default_fill = null, - default_count = 0, - can_be_saved_as_png = true, - authored = false, - srgb = true - }, - CHANNEL_SPLAT_INDEX: { - name = "splat_index", - shader_param_name = "u_terrain_splat_index_map", - filter = false, - mipmaps = false, - texture_format = Image.FORMAT_RGB8, - default_fill = Color(0, 0, 0), - default_count = 0, - can_be_saved_as_png = true, - authored = true, - srgb = false - }, - CHANNEL_SPLAT_WEIGHT: { - name = "splat_weight", - shader_param_name = "u_terrain_splat_weight_map", - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RG8, - default_fill = Color(1, 0, 0), - default_count = 0, - can_be_saved_as_png = true, - authored = true, - srgb = false - } -} - -# Resolution is a power of two + 1 -const MAX_RESOLUTION = 4097 -const MIN_RESOLUTION = 65 # must be higher than largest chunk size -const DEFAULT_RESOLUTION = 513 -const SUPPORTED_RESOLUTIONS = [65, 129, 257, 513, 1025, 2049, 4097] - -const VERTICAL_BOUNDS_CHUNK_SIZE = 16 -# TODO Have undo chunk size to emphasise the fact it's independent - -const META_EXTENSION = "hterrain" -const META_FILENAME = "data.hterrain" -const META_VERSION = "0.11" - -signal resolution_changed -signal region_changed(x, y, w, h, channel) -signal map_added(type, index) -signal map_removed(type, index) -signal map_changed(type, index) - - -# A map is a texture covering the terrain. -# The usage of a map depends on its type (heightmap, normalmap, splatmap...). -class HT_Map: - var texture: Texture2D - # Reference used in case we need the data CPU-side - var image: Image - # ID used for saving, because when adding/removing maps, - # we shouldn't rename texture files just because the indexes change. - # This is mostly for internal keeping. - # The API still uses indexes that may shift if your remove a map. - var id := -1 - # Should be set to true if the map has unsaved modifications. - var modified := true - - func _init(p_id: int): - id = p_id - - -var _resolution := 0 - -# There can be multiple maps of the same type, though most of them are single -# [map_type][instance_index] => map -var _maps := [[]] - -# RGF image where R is min height and G is max height -var _chunked_vertical_bounds := Image.new() - -var _locked := false - -var _edit_disable_apply_undo := false -var _logger := HT_Logger.get_for(self) - - -func _init(): - # Initialize default maps - _set_default_maps() - - -func _set_default_maps(): - _maps.resize(CHANNEL_COUNT) - for c in CHANNEL_COUNT: - var maps := [] - var n : int = _map_types[c].default_count - for i in n: - maps.append(HT_Map.new(i)) - _maps[c] = maps - - -func _edit_load_default(): - _logger.debug("Loading default data") - _set_default_maps() - resize(DEFAULT_RESOLUTION) - - -# Don't use the data if this getter returns false -func is_locked() -> bool: - return _locked - - -func get_resolution() -> int: - return _resolution - - -# @obsolete -func set_resolution(p_res): - _logger.error("`HTerrainData.set_resolution()` is obsolete, use `resize()` instead") - resize(p_res) - - -# @obsolete -func set_resolution2(p_res, update_normals): - _logger.error("`HTerrainData.set_resolution2()` is obsolete, use `resize()` instead") - resize(p_res, true, Vector2(-1, -1)) - - -# Resizes all maps of the terrain. This may take some time to complete. -# Note that no upload to GPU is done, you have to do it once you're done with all changes, -# by calling `notify_region_change` or `notify_full_change`. -# p_res: new resolution. Must be a power of two + 1. -# stretch: if true, the terrain will be stretched in X and Z axes. -# If false, it will be cropped or expanded. -# anchor: if stretch is false, decides which side or corner to crop/expand the terrain from. -# -# There is an off-by-one in the data, -# so for example a map of 512x512 will actually have 513x513 cells. -# Here is why: -# If we had an even amount of cells, it would produce this situation when making LOD chunks: -# -# x---x---x---x x---x---x---x -# | | | | | | -# x---x---x---x x x x x -# | | | | | | -# x---x---x---x x---x---x---x -# | | | | | | -# x---x---x---x x x x x -# -# LOD 0 LOD 1 -# -# We would be forced to ignore the last cells because they would produce an irregular chunk. -# We need an off-by-one because quads making up chunks SHARE their consecutive vertices. -# One quad needs at least 2x2 cells to exist. -# Two quads of the heightmap share an edge, which needs a total of 3x3 cells, not 4x4. -# One chunk has 16x16 quads, so it needs 17x17 cells, -# not 16, where the last cell is shared with the next chunk. -# As a result, a map of 4x4 chunks needs 65x65 cells, not 64x64. -func resize(p_res: int, stretch := true, anchor := Vector2(-1, -1)): - assert(typeof(p_res) == TYPE_INT) - assert(typeof(stretch) == TYPE_BOOL) - assert(typeof(anchor) == TYPE_VECTOR2) - - _logger.debug(str("set_resolution ", p_res)) - - if p_res == get_resolution(): - return - - p_res = clampi(p_res, MIN_RESOLUTION, MAX_RESOLUTION) - - # Power of two is important for LOD. - # Also, grid data is off by one, - # because for an even number of quads you need an odd number of vertices. - # To prevent size from increasing at every deserialization, - # remove 1 before applying power of two. - p_res = HT_Util.next_power_of_two(p_res - 1) + 1 - - _resolution = p_res; - - for channel in CHANNEL_COUNT: - var maps : Array = _maps[channel] - - for index in len(maps): - _logger.debug(str("Resizing ", get_map_debug_name(channel, index), "...")) - - var map : HT_Map = maps[index] - var im := map.image - - if im == null: - _logger.debug("Image not in memory, creating it") - im = Image.create(_resolution, _resolution, false, get_channel_format(channel)) - - var fill_color = _get_map_default_fill_color(channel, index) - if fill_color != null: - _logger.debug(str("Fill with ", fill_color)) - im.fill(fill_color) - - else: - if stretch and not _map_types[channel].authored: - # Create a blank new image, it will be automatically computed later - im = Image.create(_resolution, _resolution, false, get_channel_format(channel)) - else: - if stretch: - if im.get_format() == Image.FORMAT_RGB8: - # Can't directly resize this format - var float_heightmap := convert_heightmap_to_float(im, _logger) - float_heightmap.resize(_resolution, _resolution) - im = Image.create( - float_heightmap.get_width(), - float_heightmap.get_height(), im.has_mipmaps(), im.get_format()) - convert_float_heightmap_to_rgb8(float_heightmap, im) - else: - # Assuming float or single-component fixed-point - im.resize(_resolution, _resolution) - else: - var fill_color = _get_map_default_fill_color(channel, index) - im = HT_Util.get_cropped_image(im, _resolution, _resolution, \ - fill_color, anchor) - - map.image = im - map.modified = true - - _update_all_vertical_bounds() - - resolution_changed.emit() - - -# TODO Can't hint it, the return is a nullable Color -static func _get_map_default_fill_color(map_type: int, map_index: int): - var config = _map_types[map_type].default_fill - if config == null: - # No fill required - return null - if typeof(config) == TYPE_COLOR: - # Standard color fill - return config - assert(typeof(config) == TYPE_ARRAY) - assert(len(config) == 2) - if map_index == 0: - # First map has this config - return config[0] - # Others have this - return config[1] - - -# Gets the height at the given cell position. -# This height is raw and doesn't account for scaling of the terrain node. -# This function is relatively slow due to locking, so don't use it to fetch large areas. -func get_height_at(x: int, y: int) -> float: - # Height data must be loaded in RAM - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - match im.get_format(): - Image.FORMAT_RF: - return HT_Util.get_pixel_clamped(im, x, y).r - Image.FORMAT_RGB8: - return decode_height_from_rgb8_unorm(HT_Util.get_pixel_clamped(im, x, y)) - _: - _logger.error(str("Invalid heigthmap format ", im.get_format())) - return 0.0 - - -# Gets the height at the given floating-point cell position. -# This height is raw and doesn't account for scaling of the terrain node. -# This function is relatively slow due to locking, so don't use it to fetch large areas -func get_interpolated_height_at(pos: Vector3) -> float: - # Height data must be loaded in RAM - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - var map_type = _map_types[CHANNEL_HEIGHT] - assert(im.get_format() == map_type.texture_format) - - # The function takes a Vector3 for convenience so it's easier to use in 3D scripting - var x0 := int(floorf(pos.x)) - var y0 := int(floorf(pos.z)) - - var xf := pos.x - x0 - var yf := pos.z - y0 - - var h00 : float - var h10 : float - var h01 : float - var h11 : float - - match im.get_format(): - Image.FORMAT_RF: - h00 = HT_Util.get_pixel_clamped(im, x0, y0).r - h10 = HT_Util.get_pixel_clamped(im, x0 + 1, y0).r - h01 = HT_Util.get_pixel_clamped(im, x0, y0 + 1).r - h11 = HT_Util.get_pixel_clamped(im, x0 + 1, y0 + 1).r - - Image.FORMAT_RGB8: - var c00 := HT_Util.get_pixel_clamped(im, x0, y0) - var c10 := HT_Util.get_pixel_clamped(im, x0 + 1, y0) - var c01 := HT_Util.get_pixel_clamped(im, x0, y0 + 1) - var c11 := HT_Util.get_pixel_clamped(im, x0 + 1, y0 + 1) - - h00 = decode_height_from_rgb8_unorm(c00) - h10 = decode_height_from_rgb8_unorm(c10) - h01 = decode_height_from_rgb8_unorm(c01) - h11 = decode_height_from_rgb8_unorm(c11) - - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - return 0.0 - - # Bilinear filter - var h := lerpf(lerpf(h00, h10, xf), lerpf(h01, h11, xf), yf) - return h - -# Gets all heights within the given rectangle in cells. -# This height is raw and doesn't account for scaling of the terrain node. -# Data is returned as a PackedFloat32Array. -func get_heights_region(x0: int, y0: int, w: int, h: int) -> PackedFloat32Array: - var im = get_image(CHANNEL_HEIGHT) - assert(im != null) - - var min_x := clampi(x0, 0, im.get_width()) - var min_y := clampi(y0, 0, im.get_height()) - var max_x := clampi(x0 + w, 0, im.get_width() + 1) - var max_y := clampi(y0 + h, 0, im.get_height() + 1) - - var heights := PackedFloat32Array() - - var area := (max_x - min_x) * (max_y - min_y) - if area == 0: - _logger.debug("Empty heights region!") - return heights - - heights.resize(area) - - var i := 0 - - if im.get_format() == Image.FORMAT_RF or im.get_format() == Image.FORMAT_RH: - for y in range(min_y, max_y): - for x in range(min_x, max_x): - heights[i] = im.get_pixel(x, y).r - i += 1 - - elif im.get_format() == Image.FORMAT_RGB8: - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var c := im.get_pixel(x, y) - heights[i] = decode_height_from_rgb8_unorm(c) - i += 1 - - else: - _logger.error(str("Unknown heightmap format! ", im.get_format())) - - return heights - - -# Gets all heights as an array indexed as [x + y * width]. -# This height is raw and doesn't account for scaling of the terrain node. -func get_all_heights() -> PackedFloat32Array: - var im = get_image(CHANNEL_HEIGHT) - assert(im != null) - if im.get_format() == Image.FORMAT_RF: - return im.get_data().to_float32_array() - else: - return get_heights_region(0, 0, _resolution, _resolution) - - -# Call this function after you end modifying a map. -# It will commit the change to the GPU so the change will take effect. -# In the editor, it will also mark the map as modified so it will be saved when needed. -# Finally, it will emit `region_changed`, -# which allows other systems to catch up (like physics or grass) -# -# p_rect: -# modified area. -# -# map_type: -# which kind of map changed, see CHANNEL_* constants -# -# index: -# index of the map that changed -# -# p_upload_to_texture: -# the modified region will be copied from the map image to the texture. -# If the change already occurred on GPU, you may set this to false. -# -# p_update_vertical_bounds: -# if the modified map is the heightmap, vertical bounds will be updated. -# -func notify_region_change( - p_rect: Rect2, - p_map_type: int, - p_index := 0, - p_upload_to_texture := true, - p_update_vertical_bounds := true): - - assert(p_map_type >= 0 and p_map_type < CHANNEL_COUNT) - - var min_x := int(p_rect.position.x) - var min_y := int(p_rect.position.y) - var size_x := int(p_rect.size.x) - var size_y := int(p_rect.size.y) - - if p_map_type == CHANNEL_HEIGHT and p_update_vertical_bounds: - assert(p_index == 0) - _update_vertical_bounds(min_x, min_y, size_x, size_y) - - if p_upload_to_texture: - _upload_region(p_map_type, p_index, min_x, min_y, size_x, size_y) - - _maps[p_map_type][p_index].modified = true - - region_changed.emit(min_x, min_y, size_x, size_y, p_map_type) - changed.emit() - - -func notify_full_change(): - for maptype in range(CHANNEL_COUNT): - # Ignore normals because they get updated along with heights - if maptype == CHANNEL_NORMAL: - continue - var maps = _maps[maptype] - for index in len(maps): - notify_region_change(Rect2(0, 0, _resolution, _resolution), maptype, index) - - -func _edit_set_disable_apply_undo(e: bool): - _edit_disable_apply_undo = e - - -func _edit_apply_undo(undo_data: Dictionary, image_cache: HT_ImageFileCache): - if _edit_disable_apply_undo: - return - - var chunk_positions: Array = undo_data["chunk_positions"] - var map_infos: Array = undo_data["maps"] - var chunk_size: int = undo_data["chunk_size"] - - _logger.debug(str("Applying ", len(chunk_positions), " undo/redo chunks")) - - # Validate input - - for map_info in map_infos: - assert(map_info.map_type >= 0 and map_info.map_type < CHANNEL_COUNT) - assert(len(map_info.chunks) == len(chunk_positions)) - for im_cache_id in map_info.chunks: - assert(typeof(im_cache_id) == TYPE_INT) - - # Apply for each map - for map_info in map_infos: - var map_type := map_info.map_type as int - var map_index := map_info.map_index as int - - var regions_changed := [] - - for chunk_index in len(map_info.chunks): - var cpos : Vector2 = chunk_positions[chunk_index] - var cpos_x := int(cpos.x) - var cpos_y := int(cpos.y) - - var min_x := cpos_x * chunk_size - var min_y := cpos_y * chunk_size - var max_x := min_x + chunk_size - var max_y := min_y + chunk_size - - var data_id = map_info.chunks[chunk_index] - var data := image_cache.load_image(data_id) - assert(data != null) - - var dst_image := get_image(map_type, map_index) - assert(dst_image != null) - - if _map_types[map_type].authored: - #_logger.debug(str("Apply undo chunk ", cpos, " to ", Vector2(min_x, min_y))) - var src_rect := Rect2i(0, 0, data.get_width(), data.get_height()) - dst_image.blit_rect(data, src_rect, Vector2i(min_x, min_y)) - else: - _logger.error( - str("Channel ", map_type, " is a calculated channel!, no undo on this one")) - - # Defer this to a second pass, - # otherwise it causes order-dependent artifacts on the normal map - regions_changed.append([ - Rect2(min_x, min_y, max_x - min_x, max_y - min_y), map_type, map_index]) - - for args in regions_changed: - notify_region_change(args[0], args[1], args[2]) - - -#static func _debug_dump_heightmap(src: Image, fpath: String): -# var im = Image.new() -# im.create(src.get_width(), src.get_height(), false, Image.FORMAT_RGB8) -# im.lock() -# src.lock() -# for y in im.get_height(): -# for x in im.get_width(): -# var col = src.get_pixel(x, y) -# var c = col.r - floor(col.r) -# im.set_pixel(x, y, Color(c, 0.0, 0.0, 1.0)) -# im.unlock() -# src.unlock() -# im.save_png(fpath) - - -# TODO Support map indexes -# Used for undoing full-terrain changes -func _edit_apply_maps_from_file_cache(image_file_cache: HT_ImageFileCache, map_ids: Dictionary): - if _edit_disable_apply_undo: - return - for map_type in map_ids: - var id = map_ids[map_type] - var src_im := image_file_cache.load_image(id) - if src_im == null: - continue - var index := 0 - var dst_im := get_image(map_type, index) - var rect := Rect2i(0, 0, src_im.get_height(), src_im.get_height()) - dst_im.blit_rect(src_im, rect, Vector2i()) - notify_region_change(rect, map_type, index) - - -func _upload_channel(channel: int, index: int): - _upload_region(channel, index, 0, 0, _resolution, _resolution) - - -func _upload_region(channel: int, index: int, min_x: int, min_y: int, size_x: int, size_y: int): - #_logger.debug("Upload ", min_x, ", ", min_y, ", ", size_x, "x", size_y) - #var time_before = OS.get_ticks_msec() - - var map : HT_Map = _maps[channel][index] - - var image := map.image - assert(image != null) - assert(size_x > 0 and size_y > 0) - - # TODO Actually, I think the input params should be valid in the first place... - if min_x < 0: - min_x = 0 - if min_y < 0: - min_y = 0 - if min_x + size_x > image.get_width(): - size_x = image.get_width() - min_x - if min_y + size_y > image.get_height(): - size_y = image.get_height() - min_y - if size_x <= 0 or size_y <= 0: - return - - var texture := map.texture - - if texture == null or not (texture is ImageTexture): - # The texture doesn't exist yet in an editable format - if texture != null and not (texture is ImageTexture): - _logger.debug(str( - "_upload_region was used but the texture isn't an ImageTexture. ",\ - "The map ", channel, "[", index, "] will be reuploaded entirely.")) - else: - _logger.debug(str( - "_upload_region was used but the texture is not created yet. ",\ - "The map ", channel, "[", index, "] will be uploaded entirely.")) - - map.texture = ImageTexture.create_from_image(image) - - # Need to notify because other systems may want to grab the new texture object - map_changed.emit(channel, index) - - # TODO Unfortunately Texture2D.get_size() wasn't updated to use Vector2i in Godot 4 - elif Vector2i(texture.get_size()) != image.get_size(): - _logger.debug(str( - "_upload_region was used but the image size is different. ",\ - "The map ", channel, "[", index, "] will be reuploaded entirely.")) - - map.texture = ImageTexture.create_from_image(image) - - # Since Godot 4, need to notify because other systems may want to grab the new texture - # object. In Godot 3 it wasn't necessary because we were able to resize a texture without - # having to recreate it from scratch... - map_changed.emit(channel, index) - - else: - HT_Util.update_texture_partial(texture, image, - Rect2i(min_x, min_y, size_x, size_y), Vector2i(min_x, min_y)) - - #_logger.debug(str("Channel updated ", channel)) - - #var time_elapsed = OS.get_ticks_msec() - time_before - #_logger.debug(str("Texture upload time: ", time_elapsed, "ms")) - - -# Gets how many instances of a given map are present in the terrain data. -# A return value of 0 means there is no such map, and querying for it might cause errors. -func get_map_count(map_type: int) -> int: - if map_type < len(_maps): - return len(_maps[map_type]) - return 0 - - -# TODO Deprecated -func _edit_add_detail_map(): - return _edit_add_map(CHANNEL_DETAIL) - - -# TODO Deprecated -func _edit_remove_detail_map(index): - _edit_remove_map(CHANNEL_DETAIL, index) - - -func _edit_add_map(map_type: int) -> int: - # TODO Check minimum and maximum instances of a given map - _logger.debug(str("Adding map of type ", get_channel_name(map_type))) - while map_type >= len(_maps): - _maps.append([]) - var maps = _maps[map_type] - var map = HT_Map.new(_get_free_id(map_type)) - map.image = Image.create(_resolution, _resolution, false, get_channel_format(map_type)) - var index = len(maps) - var default_color = _get_map_default_fill_color(map_type, index) - if default_color != null: - map.image.fill(default_color) - maps.append(map) - map_added.emit(map_type, index) - return index - - -func _edit_insert_map_from_image_cache(map_type: int, index: int, image_cache, image_id: int): - if _edit_disable_apply_undo: - return - _logger.debug(str("Adding map of type ", get_channel_name(map_type), - " from an image at index ", index)) - while map_type >= len(_maps): - _maps.append([]) - var maps = _maps[map_type] - var map := HT_Map.new(_get_free_id(map_type)) - map.image = image_cache.load_image(image_id) - maps.insert(index, map) - map_added.emit(map_type, index) - - -func _edit_remove_map(map_type: int, index: int): - # TODO Check minimum and maximum instances of a given map - _logger.debug(str("Removing map ", get_channel_name(map_type), " at index ", index)) - var maps : Array = _maps[map_type] - maps.remove_at(index) - map_removed.emit(map_type, index) - - -func _get_free_id(map_type: int) -> int: - var maps = _maps[map_type] - var id = 0 - while _get_map_by_id(map_type, id) != null: - id += 1 - return id - - -func _get_map_by_id(map_type: int, id: int) -> HT_Map: - var maps = _maps[map_type] - for map in maps: - if map.id == id: - return map - return null - - -func get_image(map_type: int, index := 0) -> Image: - var maps = _maps[map_type] - return maps[index].image - - -func get_texture(map_type: int, index := 0, writable := false) -> Texture: - # TODO Split into `get_texture` and `get_writable_texture`? - - var maps : Array = _maps[map_type] - var map : HT_Map = maps[index] - - if map.image != null: - if map.texture == null: - _upload_channel(map_type, index) - elif writable and not (map.texture is ImageTexture): - _upload_channel(map_type, index) - else: - if writable: - _logger.warn(str("Requested writable terrain texture ", - get_map_debug_name(map_type, index), ", but it's not available in this context")) - - return map.texture - - -func has_texture(map_type: int, index: int) -> bool: - var maps = _maps[map_type] - return index < len(maps) - - -func get_aabb() -> AABB: - # TODO Why subtract 1? I forgot - # TODO Optimize for full region, this is actually quite costy - return get_region_aabb(0, 0, _resolution - 1, _resolution - 1) - - -# Not so useful in itself, but GDScript is slow, -# so I needed it to speed up the LOD hack I had to do to take height into account -func get_point_aabb(cell_x: int, cell_y: int) -> Vector2: - assert(typeof(cell_x) == TYPE_INT) - assert(typeof(cell_y) == TYPE_INT) - - var cx = cell_x / VERTICAL_BOUNDS_CHUNK_SIZE - var cy = cell_y / VERTICAL_BOUNDS_CHUNK_SIZE - - if cx < 0: - cx = 0 - if cy < 0: - cy = 0 - if cx >= _chunked_vertical_bounds.get_width(): - cx = _chunked_vertical_bounds.get_width() - 1 - if cy >= _chunked_vertical_bounds.get_height(): - cy = _chunked_vertical_bounds.get_height() - 1 - - var b := _chunked_vertical_bounds.get_pixel(cx, cy) - return Vector2(b.r, b.g) - - -func get_region_aabb(origin_in_cells_x: int, origin_in_cells_y: int, - size_in_cells_x: int, size_in_cells_y: int) -> AABB: - - assert(typeof(origin_in_cells_x) == TYPE_INT) - assert(typeof(origin_in_cells_y) == TYPE_INT) - assert(typeof(size_in_cells_x) == TYPE_INT) - assert(typeof(size_in_cells_y) == TYPE_INT) - - # Get info from cached vertical bounds, - # which is a lot faster than directly fetching heights from the map. - # It's not 100% accurate, but enough for culling use case if chunk size is decently chosen. - - var cmin_x := origin_in_cells_x / VERTICAL_BOUNDS_CHUNK_SIZE - var cmin_y := origin_in_cells_y / VERTICAL_BOUNDS_CHUNK_SIZE - - var cmax_x := (origin_in_cells_x + size_in_cells_x - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - var cmax_y := (origin_in_cells_y + size_in_cells_y - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - - cmin_x = clampi(cmin_x, 0, _chunked_vertical_bounds.get_width() - 1) - cmin_y = clampi(cmin_y, 0, _chunked_vertical_bounds.get_height() - 1) - cmax_x = clampi(cmax_x, 0, _chunked_vertical_bounds.get_width()) - cmax_y = clampi(cmax_y, 0, _chunked_vertical_bounds.get_height()) - - var min_height := _chunked_vertical_bounds.get_pixel(cmin_x, cmin_y).r - var max_height = min_height - - for y in range(cmin_y, cmax_y): - for x in range(cmin_x, cmax_x): - var b = _chunked_vertical_bounds.get_pixel(x, y) - min_height = minf(b.r, min_height) - max_height = maxf(b.g, max_height) - - var aabb = AABB() - aabb.position = Vector3(origin_in_cells_x, min_height, origin_in_cells_y) - aabb.size = Vector3(size_in_cells_x, max_height - min_height, size_in_cells_y) - - return aabb - - -func _update_all_vertical_bounds(): - var csize_x := _resolution / VERTICAL_BOUNDS_CHUNK_SIZE - var csize_y := _resolution / VERTICAL_BOUNDS_CHUNK_SIZE - _logger.debug(str("Updating all vertical bounds... (", csize_x , "x", csize_y, " chunks)")) - _chunked_vertical_bounds = Image.create(csize_x, csize_y, false, Image.FORMAT_RGF) - _update_vertical_bounds(0, 0, _resolution - 1, _resolution - 1) - - -func update_vertical_bounds(p_rect: Rect2): - var min_x := int(p_rect.position.x) - var min_y := int(p_rect.position.y) - var size_x := int(p_rect.size.x) - var size_y := int(p_rect.size.y) - - _update_vertical_bounds(min_x, min_y, size_x, size_y) - - -func _update_vertical_bounds(origin_in_cells_x: int, origin_in_cells_y: int, \ - size_in_cells_x: int, size_in_cells_y: int): - - var cmin_x := origin_in_cells_x / VERTICAL_BOUNDS_CHUNK_SIZE - var cmin_y := origin_in_cells_y / VERTICAL_BOUNDS_CHUNK_SIZE - - var cmax_x := (origin_in_cells_x + size_in_cells_x - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - var cmax_y := (origin_in_cells_y + size_in_cells_y - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - - cmin_x = clampi(cmin_x, 0, _chunked_vertical_bounds.get_width() - 1) - cmin_y = clampi(cmin_y, 0, _chunked_vertical_bounds.get_height() - 1) - cmax_x = clampi(cmax_x, 0, _chunked_vertical_bounds.get_width()) - cmax_y = clampi(cmax_y, 0, _chunked_vertical_bounds.get_height()) - - # Note: chunks in _chunked_vertical_bounds share their edge cells and - # have an actual size of chunk size + 1. - var chunk_size_x := VERTICAL_BOUNDS_CHUNK_SIZE + 1 - var chunk_size_y := VERTICAL_BOUNDS_CHUNK_SIZE + 1 - - for y in range(cmin_y, cmax_y): - var pmin_y := y * VERTICAL_BOUNDS_CHUNK_SIZE - - for x in range(cmin_x, cmax_x): - var pmin_x := x * VERTICAL_BOUNDS_CHUNK_SIZE - var b = _compute_vertical_bounds_at(pmin_x, pmin_y, chunk_size_x, chunk_size_y) - _chunked_vertical_bounds.set_pixel(x, y, Color(b.x, b.y, 0)) - - -func _compute_vertical_bounds_at( - origin_x: int, origin_y: int, size_x: int, size_y: int) -> Vector2: - - var heights := get_image(CHANNEL_HEIGHT) - assert(heights != null) - match heights.get_format(): - Image.FORMAT_RF: - return _get_heights_range_f(heights, Rect2i(origin_x, origin_y, size_x, size_y)) - Image.FORMAT_RGB8: - return _get_heights_range_rgb8(heights, Rect2i(origin_x, origin_y, size_x, size_y)) - _: - _logger.error(str("Unknown heightmap format ", heights.get_format())) - return Vector2() - - -static func _get_heights_range_rgb8(im: Image, rect: Rect2i) -> Vector2: - assert(im.get_format() == Image.FORMAT_RGB8) - - rect = rect.intersection(Rect2i(0, 0, im.get_width(), im.get_height())) - var min_x := rect.position.x - var min_y := rect.position.y - var max_x := min_x + rect.size.x - var max_y := min_y + rect.size.y - - var min_height := decode_height_from_rgb8_unorm(im.get_pixel(min_x, min_y)) - var max_height := min_height - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var h := decode_height_from_rgb8_unorm(im.get_pixel(x, y)) - min_height = minf(h, min_height) - max_height = maxf(h, max_height) - - return Vector2(min_height, max_height) - - -static func _get_heights_range_f(im: Image, rect: Rect2i) -> Vector2: - assert(im.get_format() == Image.FORMAT_RF) - - rect = rect.intersection(Rect2i(0, 0, im.get_width(), im.get_height())) - var min_x := rect.position.x - var min_y := rect.position.y - var max_x := min_x + rect.size.x - var max_y := min_y + rect.size.y - - var min_height := im.get_pixel(min_x, min_y).r - var max_height := min_height - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var h := im.get_pixel(x, y).r - min_height = minf(h, min_height) - max_height = maxf(h, max_height) - - return Vector2(min_height, max_height) - - -func save_data(data_dir: String) -> bool: - _logger.debug("Saving terrain data...") - - _locked = true - - _save_metadata(data_dir.path_join(META_FILENAME)) - - var map_count = _get_total_map_count() - - var all_succeeded = true - - var pi = 0 - for map_type in CHANNEL_COUNT: - var maps : Array = _maps[map_type] - - for index in len(maps): - var map : HT_Map = maps[index] - if not map.modified: - _logger.debug(str( - "Skipping non-modified ", get_map_debug_name(map_type, index))) - continue - - _logger.debug(str("Saving map ", get_map_debug_name(map_type, index), - " as ", _get_map_filename(map_type, index), "...")) - - all_succeeded = all_succeeded and _save_map(data_dir, map_type, index) - - map.modified = false - pi += 1 - - # TODO Cleanup unused map files? - - # TODO In editor, trigger reimport on generated assets - _locked = false - - return all_succeeded - - -func _is_any_map_modified() -> bool: - for maplist in _maps: - for map in maplist: - if map.modified: - return true - return false - - -func _get_total_map_count() -> int: - var s = 0 - for maps in _maps: - s += len(maps) - return s - - -func _load_metadata(path: String): - var f = FileAccess.open(path, FileAccess.READ) - assert(f != null) - var text = f.get_as_text() - f = null # close file - var json = JSON.new() - var json_err := json.parse(text) - # Careful, `assert` is stripped in release exports, including its argument expression... - # See https://github.com/godotengine/godot-proposals/issues/502 - assert(json_err == OK) - _deserialize_metadata(json.data) - - -func _save_metadata(path: String): - var d = _serialize_metadata() - var text = JSON.stringify(d, "\t", true) - var f = FileAccess.open(path, FileAccess.WRITE) - var err = f.get_error() - assert(err == OK) - f.store_string(text) - - -func _serialize_metadata() -> Dictionary: - var data := [] - data.resize(len(_maps)) - - for i in range(len(_maps)): - var maps = _maps[i] - var maps_data := [] - - for j in range(len(maps)): - var map : HT_Map = maps[j] - maps_data.append({ "id": map.id }) - - data[i] = maps_data - - return { - "version": META_VERSION, - "maps": data - } - - -# Parse metadata that we'll then use to load the actual terrain -# (How many maps, which files to load etc...) -func _deserialize_metadata(dict: Dictionary) -> bool: - if not dict.has("version"): - _logger.error("Terrain metadata has no version") - return false - - if dict.version != META_VERSION: - _logger.error("Terrain metadata version mismatch. Got {0}, expected {1}" \ - .format([dict.version, META_VERSION])) - return false - - var data = dict["maps"] - assert(len(data) <= len(_maps)) - - for i in len(data): - var maps = _maps[i] - - var maps_data = data[i] - if len(maps) != len(maps_data): - maps.resize(len(maps_data)) - - for j in len(maps): - var map = maps[j] - # Cast because the data comes from json, where every number is double - var id := int(maps_data[j].id) - if map == null: - map = HT_Map.new(id) - maps[j] = map - else: - map.id = id - - return true - - -func load_data(dir_path: String): - _locked = true - - _load_metadata(dir_path.path_join(META_FILENAME)) - - _logger.debug("Loading terrain data...") - - var channel_instance_sum = _get_total_map_count() - var pi = 0 - - # Note: if we loaded all maps at once before uploading them to VRAM, - # it would take a lot more RAM than if we load them one by one - for map_type in len(_maps): - var maps = _maps[map_type] - - for index in len(maps): - _logger.debug(str("Loading map ", get_map_debug_name(map_type, index), - " from ", _get_map_filename(map_type, index), "...")) - - _load_map(dir_path, map_type, index) - - # A map that was just loaded is considered not modified yet - maps[index].modified = false - - pi += 1 - - _logger.debug("Calculating vertical bounds...") - _update_all_vertical_bounds() - - _logger.debug("Notify resolution change...") - - _locked = false - resolution_changed.emit() - - -func get_data_dir() -> String: - # The HTerrainData resource represents the metadata and entry point for Godot. - # It should be placed within a folder dedicated for terrain storage. - # Other heavy data such as maps are stored next to that file. - return resource_path.get_base_dir() - - -func _save_map(dir_path: String, map_type: int, index: int) -> bool: - var map : HT_Map = _maps[map_type][index] - var im := map.image - if im == null: - var tex := map.texture - if tex != null: - _logger.debug(str("Image not found for map ", map_type, ", downloading from VRAM")) - im = tex.get_image() - else: - _logger.debug(str("No data in map ", map_type, "[", index, "]")) - # This data doesn't have such map - return true - - # The function says "absolute" but in reality it accepts paths like `res://x`, - # which from a user standpoint are not absolute. Also, `FileAccess.file_exists` exists but - # isn't named "absolute" :shrug: - if not DirAccess.dir_exists_absolute(dir_path): - var err := DirAccess.make_dir_absolute(dir_path) - if err != OK: - _logger.error("Could not create directory '{0}', error {1}" \ - .format([dir_path, HT_Errors.get_message(err)])) - return false - - var fpath := dir_path.path_join(_get_map_filename(map_type, index)) - - return _save_map_image(fpath, map_type, im) - - -func _save_map_image(fpath: String, map_type: int, im: Image) -> bool: - if _channel_can_be_saved_as_png(map_type): - fpath += ".png" - var err := im.save_png(fpath) - if err != OK: - _logger.error("Could not save '{0}', error {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return false - _try_write_default_import_options(fpath, map_type, _logger) - - else: - fpath += ".res" - var err := ResourceSaver.save(im, fpath) - if err != OK: - _logger.error("Could not save '{0}', error {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return false - - return true - - -static func _try_write_default_import_options( - fpath: String, channel: int, logger: HT_Logger.HT_LoggerBase): - - var imp_fpath := fpath + ".import" - if FileAccess.file_exists(imp_fpath): - # Already exists - return - - var map_info = _map_types[channel] - var srgb: bool = map_info.srgb - - var defaults : Dictionary - - if channel == CHANNEL_HEIGHT: - defaults = { - "remap": { - # Have the heightmap editable as an image by default - "importer": "image", - "type": "Image" - }, - "deps": { - "source_file": fpath - } - } - - else: - defaults = { - "remap": { - "importer": "texture", - "type": "CompressedTexture2D" - }, - "deps": { - "source_file": fpath - }, - "params": { - # Use lossless compression. - # Lossy ruins quality and makes the editor choke on big textures. - # TODO I would have used ImageTexture.COMPRESS_LOSSLESS, - # but apparently what is saved in the .import file does not match, - # and rather corresponds TO THE UI IN THE IMPORT DOCK :facepalm: - "compress/mode": 0, - - "compress/hdr_compression": 0, - "compress/normal_map": 0, - # No mipmaps - "mipmaps/limit": 0, - - # Most textures aren't color. - # Same here, this is mapping something from the import dock UI, - # and doesn't have any enum associated, just raw numbers in C++ code... - # 0 = "disabled", 1 = "enabled", 2 = "detect" - "flags/srgb": 2 if srgb else 0, - - # No need for this, the meaning of alpha is never transparency - "process/fix_alpha_border": false, - - # Don't try to be smart. - # This can actually overwrite the settings with defaults... - # https://github.com/godotengine/godot/issues/24220 - "detect_3d/compress_to": 0, - } - } - - HT_Util.write_import_file(defaults, imp_fpath, logger) - - -func _load_map(dir: String, map_type: int, index: int) -> bool: - var fpath := dir.path_join(_get_map_filename(map_type, index)) - - # Maps must be configured before being loaded - var map : HT_Map = _maps[map_type][index] - # while len(_maps) <= map_type: - # _maps.append([]) - # while len(_maps[map_type]) <= index: - # _maps[map_type].append(null) - # var map = _maps[map_type][index] - # if map == null: - # map = Map.new() - # _maps[map_type][index] = map - - if _channel_can_be_saved_as_png(map_type): - fpath += ".png" - else: - fpath += ".res" - - var tex = load(fpath) - - var must_load_image_in_editor := true - - # Short-term compatibility with RGB8 encoding from the godot4 branch - if Engine.is_editor_hint() and tex == null and map_type == CHANNEL_HEIGHT: - var legacy_fpath := fpath.get_basename() + ".png" - var temp = load(legacy_fpath) - if temp != null: - if temp is Texture2D: - temp = temp.get_image() - if temp is Image: - if temp.get_format() == Image.FORMAT_RGB8: - _logger.warn(str( - "Found a heightmap using legacy RGB8 format. It will be converted to RF. ", - "You may want to remove the old file: {0}").format([fpath])) - tex = convert_heightmap_to_float(temp, _logger) - _save_map_image(fpath.get_basename(), map_type, tex) - - if tex != null and tex is Image: - # The texture is imported as Image, - # perhaps the user wants it to be accessible from RAM in game. - _logger.debug("Map {0} is imported as Image. An ImageTexture will be generated." \ - .format([get_map_debug_name(map_type, index)])) - map.image = tex - tex = ImageTexture.create_from_image(map.image) - must_load_image_in_editor = false - - map.texture = tex - - if Engine.is_editor_hint(): - if must_load_image_in_editor: - # But in the editor we want textures to be editable, - # so we have to automatically load the data also in RAM - if map.image == null: - map.image = Image.load_from_file(fpath) - else: - map.image.load(fpath) - _ensure_map_format(map.image, map_type, index) - - if map_type == CHANNEL_HEIGHT: - _resolution = map.image.get_width() - - return true - - -func _ensure_map_format(im: Image, map_type: int, index: int): - var format := im.get_format() - var expected_format : int = _map_types[map_type].texture_format - if format != expected_format: - _logger.warn("Map {0} loaded as format {1}, expected {2}. Will be converted." \ - .format([get_map_debug_name(map_type, index), format, expected_format])) - im.convert(expected_format) - - -# Imports images into the terrain data by converting them to the internal format. -# It is possible to omit some of them, in which case those already setup will be used. -# This function is quite permissive, and will only fail if there is really no way to import. -# It may involve cropping, so preliminary checks should be done to inform the user. -# -# TODO Plan is to make this function threaded, in case import takes too long. -# So anything that could mess with the main thread should be avoided. -# Eventually, it would be temporarily removed from the terrain node to work -# in isolation during import. -func _edit_import_maps(input: Dictionary) -> bool: - assert(typeof(input) == TYPE_DICTIONARY) - - if input.has(CHANNEL_HEIGHT): - var params = input[CHANNEL_HEIGHT] - if not _import_heightmap( - params.path, params.min_height, params.max_height, params.big_endian): - return false - - # TODO Import indexed maps? - var maptypes := [CHANNEL_COLOR, CHANNEL_SPLAT] - - for map_type in maptypes: - if input.has(map_type): - var params = input[map_type] - if not _import_map(map_type, params.path): - return false - - return true - - -# Provided an arbitrary width and height, -# returns the closest size the terrain actuallysupports -static func get_adjusted_map_size(width: int, height: int) -> int: - var width_po2 = HT_Util.next_power_of_two(width - 1) + 1 - var height_po2 = HT_Util.next_power_of_two(height - 1) + 1 - var size_po2 = mini(width_po2, height_po2) - size_po2 = clampi(size_po2, MIN_RESOLUTION, MAX_RESOLUTION) - return size_po2 - - -func _import_heightmap(fpath: String, min_y: float, max_y: float, big_endian: bool) -> bool: - var ext := fpath.get_extension().to_lower() - - if ext == "png": - # Godot can only load 8-bit PNG, - # so we have to bring it back to float in the wanted range - - var src_image := Image.load_from_file(fpath) - # TODO No way to access the error code? - if src_image == null: - return false - - var res := get_adjusted_map_size(src_image.get_width(), src_image.get_height()) - if res != src_image.get_width(): - src_image.crop(res, res) - - _locked = true - - _logger.debug(str("Resizing terrain to ", res, "x", res, "...")) - resize(src_image.get_width(), false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - var hrange := max_y - min_y - - var width := mini(im.get_width(), src_image.get_width()) - var height := mini(im.get_height(), src_image.get_height()) - - _logger.debug("Converting to internal format...") - - # Convert to internal format with range scaling - match im.get_format(): - Image.FORMAT_RF: - for y in width: - for x in height: - var gs := src_image.get_pixel(x, y).r - var h := min_y + hrange * gs - im.set_pixel(x, y, Color(h, h, h)) - Image.FORMAT_RGB8: - for y in width: - for x in height: - var gs := src_image.get_pixel(x, y).r - var h := min_y + hrange * gs - im.set_pixel(x, y, encode_height_to_rgb8_unorm(h)) - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - - elif ext == "exr": - var src_image := Image.load_from_file(fpath) - # TODO No way to access the error code? - if src_image == null: - return false - - var res := get_adjusted_map_size(src_image.get_width(), src_image.get_height()) - if res != src_image.get_width(): - src_image.crop(res, res) - - _locked = true - - _logger.debug(str("Resizing terrain to ", res, "x", res, "...")) - resize(src_image.get_width(), false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - _logger.debug("Converting to internal format...") - - match im.get_format(): - Image.FORMAT_RF: - # See https://github.com/Zylann/godot_heightmap_plugin/issues/34 - # Godot can load EXR but it always makes them have at least 3-channels. - # Heightmaps need only one, so we have to get rid of 2. - var height_format = _map_types[CHANNEL_HEIGHT].texture_format - src_image.convert(height_format) - im.blit_rect(src_image, Rect2i(0, 0, res, res), Vector2i()) - - Image.FORMAT_RGB8: - convert_float_heightmap_to_rgb8(src_image, im) - - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - - elif ext == "raw": - # RAW files don't contain size, so we have to deduce it from 16-bit size. - # We also need to bring it back to float in the wanted range. - - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - return false - - var file_len := f.get_length() - var file_res := HT_Util.integer_square_root(file_len / 2) - if file_res == -1: - # Can't deduce size - return false - - # TODO Need a way to know which endianess our system has! - # For now we have to make an assumption... - # This function is most supposed to execute in the editor. - # The editor officially runs on desktop architectures, which are - # generally little-endian. - if big_endian: - f.big_endian = true - - var res := get_adjusted_map_size(file_res, file_res) - - var width := res - var height := res - - _locked = true - - _logger.debug(str("Resizing terrain to ", width, "x", height, "...")) - resize(res, false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - var hrange := max_y - min_y - - _logger.debug("Converting to internal format...") - - var rw := mini(res, file_res) - var rh := mini(res, file_res) - - # Convert to internal format - var h := 0.0 - for y in rh: - for x in rw: - var gs := float(f.get_16()) / 65535.0 - h = min_y + hrange * float(gs) - match im.get_format(): - Image.FORMAT_RF: - im.set_pixel(x, y, Color(h, 0, 0)) - Image.FORMAT_RGB8: - im.set_pixel(x, y, encode_height_to_rgb8_unorm(h)) - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - return false - - # Skip next pixels if the file is bigger than the accepted resolution - for x in range(rw, file_res): - f.get_16() - - elif ext == "xyz": - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - return false - - var bounds := HT_XYZFormat.load_bounds(f) - var res := get_adjusted_map_size(bounds.image_width, bounds.image_height) - - var width := res - var height := res - - _locked = true - - _logger.debug(str("Resizing terrain to ", width, "x", height, "...")) - resize(res, false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - im.fill(Color(0,0,0)) - - _logger.debug(str("Parsing XYZ file (this can take a while)...")) - f.seek(0) - var float_heightmap := Image.create(im.get_width(), im.get_height(), false, Image.FORMAT_RF) - HT_XYZFormat.load_heightmap(f, float_heightmap, bounds) - - # Flipping because in Godot, for X to mean "east"/"right", Z must be backward, - # and we are using Z to map the Y axis of the heightmap image. - float_heightmap.flip_y() - - match im.get_format(): - Image.FORMAT_RF: - im.blit_rect(float_heightmap, Rect2i(0, 0, res, res), Vector2i()) - Image.FORMAT_RGB8: - convert_float_heightmap_to_rgb8(float_heightmap, im) - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - - # Note: when importing maps with non-compliant sizes and flipping, - # the result might not be aligned to global coordinates. - # If this is a problem, we could just offset the terrain to compensate? - - else: - # File extension not recognized - return false - - _locked = false - - _logger.debug("Notify region change...") - notify_region_change(Rect2(0, 0, get_resolution(), get_resolution()), CHANNEL_HEIGHT) - - return true - - -func _import_map(map_type: int, path: String) -> bool: - # Heightmap requires special treatment - assert(map_type != CHANNEL_HEIGHT) - - var im := Image.load_from_file(path) - # TODO No way to get the error code? - if im == null: - return false - - var res := get_resolution() - if im.get_width() != res or im.get_height() != res: - im.crop(res, res) - - if im.get_format() != get_channel_format(map_type): - im.convert(get_channel_format(map_type)) - - var map : HT_Map = _maps[map_type][0] - map.image = im - - notify_region_change(Rect2(0, 0, im.get_width(), im.get_height()), map_type) - return true - - -# TODO Workaround for https://github.com/Zylann/godot_heightmap_plugin/issues/101 -func _dummy_function(): - pass - - -static func _get_xz(v: Vector3) -> Vector2: - return Vector2(v.x, v.z) - - -class HT_CellRaycastContext: - var begin_pos := Vector3() - var _cell_begin_pos_y := 0.0 - var _cell_begin_pos_2d := Vector2() - var dir := Vector3() - var dir_2d := Vector2() - var vertical_bounds : Image - var hit = null # Vector3 - var heightmap : Image - var broad_param_2d_to_3d := 1.0 - var cell_param_2d_to_3d := 1.0 - # TODO Can't call static functions of the enclosing class..................... - var decode_height_func : Callable - #var dbg - - func broad_cb(cx: int, cz: int, enter_param: float, exit_param: float) -> bool: - if cx < 0 or cz < 0 or cz >= vertical_bounds.get_height() \ - or cx >= vertical_bounds.get_width(): - # The function may occasionally be called at boundary values - return false - var vb := vertical_bounds.get_pixel(cx, cz) - var begin := begin_pos + dir * (enter_param * broad_param_2d_to_3d) - var exit_y := begin_pos.y + dir.y * exit_param * broad_param_2d_to_3d - #_spawn_box(Vector3(cx * VERTICAL_BOUNDS_CHUNK_SIZE, \ - # begin.y, cz * VERTICAL_BOUNDS_CHUNK_SIZE), 2.0) - if begin.y < vb.r or exit_y > vb.g: - # Not hitting this chunk - return false - # We may be hitting something in this chunk, perform a narrow phase - # through terrain cells - var distance_in_chunk_2d := (exit_param - enter_param) * VERTICAL_BOUNDS_CHUNK_SIZE - var cell_ray_origin_2d := Vector2(begin.x, begin.z) - _cell_begin_pos_y = begin.y - _cell_begin_pos_2d = cell_ray_origin_2d - var rhit = HT_Util.grid_raytrace_2d( - cell_ray_origin_2d, dir_2d, cell_cb, distance_in_chunk_2d) - return rhit != null - - func cell_cb(cx: int, cz: int, enter_param: float, exit_param: float) -> bool: - var enter_pos := _cell_begin_pos_2d + dir_2d * enter_param - #var exit_pos := _cell_begin_pos_2d + dir_2d * exit_param - - var enter_y := _cell_begin_pos_y + dir.y * enter_param * cell_param_2d_to_3d - var exit_y := _cell_begin_pos_y + dir.y * exit_param * cell_param_2d_to_3d - - hit = _intersect_cell(heightmap, cx, cz, Vector3(enter_pos.x, enter_y, enter_pos.y), dir, - decode_height_func) - - return hit != null - - static func _intersect_cell(heightmap: Image, cx: int, cz: int, - begin_pos: Vector3, dir: Vector3, decode_func : Callable): - - var c00 := HT_Util.get_pixel_clamped(heightmap, cx, cz) - var c10 := HT_Util.get_pixel_clamped(heightmap, cx + 1, cz) - var c01 := HT_Util.get_pixel_clamped(heightmap, cx, cz + 1) - var c11 := HT_Util.get_pixel_clamped(heightmap, cx + 1, cz + 1) - - var h00 : float = decode_func.call(c00) - var h10 : float = decode_func.call(c10) - var h01 : float = decode_func.call(c01) - var h11 : float = decode_func.call(c11) - - var p00 := Vector3(cx, h00, cz) - var p10 := Vector3(cx + 1, h10, cz) - var p01 := Vector3(cx, h01, cz + 1) - var p11 := Vector3(cx + 1, h11, cz + 1) - - var th0 = Geometry3D.ray_intersects_triangle(begin_pos, dir, p00, p10, p11) - var th1 = Geometry3D.ray_intersects_triangle(begin_pos, dir, p00, p11, p01) - - if th0 != null: - return th0 - return th1 - -# func _spawn_box(pos: Vector3, r: float): -# if not Input.is_key_pressed(KEY_CONTROL): -# return -# var mi = MeshInstance.new() -# mi.mesh = CubeMesh.new() -# mi.translation = pos * dbg.map_scale -# mi.scale = Vector3(r, r, r) -# dbg.add_child(mi) -# mi.owner = dbg.get_tree().edited_scene_root - - -# Raycasts heightmap image directly without using a collider. -# The coordinate system is such that Y is up, terrain minimum corner is at (0, 0), -# and one heightmap pixel is one space unit. -# TODO Cannot hint as `-> Vector2` because it can be null if there is no hit -func cell_raycast(ray_origin: Vector3, ray_direction: Vector3, max_distance: float): - var heightmap := get_image(CHANNEL_HEIGHT) - if heightmap == null: - return null - - var terrain_rect := Rect2(Vector2(), Vector2(_resolution, _resolution)) - - # Project and clip into 2D - var ray_origin_2d := _get_xz(ray_origin) - var ray_end_2d := _get_xz(ray_origin + ray_direction * max_distance) - var clipped_segment_2d := HT_Util.get_segment_clipped_by_rect(terrain_rect, - ray_origin_2d, ray_end_2d) - # TODO We could clip along Y too if we had total AABB cached somewhere - - if len(clipped_segment_2d) == 0: - # Not hitting the terrain area - return null - - var max_distance_2d := ray_origin_2d.distance_to(ray_end_2d) - if max_distance_2d < 0.001: - # TODO Direct vertical hit? - return null - - # Get ratio along the segment where the first point was clipped - var begin_clip_param := ray_origin_2d.distance_to(clipped_segment_2d[0]) / max_distance_2d - - var ray_direction_2d := _get_xz(ray_direction).normalized() - - var ctx := HT_CellRaycastContext.new() - ctx.begin_pos = ray_origin + ray_direction * (begin_clip_param * max_distance) - ctx.dir = ray_direction - ctx.dir_2d = ray_direction_2d - ctx.vertical_bounds = _chunked_vertical_bounds - ctx.heightmap = heightmap - ctx.cell_param_2d_to_3d = max_distance / max_distance_2d - ctx.broad_param_2d_to_3d = ctx.cell_param_2d_to_3d * VERTICAL_BOUNDS_CHUNK_SIZE - - match heightmap.get_format(): - Image.FORMAT_RF: - ctx.decode_height_func = decode_height_from_f - Image.FORMAT_RGB8: - ctx.decode_height_func = decode_height_from_rgb8_unorm - _: - _logger.error(str("Invalid heightmap format ", heightmap.get_format())) - return null - - #ctx.dbg = dbg - - # Broad phase through cached vertical bound chunks - var broad_ray_origin = clipped_segment_2d[0] / VERTICAL_BOUNDS_CHUNK_SIZE - var broad_max_distance = \ - clipped_segment_2d[0].distance_to(clipped_segment_2d[1]) / VERTICAL_BOUNDS_CHUNK_SIZE - var hit_bp = HT_Util.grid_raytrace_2d(broad_ray_origin, ray_direction_2d, ctx.broad_cb, - broad_max_distance) - - if hit_bp == null: - # No hit - return null - - return Vector2(ctx.hit.x, ctx.hit.z) - - -static func encode_normal(n: Vector3) -> Color: - n = 0.5 * (n + Vector3.ONE) - return Color(n.x, n.z, n.y) - - -static func get_channel_format(channel: int) -> int: - return _map_types[channel].texture_format as int - - -# Note: PNG supports 16-bit channels, unfortunately Godot doesn't -static func _channel_can_be_saved_as_png(channel: int) -> bool: - return _map_types[channel].can_be_saved_as_png - - -static func get_channel_name(c: int) -> String: - return _map_types[c].name as String - - -static func get_map_debug_name(map_type: int, index: int) -> String: - return str(get_channel_name(map_type), "[", index, "]") - - -func _get_map_filename(map_type: int, index: int) -> String: - var name = get_channel_name(map_type) - var id = _maps[map_type][index].id - if id > 0: - name += str(id + 1) - return name - - -static func get_map_shader_param_name(map_type: int, index: int) -> String: - var param_name = _map_types[map_type].shader_param_name - if typeof(param_name) == TYPE_STRING: - return param_name - return param_name[index] - - -# TODO Can't type hint because it returns a nullable array -#static func get_map_type_and_index_from_shader_param_name(p_name: String): -# for map_type in _map_types: -# var pn = _map_types[map_type].shader_param_name -# if typeof(pn) == TYPE_STRING: -# if pn == p_name: -# return [map_type, 0] -# else: -# for i in len(pn): -# if pn[i] == p_name: -# return [map_type, i] -# return null - - -static func decode_height_from_f(c: Color) -> float: - return c.r - - -const _V2_UNIT_STEPS = 1024.0 -const _V2_MIN = -8192.0 -const _V2_MAX = 8191.0 -const _V2_DF = 255.0 / _V2_UNIT_STEPS - -# This RGB8 encoding implementation is specific to this plugin. -# It was used in the port to Godot 4.0 for a time, until it was found float -# textures could be used. - -static func decode_height_from_rgb8_unorm(c: Color) -> float: - return (c.r * 0.25 + c.g * 64.0 + c.b * 16384.0) * (4.0 * _V2_DF) + _V2_MIN - - -static func encode_height_to_rgb8_unorm(h: float) -> Color: - h -= _V2_MIN - var i := int(h * _V2_UNIT_STEPS) - var r := i % 256 - var g := (i / 256) % 256 - var b := i / 65536 - return Color(r, g, b, 255.0) / 255.0 - - -static func convert_heightmap_to_float(src: Image, logger: HT_Logger.HT_LoggerBase) -> Image: - var src_format := src.get_format() - - if src_format == Image.FORMAT_RH: - var im : Image = src.duplicate() - im.convert(Image.FORMAT_RF) - return im - - if src_format == Image.FORMAT_RF: - return src.duplicate() as Image - - if src_format == Image.FORMAT_RGB8: - var im := Image.create(src.get_width(), src.get_height(), false, Image.FORMAT_RF) - for y in src.get_height(): - for x in src.get_width(): - var c := src.get_pixel(x, y) - var h := decode_height_from_rgb8_unorm(c) - im.set_pixel(x, y, Color(h, h, h, 1.0)) - return im - - logger.error("Unknown source heightmap format!") - return null - - -static func convert_float_heightmap_to_rgb8(src: Image, dst: Image): - assert(dst.get_format() == Image.FORMAT_RGB8) - assert(dst.get_size() == src.get_size()) - - for y in src.get_height(): - for x in src.get_width(): - var h = src.get_pixel(x, y).r - dst.set_pixel(x, y, encode_height_to_rgb8_unorm(h)) - diff --git a/addons/zylann.hterrain/hterrain_detail_layer.gd b/addons/zylann.hterrain/hterrain_detail_layer.gd deleted file mode 100644 index 2dee704..0000000 --- a/addons/zylann.hterrain/hterrain_detail_layer.gd +++ /dev/null @@ -1,742 +0,0 @@ -@tool -extends Node3D - -# Child node of the terrain, used to render numerous small objects on the ground -# such as grass or rocks. They do so by using a texture covering the terrain -# (a "detail map"), which is found in the terrain data itself. -# A terrain can have multiple detail maps, and you can choose which one will be -# used with `layer_index`. -# Details use instanced rendering within their own chunk grid, scattered around -# the player. Importantly, the position and rotation of this node don't matter, -# and they also do NOT scale with map scale. Indeed, scaling the heightmap -# doesn't mean we want to scale grass blades (which is not a use case I know of). - -const HTerrainData = preload("./hterrain_data.gd") -const HT_DirectMultiMeshInstance = preload("./util/direct_multimesh_instance.gd") -const HT_DirectMeshInstance = preload("./util/direct_mesh_instance.gd") -const HT_Util = preload("./util/util.gd") -const HT_Logger = preload("./util/logger.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const DEFAULT_MESH_PATH = "res://addons/zylann.hterrain/models/grass_quad.obj" - -# Cannot use `const` because `HTerrain` depends on the current script -var HTerrain = load("res://addons/zylann.hterrain/hterrain.gd") - -const CHUNK_SIZE = 32 -const DEFAULT_SHADER_PATH = "res://addons/zylann.hterrain/shaders/detail.gdshader" -const DEBUG = false - -# These parameters are considered built-in, -# they are managed internally so they are not directly exposed -const _API_SHADER_PARAMS = { - "u_terrain_heightmap": true, - "u_terrain_detailmap": true, - "u_terrain_normalmap": true, - "u_terrain_globalmap": true, - "u_terrain_inverse_transform": true, - "u_terrain_normal_basis": true, - "u_albedo_alpha": true, - "u_view_distance": true, - "u_ambient_wind": true -} - -# TODO Should be renamed `map_index` -# Which detail map this layer will use -@export var layer_index := 0: - get: - return layer_index - set(v): - if layer_index == v: - return - layer_index = v - if is_inside_tree(): - _update_material() - HT_Util.update_configuration_warning(self, false) - - -# Texture to render on the detail meshes. -@export var texture : Texture: - get: - return texture - set(tex): - texture = tex - _material.set_shader_parameter("u_albedo_alpha", tex) - - -# How far detail meshes can be seen. -# TODO Improve speed of _get_chunk_aabb() so we can increase the limit -# See https://github.com/Zylann/godot_heightmap_plugin/issues/155 -@export_range(1.0, 500.0) var view_distance := 100.0: - get: - return view_distance - set(v): - if view_distance == v: - return - view_distance = maxf(v, 1.0) - if is_inside_tree(): - _update_material() - - -# Custom shader to replace the default one. -@export var custom_shader : Shader: - get: - return custom_shader - set(shader): - if custom_shader == shader: - return - custom_shader = shader - if custom_shader == null: - _material.shader = load(DEFAULT_SHADER_PATH) - else: - _material.shader = custom_shader - - if Engine.is_editor_hint(): - # Ability to fork default shader - if shader.code == "": - shader.code = _default_shader.code - - -# Density modifier, to make more or less detail meshes appear overall. -@export_range(0, 10) var density := 4.0: - get: - return density - set(v): - v = clampf(v, 0, 10) - if v == density: - return - density = v - _multimesh_need_regen = true - - -# Mesh used for every detail instance (for example, every grass patch). -# If not assigned, an internal quad mesh will be used. -# I would have called it `mesh` but that's too broad and conflicts with local vars ._. -@export var instance_mesh : Mesh: - get: - return instance_mesh - set(p_mesh): - if p_mesh == instance_mesh: - return - instance_mesh = p_mesh - _multimesh.mesh = _get_used_mesh() - - -# Exposes rendering layers, similar to `VisualInstance.layers` -# (IMO this annotation is not specific enough, something might be off...) -@export_flags_3d_render var render_layers := 1: - get: - return render_layers - set(mask): - render_layers = mask - for k in _chunks: - var chunk = _chunks[k] - chunk.set_layer_mask(mask) - - -# Exposes shadow casting setting. -# Possible values are the same as the enum `GeometryInstance.SHADOW_CASTING_SETTING_*`. -# TODO Casting to `int` should not be necessary! Had to do it otherwise GDScript complains... -@export_enum("Off", "On", "DoubleSided", "ShadowsOnly") \ - var cast_shadow := int(GeometryInstance3D.SHADOW_CASTING_SETTING_ON): - get: - return cast_shadow - set(option): - if option == cast_shadow: - return - cast_shadow = option - for k in _chunks: - var mmi : HT_DirectMultiMeshInstance = _chunks[k] - mmi.set_cast_shadow(option) - - -var _material: ShaderMaterial = null -var _default_shader: Shader = null - -# Vector2 => DirectMultiMeshInstance -var _chunks := {} - -var _multimesh: MultiMesh -var _multimesh_need_regen = true -var _multimesh_instance_pool := [] -var _ambient_wind_time := 0.0 -#var _auto_pick_index_on_enter_tree := Engine.is_editor_hint() -var _debug_wirecube_mesh: Mesh = null -var _debug_cubes := [] -var _logger := HT_Logger.get_for(self) - - -func _init(): - _default_shader = load(DEFAULT_SHADER_PATH) - _material = ShaderMaterial.new() - _material.shader = _default_shader - - _multimesh = MultiMesh.new() - _multimesh.transform_format = MultiMesh.TRANSFORM_3D - # TODO Godot 3 had the option to specify color format, but Godot 4 no longer does... - # I only need 8-bit, but Godot 4 uses 32-bit components colors... - #_multimesh.color_format = MultiMesh.COLOR_8BIT - _multimesh.use_colors = true - - -func _enter_tree(): - var terrain = _get_terrain() - if terrain != null: - terrain.transform_changed.connect(_on_terrain_transform_changed) - - #if _auto_pick_index_on_enter_tree: - # _auto_pick_index_on_enter_tree = false - # _auto_pick_index() - - terrain._internal_add_detail_layer(self) - - _update_material() - - -func _exit_tree(): - var terrain = _get_terrain() - if terrain != null: - terrain.transform_changed.disconnect(_on_terrain_transform_changed) - terrain._internal_remove_detail_layer(self) - _update_material() - for k in _chunks.keys(): - _recycle_chunk(k) - _chunks.clear() - - -#func _auto_pick_index(): -# # Automatically pick an unused layer -# -# var terrain = _get_terrain() -# if terrain == null: -# return -# -# var terrain_data = terrain.get_data() -# if terrain_data == null or terrain_data.is_locked(): -# return -# -# var auto_index := layer_index -# var others = terrain.get_detail_layers() -# -# if len(others) > 0: -# var used_layers := [] -# for other in others: -# used_layers.append(other.layer_index) -# used_layers.sort() -# -# auto_index = used_layers[-1] -# for i in range(1, len(used_layers)): -# if used_layers[i - 1] - used_layers[i] > 1: -# # Found a hole, take it instead -# auto_index = used_layers[i] - 1 -# break -# -# print("Auto picked ", auto_index, " ") -# layer_index = auto_index - - -func _get_property_list() -> Array: - # Dynamic properties coming from the shader - var props := [] - if _material != null: - var shader_params = RenderingServer.get_shader_parameter_list(_material.shader.get_rid()) - for p in shader_params: - if _API_SHADER_PARAMS.has(p.name): - continue - var cp := {} - for k in p: - cp[k] = p[k] - cp.name = str("shader_params/", p.name) - props.append(cp) - return props - - -func _get(key: StringName): - var key_str := String(key) - if key_str.begins_with("shader_params/"): - var param_name = key_str.substr(len("shader_params/")) - return get_shader_param(param_name) - - -func _set(key: StringName, v): - var key_str := String(key) - if key_str.begins_with("shader_params/"): - var param_name = key_str.substr(len("shader_params/")) - set_shader_param(param_name, v) - - -func get_shader_param(param_name: String): - return _material.get_shader_parameter(param_name) - - -func set_shader_param(param_name: String, v): - _material.set_shader_parameter(param_name, v) - - -func _get_terrain(): - if is_inside_tree(): - return get_parent() - return null - - -# Compat -func set_texture(tex: Texture): - texture = tex - - -# Compat -func get_texture() -> Texture: - return texture - - -# Compat -func set_layer_index(v: int): - layer_index = v - - -# Compat -func get_layer_index() -> int: - return layer_index - - -# Compat -func set_view_distance(v: float): - return view_distance - - -# Compat -func get_view_distance() -> float: - return view_distance - - -# Compat -func set_custom_shader(shader: Shader): - custom_shader = shader - - -# Compat -func get_custom_shader() -> Shader: - return custom_shader - - -# Compat -func set_instance_mesh(p_mesh: Mesh): - instance_mesh = p_mesh - - -# Compat -func get_instance_mesh() -> Mesh: - return instance_mesh - - -# Compat -func set_render_layer_mask(mask: int): - render_layers = mask - - -# Compat -func get_render_layer_mask() -> int: - return render_layers - - -func _get_used_mesh() -> Mesh: - if instance_mesh == null: - var mesh = load(DEFAULT_MESH_PATH) as Mesh - if mesh == null: - _logger.error(str("Failed to load default mesh: ", DEFAULT_MESH_PATH)) - return mesh - return instance_mesh - - -# Compat -func set_density(v: float): - density = v - - -# Compat -func get_density() -> float: - return density - - -# Updates texture references and values that come from the terrain itself. -# This is typically used when maps are being swapped around in terrain data, -# so we can restore texture references that may break. -func update_material(): - _update_material() - # Formerly update_ambient_wind, reset - - -func _notification(what: int): - match what: - NOTIFICATION_ENTER_WORLD: - _set_world(get_world_3d()) - - NOTIFICATION_EXIT_WORLD: - _set_world(null) - - NOTIFICATION_VISIBILITY_CHANGED: - _set_visible(visible) - - NOTIFICATION_PREDELETE: - # Force DirectMeshInstances to be destroyed before the material. - # Otherwise it causes RenderingServer errors... - _chunks.clear() - _multimesh_instance_pool.clear() - - -func _set_visible(v: bool): - for k in _chunks: - var chunk = _chunks[k] - chunk.set_visible(v) - - -func _set_world(w: World3D): - for k in _chunks: - var chunk = _chunks[k] - chunk.set_world(w) - - -func _on_terrain_transform_changed(gt: Transform3D): - _update_material() - - var terrain = _get_terrain() - if terrain == null: - _logger.error("Detail layer is not child of a terrain!") - return - - var terrain_transform : Transform3D = terrain.get_internal_transform() - - # Update AABBs and transforms, because scale might have changed - for k in _chunks: - var mmi = _chunks[k] - var aabb = _get_chunk_aabb(terrain, Vector3(k.x * CHUNK_SIZE, 0, k.y * CHUNK_SIZE)) - # Nullify XZ translation because that's done by transform already - aabb.position.x = 0 - aabb.position.z = 0 - mmi.set_aabb(aabb) - mmi.set_transform(_get_chunk_transform(terrain_transform, k.x, k.y)) - - -func process(delta: float, viewer_pos: Vector3): - var terrain = _get_terrain() - if terrain == null: - _logger.error("DetailLayer processing while terrain is null!") - return - - if _multimesh_need_regen: - _regen_multimesh() - _multimesh_need_regen = false - # Crash workaround for Godot 3.1 - # See https://github.com/godotengine/godot/issues/32500 - for k in _chunks: - var mmi = _chunks[k] - mmi.set_multimesh(_multimesh) - - # Detail layers are unaffected by ground map_scale - var terrain_transform_without_map_scale : Transform3D = \ - terrain.get_internal_transform_unscaled() - var local_viewer_pos := terrain_transform_without_map_scale.affine_inverse() * viewer_pos - - var viewer_cx = local_viewer_pos.x / CHUNK_SIZE - var viewer_cz = local_viewer_pos.z / CHUNK_SIZE - - var cr = int(view_distance) / CHUNK_SIZE + 1 - - var cmin_x = viewer_cx - cr - var cmin_z = viewer_cz - cr - var cmax_x = viewer_cx + cr - var cmax_z = viewer_cz + cr - - var map_res = terrain.get_data().get_resolution() - var map_scale = terrain.map_scale - - var terrain_size_x = map_res * map_scale.x - var terrain_size_z = map_res * map_scale.z - - var terrain_chunks_x = terrain_size_x / CHUNK_SIZE - var terrain_chunks_z = terrain_size_z / CHUNK_SIZE - - cmin_x = clampi(cmin_x, 0, terrain_chunks_x) - cmin_z = clampi(cmin_z, 0, terrain_chunks_z) - - if DEBUG and visible: - _debug_cubes.clear() - for cz in range(cmin_z, cmax_z): - for cx in range(cmin_x, cmax_x): - _add_debug_cube(terrain, _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE)) - - for cz in range(cmin_z, cmax_z): - for cx in range(cmin_x, cmax_x): - - var cpos2d = Vector2(cx, cz) - if _chunks.has(cpos2d): - continue - - var aabb = _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE) - var d = (aabb.position + 0.5 * aabb.size).distance_to(local_viewer_pos) - - if d < view_distance: - _load_chunk(terrain_transform_without_map_scale, cx, cz, aabb) - - var to_recycle = [] - - for k in _chunks: - var chunk = _chunks[k] - var aabb = _get_chunk_aabb(terrain, Vector3(k.x, 0, k.y) * CHUNK_SIZE) - var d = (aabb.position + 0.5 * aabb.size).distance_to(local_viewer_pos) - if d > view_distance: - to_recycle.append(k) - - for k in to_recycle: - _recycle_chunk(k) - - # Update time manually, so we can accelerate the animation when strength is increased, - # without causing phase jumps (which would be the case if we just scaled TIME) - var ambient_wind_frequency = 1.0 + 3.0 * terrain.ambient_wind - _ambient_wind_time += delta * ambient_wind_frequency - var awp = _get_ambient_wind_params() - _material.set_shader_parameter("u_ambient_wind", awp) - - -# Gets local-space AABB of a detail chunk. -# This only apply map_scale in Y, because details are not affected by X and Z map scale. -func _get_chunk_aabb(terrain, lpos: Vector3): - var terrain_scale = terrain.map_scale - var terrain_data = terrain.get_data() - var origin_cells_x := int(lpos.x / terrain_scale.x) - var origin_cells_z := int(lpos.z / terrain_scale.z) - var size_cells_x := int(CHUNK_SIZE / terrain_scale.x) - var size_cells_z := int(CHUNK_SIZE / terrain_scale.z) - - var aabb = terrain_data.get_region_aabb( - origin_cells_x, origin_cells_z, size_cells_x, size_cells_z) - - aabb.position = Vector3(lpos.x, lpos.y + aabb.position.y * terrain_scale.y, lpos.z) - aabb.size = Vector3(CHUNK_SIZE, aabb.size.y * terrain_scale.y, CHUNK_SIZE) - return aabb - - -func _get_chunk_transform(terrain_transform: Transform3D, cx: int, cz: int) -> Transform3D: - var lpos := Vector3(cx, 0, cz) * CHUNK_SIZE - # `terrain_transform` should be the terrain's internal transform, without `map_scale`. - var trans := Transform3D( - terrain_transform.basis, - terrain_transform.origin + terrain_transform.basis * lpos) - return trans - - -func _load_chunk(terrain_transform_without_map_scale: Transform3D, cx: int, cz: int, aabb: AABB): - aabb.position.x = 0 - aabb.position.z = 0 - - var mmi = null - if len(_multimesh_instance_pool) != 0: - mmi = _multimesh_instance_pool[-1] - _multimesh_instance_pool.pop_back() - else: - mmi = HT_DirectMultiMeshInstance.new() - mmi.set_world(get_world_3d()) - mmi.set_multimesh(_multimesh) - - var trans := _get_chunk_transform(terrain_transform_without_map_scale, cx, cz) - - mmi.set_material_override(_material) - mmi.set_transform(trans) - mmi.set_aabb(aabb) - mmi.set_layer_mask(render_layers) - mmi.set_cast_shadow(cast_shadow) - mmi.set_visible(visible) - - _chunks[Vector2(cx, cz)] = mmi - - -func _recycle_chunk(cpos2d: Vector2): - var mmi = _chunks[cpos2d] - _chunks.erase(cpos2d) - mmi.set_visible(false) - _multimesh_instance_pool.append(mmi) - - -func _get_ambient_wind_params() -> Vector2: - var aw = 0.0 - var terrain = _get_terrain() - if terrain != null: - aw = terrain.ambient_wind - # amplitude, time - return Vector2(aw, _ambient_wind_time) - - -func _update_material(): - # Sets API shader properties. Custom properties are assumed to be set already - _logger.debug("Updating detail layer material") - - var terrain_data = null - var terrain = _get_terrain() - var it = Transform3D() - var normal_basis = Basis() - - if terrain != null: - var gt = terrain.get_internal_transform() - it = gt.affine_inverse() - terrain_data = terrain.get_data() - # This is needed to properly transform normals if the terrain is scaled. - # However we don't want to pick up rotation because it's already factored in the instance - #normal_basis = gt.basis.inverse().transposed() - normal_basis = Basis().scaled(terrain.map_scale).inverse().transposed() - - var mat = _material - - mat.set_shader_parameter("u_terrain_inverse_transform", it) - mat.set_shader_parameter("u_terrain_normal_basis", normal_basis) - mat.set_shader_parameter("u_albedo_alpha", texture) - mat.set_shader_parameter("u_view_distance", view_distance) - mat.set_shader_parameter("u_ambient_wind", _get_ambient_wind_params()) - - var heightmap_texture = null - var normalmap_texture = null - var detailmap_texture = null - var globalmap_texture = null - - if terrain_data != null: - if terrain_data.is_locked(): - _logger.error("Terrain data locked, can't update detail layer now") - return - - heightmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_HEIGHT) - normalmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_NORMAL) - - if layer_index < terrain_data.get_map_count(HTerrainData.CHANNEL_DETAIL): - detailmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_DETAIL, layer_index) - - if terrain_data.get_map_count(HTerrainData.CHANNEL_GLOBAL_ALBEDO) > 0: - globalmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - else: - _logger.error("Terrain data is null, can't update detail layer completely") - - mat.set_shader_parameter("u_terrain_heightmap", heightmap_texture) - mat.set_shader_parameter("u_terrain_detailmap", detailmap_texture) - mat.set_shader_parameter("u_terrain_normalmap", normalmap_texture) - mat.set_shader_parameter("u_terrain_globalmap", globalmap_texture) - - -func _add_debug_cube(terrain: Node3D, aabb: AABB): - var world : World3D = terrain.get_world_3d() - - if _debug_wirecube_mesh == null: - _debug_wirecube_mesh = HT_Util.create_wirecube_mesh() - var mat := StandardMaterial3D.new() - mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - _debug_wirecube_mesh.surface_set_material(0, mat) - - var debug_cube := HT_DirectMeshInstance.new() - debug_cube.set_mesh(_debug_wirecube_mesh) - debug_cube.set_world(world) - #aabb.position.y += 0.2*randf() - debug_cube.set_transform(Transform3D(Basis().scaled(aabb.size), aabb.position)) - - _debug_cubes.append(debug_cube) - - -func _regen_multimesh(): - # We modify the existing multimesh instead of replacing it. - # DirectMultiMeshInstance does not keep a strong reference to them, - # so replacing would break pooled instances. - _generate_multimesh(CHUNK_SIZE, density, _get_used_mesh(), _multimesh) - - -func is_layer_index_valid() -> bool: - var terrain = _get_terrain() - if terrain == null: - return false - var data = terrain.get_data() - if data == null: - return false - return layer_index >= 0 and layer_index < data.get_map_count(HTerrainData.CHANNEL_DETAIL) - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings := PackedStringArray() - - var terrain = _get_terrain() - if not (is_instance_of(terrain, HTerrain)): - warnings.append("This node must be child of an HTerrain node") - return warnings - - var data = terrain.get_data() - if data == null: - warnings.append("The terrain has no data") - return warnings - - if data.get_map_count(HTerrainData.CHANNEL_DETAIL) == 0: - warnings.append("The terrain does not have any detail map") - return warnings - - if layer_index < 0 or layer_index >= data.get_map_count(HTerrainData.CHANNEL_DETAIL): - warnings.append("Layer index is out of bounds") - return warnings - - var tex = data.get_texture(HTerrainData.CHANNEL_DETAIL, layer_index) - if tex == null: - warnings.append("The terrain does not have a map assigned in slot {0}" \ - .format([layer_index])) - - return warnings - - -# Compat -func set_cast_shadow(option: int): - cast_shadow = option - - -# Compat -func get_cast_shadow() -> int: - return cast_shadow - - -static func _generate_multimesh(resolution: int, density: float, mesh: Mesh, multimesh: MultiMesh): - assert(multimesh != null) - - var position_randomness := 0.5 - var scale_randomness := 0.0 - #var color_randomness = 0.5 - - var cell_count := resolution * resolution - var idensity := int(density) - var random_instance_count := int(cell_count * (density - floorf(density))) - var total_instance_count := cell_count * idensity + random_instance_count - - multimesh.instance_count = total_instance_count - multimesh.mesh = mesh - - # First pass ensures uniform spread - var i := 0 - for z in resolution: - for x in resolution: - for j in idensity: - - var pos := Vector3(x, 0, z) - pos.x += randf_range(-position_randomness, position_randomness) - pos.z += randf_range(-position_randomness, position_randomness) - - multimesh.set_instance_color(i, Color(1, 1, 1)) - multimesh.set_instance_transform(i, \ - Transform3D(_get_random_instance_basis(scale_randomness), pos)) - i += 1 - - # Second pass adds the rest - for j in random_instance_count: - var pos = Vector3(randf_range(0, resolution), 0, randf_range(0, resolution)) - multimesh.set_instance_color(i, Color(1, 1, 1)) - multimesh.set_instance_transform(i, \ - Transform3D(_get_random_instance_basis(scale_randomness), pos)) - i += 1 - - -static func _get_random_instance_basis(scale_randomness: float) -> Basis: - var sr := randf_range(0, scale_randomness) - var s := 1.0 + (sr * sr * sr * sr * sr) * 50.0 - - var basis := Basis() - basis = basis.scaled(Vector3(1, s, 1)) - basis = basis.rotated(Vector3(0, 1, 0), randf_range(0, PI)) - - return basis diff --git a/addons/zylann.hterrain/hterrain_mesher.gd b/addons/zylann.hterrain/hterrain_mesher.gd deleted file mode 100644 index 0b371e1..0000000 --- a/addons/zylann.hterrain/hterrain_mesher.gd +++ /dev/null @@ -1,358 +0,0 @@ -@tool - -#const HT_Logger = preload("./util/logger.gd") -const HTerrainData = preload("./hterrain_data.gd") - -const SEAM_LEFT = 1 -const SEAM_RIGHT = 2 -const SEAM_BOTTOM = 4 -const SEAM_TOP = 8 -const SEAM_CONFIG_COUNT = 16 - - -# [seams_mask][lod] -var _mesh_cache := [] -var _chunk_size_x := 16 -var _chunk_size_y := 16 - - -func configure(chunk_size_x: int, chunk_size_y: int, lod_count: int): - assert(typeof(chunk_size_x) == TYPE_INT) - assert(typeof(chunk_size_y) == TYPE_INT) - assert(typeof(lod_count) == TYPE_INT) - - assert(chunk_size_x >= 2 or chunk_size_y >= 2) - - _mesh_cache.resize(SEAM_CONFIG_COUNT) - - if chunk_size_x == _chunk_size_x \ - and chunk_size_y == _chunk_size_y and lod_count == len(_mesh_cache): - return - - _chunk_size_x = chunk_size_x - _chunk_size_y = chunk_size_y - - # TODO Will reduce the size of this cache, but need index buffer swap feature - for seams in SEAM_CONFIG_COUNT: - var slot := [] - slot.resize(lod_count) - _mesh_cache[seams] = slot - - for lod in lod_count: - slot[lod] = make_flat_chunk(_chunk_size_x, _chunk_size_y, 1 << lod, seams) - - -func get_chunk(lod: int, seams: int) -> Mesh: - return _mesh_cache[seams][lod] as Mesh - - -static func make_flat_chunk(quad_count_x: int, quad_count_y: int, stride: int, seams: int) -> Mesh: - var positions = PackedVector3Array() - positions.resize((quad_count_x + 1) * (quad_count_y + 1)) - - var i = 0 - for y in quad_count_y + 1: - for x in quad_count_x + 1: - positions[i] = Vector3(x * stride, 0, y * stride) - i += 1 - - var indices := make_indices(quad_count_x, quad_count_y, seams) - - var arrays := [] - arrays.resize(Mesh.ARRAY_MAX); - arrays[Mesh.ARRAY_VERTEX] = positions - arrays[Mesh.ARRAY_INDEX] = indices - - var mesh := ArrayMesh.new() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) - - return mesh - - -# size: chunk size in quads (there are N+1 vertices) -# seams: Bitfield for which seams are present -static func make_indices(chunk_size_x: int, chunk_size_y: int, seams: int) -> PackedInt32Array: - var output_indices := PackedInt32Array() - - if seams != 0: - # LOD seams can't be made properly on uneven chunk sizes - assert(chunk_size_x % 2 == 0 and chunk_size_y % 2 == 0) - - var reg_origin_x := 0 - var reg_origin_y := 0 - var reg_size_x := chunk_size_x - var reg_size_y := chunk_size_y - var reg_hstride := 1 - - if seams & SEAM_LEFT: - reg_origin_x += 1; - reg_size_x -= 1; - reg_hstride += 1 - - if seams & SEAM_BOTTOM: - reg_origin_y += 1 - reg_size_y -= 1 - - if seams & SEAM_RIGHT: - reg_size_x -= 1 - reg_hstride += 1 - - if seams & SEAM_TOP: - reg_size_y -= 1 - - # Regular triangles - var ii := reg_origin_x + reg_origin_y * (chunk_size_x + 1) - - for y in reg_size_y: - for x in reg_size_x: - var i00 := ii - var i10 := ii + 1 - var i01 := ii + chunk_size_x + 1 - var i11 := i01 + 1 - - # 01---11 - # | /| - # | / | - # |/ | - # 00---10 - - # This flips the pattern to make the geometry orientation-free. - # Not sure if it helps in any way though - var flip = ((x + reg_origin_x) + (y + reg_origin_y) % 2) % 2 != 0 - - if flip: - output_indices.push_back( i00 ) - output_indices.push_back( i10 ) - output_indices.push_back( i01 ) - - output_indices.push_back( i10 ) - output_indices.push_back( i11 ) - output_indices.push_back( i01 ) - - else: - output_indices.push_back( i00 ) - output_indices.push_back( i11 ) - output_indices.push_back( i01 ) - - output_indices.push_back( i00 ) - output_indices.push_back( i10 ) - output_indices.push_back( i11 ) - - ii += 1 - ii += reg_hstride - - # Left seam - if seams & SEAM_LEFT: - - # 4 . 5 - # |\ . - # | \ . - # | \. - # (2)| 3 - # | /. - # | / . - # |/ . - # 0 . 1 - - var i := 0 - var n := chunk_size_y / 2 - - for j in n: - var i0 := i - var i1 := i + 1 - var i3 := i + chunk_size_x + 2 - var i4 := i + 2 * (chunk_size_x + 1) - var i5 := i4 + 1 - - output_indices.push_back( i0 ) - output_indices.push_back( i3 ) - output_indices.push_back( i4 ) - - if j != 0 or (seams & SEAM_BOTTOM) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i1 ) - output_indices.push_back( i3 ) - - if j != n - 1 or (seams & SEAM_TOP) == 0: - output_indices.push_back( i3 ) - output_indices.push_back( i5 ) - output_indices.push_back( i4 ) - - i = i4 - - if seams & SEAM_RIGHT: - - # 4 . 5 - # . /| - # . / | - # ./ | - # 2 |(3) - # .\ | - # . \ | - # . \| - # 0 . 1 - - var i := chunk_size_x - 1 - var n := chunk_size_y / 2 - - for j in n: - - var i0 := i - var i1 := i + 1 - var i2 := i + chunk_size_x + 1 - var i4 := i + 2 * (chunk_size_x + 1) - var i5 := i4 + 1 - - output_indices.push_back( i1 ) - output_indices.push_back( i5 ) - output_indices.push_back( i2 ) - - if j != 0 or (seams & SEAM_BOTTOM) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i1 ) - output_indices.push_back( i2 ) - - if j != n - 1 or (seams & SEAM_TOP) == 0: - output_indices.push_back( i2 ) - output_indices.push_back( i5 ) - output_indices.push_back( i4 ) - - i = i4; - - if seams & SEAM_BOTTOM: - - # 3 . 4 . 5 - # . / \ . - # . / \ . - # ./ \. - # 0-------2 - # (1) - - var i := 0; - var n := chunk_size_x / 2; - - for j in n: - - var i0 := i - var i2 := i + 2 - var i3 := i + chunk_size_x + 1 - var i4 := i3 + 1 - var i5 := i4 + 1 - - output_indices.push_back( i0 ) - output_indices.push_back( i2 ) - output_indices.push_back( i4 ) - - if j != 0 or (seams & SEAM_LEFT) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i4 ) - output_indices.push_back( i3 ) - - if j != n - 1 or (seams & SEAM_RIGHT) == 0: - output_indices.push_back( i2 ) - output_indices.push_back( i5 ) - output_indices.push_back( i4 ) - - i = i2 - - if seams & SEAM_TOP: - - # (4) - # 3-------5 - # .\ /. - # . \ / . - # . \ / . - # 0 . 1 . 2 - - var i := (chunk_size_y - 1) * (chunk_size_x + 1) - var n := chunk_size_x / 2 - - for j in n: - - var i0 := i - var i1 := i + 1 - var i2 := i + 2 - var i3 := i + chunk_size_x + 1 - var i5 := i3 + 2 - - output_indices.push_back( i3 ) - output_indices.push_back( i1 ) - output_indices.push_back( i5 ) - - if j != 0 or (seams & SEAM_LEFT) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i1 ) - output_indices.push_back( i3 ) - - if j != n - 1 or (seams & SEAM_RIGHT) == 0: - output_indices.push_back( i1 ) - output_indices.push_back( i2 ) - output_indices.push_back( i5 ) - - i = i2 - - return output_indices - - -static func get_mesh_size(width: int, height: int) -> Dictionary: - return { - "vertices": width * height, - "triangles": (width - 1) * (height - 1) * 2 - } - - -# Makes a full mesh from a heightmap, without any LOD considerations. -# Using this mesh for rendering is very expensive on large terrains. -# Initially used as a workaround for Godot to use for navmesh generation. -static func make_heightmap_mesh(heightmap: Image, stride: int, scale: Vector3, - logger = null) -> Mesh: - - var size_x := heightmap.get_width() / stride - var size_z := heightmap.get_height() / stride - - assert(size_x >= 2) - assert(size_z >= 2) - - var positions := PackedVector3Array() - positions.resize(size_x * size_z) - - var i := 0 - - if heightmap.get_format() == Image.FORMAT_RH or heightmap.get_format() == Image.FORMAT_RF: - for mz in size_z: - for mx in size_x: - var x := mx * stride - var z := mz * stride - var y := heightmap.get_pixel(x, z).r - positions[i] = Vector3(x, y, z) * scale - i += 1 - - elif heightmap.get_format() == Image.FORMAT_RGB8: - for mz in size_z: - for mx in size_x: - var x := mx * stride - var z := mz * stride - var c := heightmap.get_pixel(x, z) - var y := HTerrainData.decode_height_from_rgb8_unorm(c) - positions[i] = Vector3(x, y, z) * scale - i += 1 - - else: - logger.error("Unknown heightmap format!") - return null - - var indices := make_indices(size_x - 1, size_z - 1, 0) - - var arrays := [] - arrays.resize(Mesh.ARRAY_MAX); - arrays[Mesh.ARRAY_VERTEX] = positions - arrays[Mesh.ARRAY_INDEX] = indices - - if logger != null: - logger.debug(str("Generated mesh has ", len(positions), - " vertices and ", len(indices) / 3, " triangles")) - - var mesh := ArrayMesh.new() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) - - return mesh diff --git a/addons/zylann.hterrain/hterrain_resource_loader.gd b/addons/zylann.hterrain/hterrain_resource_loader.gd deleted file mode 100644 index ccc176b..0000000 --- a/addons/zylann.hterrain/hterrain_resource_loader.gd +++ /dev/null @@ -1,35 +0,0 @@ -@tool -class_name HTerrainDataLoader -extends ResourceFormatLoader - - -const HTerrainData = preload("./hterrain_data.gd") - - -func _get_recognized_extensions() -> PackedStringArray: - return PackedStringArray([HTerrainData.META_EXTENSION]) - - -func _get_resource_type(path: String) -> String: - var ext := path.get_extension().to_lower() - if ext == HTerrainData.META_EXTENSION: - return "Resource" - return "" - - -# TODO Handle UIDs? -# By default Godot will return INVALID_ID, -# which makes this resource only tracked by path, like scripts -# -# func _get_resource_uid(path: String) -> int: -# return ??? - - -func _handles_type(typename: StringName) -> bool: - return typename == &"Resource" - - -func _load(path: String, original_path: String, use_sub_threads: bool, cache_mode: int): - var res = HTerrainData.new() - res.load_data(path.get_base_dir()) - return res diff --git a/addons/zylann.hterrain/hterrain_resource_saver.gd b/addons/zylann.hterrain/hterrain_resource_saver.gd deleted file mode 100644 index be757e8..0000000 --- a/addons/zylann.hterrain/hterrain_resource_saver.gd +++ /dev/null @@ -1,29 +0,0 @@ -@tool -class_name HTerrainDataSaver -extends ResourceFormatSaver - - -const HTerrainData = preload("./hterrain_data.gd") - - -func _get_recognized_extensions(res: Resource) -> PackedStringArray: - if res != null and res is HTerrainData: - return PackedStringArray([HTerrainData.META_EXTENSION]) - return PackedStringArray() - - -func _recognize(res: Resource) -> bool: - return res is HTerrainData - - -func _save(resource: Resource, path: String, flags: int) -> Error: - if resource.save_data(path.get_base_dir()): - return OK - # This can occur if at least one map of the terrain fails to save. - # It doesnt necessarily mean the entire terrain failed to save. - return FAILED - - -# TODO Handle UIDs -# func _set_uid(path: String, uid: int) -> int: -# ??? diff --git a/addons/zylann.hterrain/hterrain_texture_set.gd b/addons/zylann.hterrain/hterrain_texture_set.gd deleted file mode 100644 index 4f9fb01..0000000 --- a/addons/zylann.hterrain/hterrain_texture_set.gd +++ /dev/null @@ -1,253 +0,0 @@ -@tool -extends Resource - -const MODE_TEXTURES = 0 -const MODE_TEXTURE_ARRAYS = 1 -const MODE_COUNT = 2 - -const _mode_names = ["Textures", "TextureArrays"] - -const SRC_TYPE_ALBEDO = 0 -const SRC_TYPE_BUMP = 1 -const SRC_TYPE_NORMAL = 2 -const SRC_TYPE_ROUGHNESS = 3 -const SRC_TYPE_COUNT = 4 - -const _src_texture_type_names = ["albedo", "bump", "normal", "roughness"] - -# Ground texture types (used by the terrain system) -const TYPE_ALBEDO_BUMP = 0 -const TYPE_NORMAL_ROUGHNESS = 1 -const TYPE_COUNT = 2 - -const _texture_type_names = ["albedo_bump", "normal_roughness"] - -const _type_to_src_types = [ - [SRC_TYPE_ALBEDO, SRC_TYPE_BUMP], - [SRC_TYPE_NORMAL, SRC_TYPE_ROUGHNESS] -] - -const _src_default_color_codes = [ - "#ff000000", - "#ff888888", - "#ff8888ff", - "#ffffffff" -] - -# TODO We may get rid of modes in the future, and only use TextureArrays. -# It exists for now for backward compatibility, but it makes the API a bit confusing -var _mode := MODE_TEXTURES -# [type][slot] -> StreamTexture or TextureArray -var _textures := [[], []] - - -static func get_texture_type_name(tt: int) -> String: - return _texture_type_names[tt] - - -static func get_source_texture_type_name(tt: int) -> String: - return _src_texture_type_names[tt] - - -static func get_source_texture_default_color_code(tt: int) -> String: - return _src_default_color_codes[tt] - - -static func get_import_mode_name(mode: int) -> String: - return _mode_names[mode] - - -static func get_src_types_from_type(t: int) -> Array: - return _type_to_src_types[t] - - -static func get_max_slots_for_mode(mode: int) -> int: - match mode: - MODE_TEXTURES: - # This is a legacy mode, where shaders can only have up to 4 - return 4 - MODE_TEXTURE_ARRAYS: - # Will probably be lifted some day - return 16 - return 0 - - -func _get_property_list() -> Array: - return [ - { - "name": "mode", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_STORAGE - }, - { - "name": "textures", - "type": TYPE_ARRAY, - "usage": PROPERTY_USAGE_STORAGE - } - ] - - -func _get(key: StringName): - if key == &"mode": - return _mode - if key == &"textures": - return _textures - - -func _set(key: StringName, value): - if key == &"mode": - # Not using set_mode() here because otherwise it could reset stuff set before... - _mode = value - if key == &"textures": - _textures = value - - -func get_slots_count() -> int: - if _mode == MODE_TEXTURES: - return get_texture_count() - - elif _mode == MODE_TEXTURE_ARRAYS: - # TODO What if there are two texture arrays of different size? - var texarray : TextureLayered = _textures[TYPE_ALBEDO_BUMP][0] - if texarray == null: - texarray = _textures[TYPE_NORMAL_ROUGHNESS][0] - if texarray == null: - return 0 - return texarray.get_layers() - - else: - assert(false) - return 0 - - -func get_texture_count() -> int: - var texs = _textures[TYPE_ALBEDO_BUMP] - return len(texs) - - -func get_texture(slot_index: int, ground_texture_type: int) -> Texture2D: - if _mode == MODE_TEXTURE_ARRAYS: - # Can't get a single texture at once - return null - - elif _mode == MODE_TEXTURES: - var texs = _textures[ground_texture_type] - if slot_index >= len(texs): - return null - return texs[slot_index] - - else: - assert(false) - return null - - -func set_texture(slot_index: int, ground_texture_type: int, texture: Texture2D): - assert(_mode == MODE_TEXTURES) - var texs = _textures[ground_texture_type] - if texs[slot_index] != texture: - texs[slot_index] = texture - emit_changed() - - -func get_texture_array(ground_texture_type: int) -> TextureLayered: - if _mode != MODE_TEXTURE_ARRAYS: - return null - var texs = _textures[ground_texture_type] - return texs[0] - - -func set_texture_array(ground_texture_type: int, texarray: TextureLayered): - assert(_mode == MODE_TEXTURE_ARRAYS) - var texs = _textures[ground_texture_type] - if texs[0] != texarray: - texs[0] = texarray - emit_changed() - - -# TODO This function only exists because of a flaw in UndoRedo -# See https://github.com/godotengine/godot/issues/36895 -func set_texture_null(slot_index: int, ground_texture_type: int): - set_texture(slot_index, ground_texture_type, null) - - -# TODO This function only exists because of a flaw in UndoRedo -# See https://github.com/godotengine/godot/issues/36895 -func set_texture_array_null(ground_texture_type: int): - set_texture_array(ground_texture_type, null) - - -func get_mode() -> int: - return _mode - - -func set_mode(mode: int): - # This effectively clears slots - _mode = mode - clear() - - -func clear(): - match _mode: - MODE_TEXTURES: - for type in TYPE_COUNT: - _textures[type] = [] - MODE_TEXTURE_ARRAYS: - for type in TYPE_COUNT: - _textures[type] = [null] - _: - assert(false) - emit_changed() - - -func insert_slot(i: int) -> int: - assert(_mode == MODE_TEXTURES) - if i == -1: - i = get_texture_count() - for type in TYPE_COUNT: - _textures[type].insert(i, null) - emit_changed() - return i - - -func remove_slot(i: int): - assert(_mode == MODE_TEXTURES) - if i == -1: - i = get_slots_count() - 1 - for type in TYPE_COUNT: - _textures[type].remove_at(i) - emit_changed() - - -func has_any_textures() -> bool: - for type in len(_textures): - var texs = _textures[type] - for i in len(texs): - if texs[i] != null: - return true - return false - - -#func set_textures(textures: Array): -# _textures = textures - - -# Cannot type hint because it would cause circular dependency -#func migrate_from_1_4(terrain): -# var textures := [] -# for type in TYPE_COUNT: -# textures.append([]) -# -# if terrain.is_using_texture_array(): -# for type in TYPE_COUNT: -# var tex : TextureArray = terrain.get_ground_texture_array(type) -# textures[type] = [tex] -# _mode = MODE_TEXTURE_ARRAYS -# -# else: -# for index in terrain.get_max_ground_texture_slot_count(): -# for type in TYPE_COUNT: -# var tex : Texture = terrain.get_ground_texture(type, index) -# textures[type].append(tex) -# _mode = MODE_TEXTURES -# -# _textures = textures diff --git a/addons/zylann.hterrain/models/grass_quad.obj b/addons/zylann.hterrain/models/grass_quad.obj deleted file mode 100644 index 2215279..0000000 --- a/addons/zylann.hterrain/models/grass_quad.obj +++ /dev/null @@ -1,14 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass.blend' -# www.blender.org -o Cube -v 0.000000 1.000000 -0.500000 -v 0.000000 0.000000 -0.500000 -v 0.000000 1.000000 0.500000 -v 0.000000 0.000000 0.500000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 diff --git a/addons/zylann.hterrain/models/grass_quad.obj.import b/addons/zylann.hterrain/models/grass_quad.obj.import deleted file mode 100644 index fe93f30..0000000 --- a/addons/zylann.hterrain/models/grass_quad.obj.import +++ /dev/null @@ -1,21 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://c1k6wgnjlvxpm" -path="res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad.obj" -dest_files=["res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh", "res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh"] - -[params] - -generate_tangents=true -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -optimize_mesh=true diff --git a/addons/zylann.hterrain/models/grass_quad_x2.obj b/addons/zylann.hterrain/models/grass_quad_x2.obj deleted file mode 100644 index 37c4707..0000000 --- a/addons/zylann.hterrain/models/grass_quad_x2.obj +++ /dev/null @@ -1,24 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass_x2.blend' -# www.blender.org -o Cube -v 0.000000 1.000000 -0.500000 -v 0.000000 0.000000 -0.500000 -v 0.000000 1.000000 0.500000 -v 0.000000 0.000000 0.500000 -v -0.500000 1.000000 0.000000 -v -0.500000 0.000000 0.000000 -v 0.500000 1.000000 0.000000 -v 0.500000 0.000000 0.000000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 -f 6/5/2 5/6/2 7/7/2 8/8/2 diff --git a/addons/zylann.hterrain/models/grass_quad_x2.obj.import b/addons/zylann.hterrain/models/grass_quad_x2.obj.import deleted file mode 100644 index 926711a..0000000 --- a/addons/zylann.hterrain/models/grass_quad_x2.obj.import +++ /dev/null @@ -1,21 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://dpef2d0qcn5d4" -path="res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad_x2.obj" -dest_files=["res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh", "res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh"] - -[params] - -generate_tangents=true -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -optimize_mesh=true diff --git a/addons/zylann.hterrain/models/grass_quad_x3.obj b/addons/zylann.hterrain/models/grass_quad_x3.obj deleted file mode 100644 index a373832..0000000 --- a/addons/zylann.hterrain/models/grass_quad_x3.obj +++ /dev/null @@ -1,34 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass_x3.blend' -# www.blender.org -o Cube -v 0.000000 1.000000 -0.500000 -v 0.000000 0.000000 -0.500000 -v 0.000000 1.000000 0.500000 -v 0.000000 0.000000 0.500000 -v -0.433013 1.000000 -0.250000 -v -0.433013 0.000000 -0.250000 -v 0.433013 1.000000 0.250000 -v 0.433013 0.000000 0.250000 -v -0.433013 1.000000 0.250000 -v -0.433013 0.000000 0.250000 -v 0.433013 1.000000 -0.250000 -v 0.433013 0.000000 -0.250000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -vn 0.5000 0.0000 -0.8660 -vn -0.5000 0.0000 -0.8660 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 -f 6/5/2 5/6/2 7/7/2 8/8/2 -f 10/9/3 9/10/3 11/11/3 12/12/3 diff --git a/addons/zylann.hterrain/models/grass_quad_x3.obj.import b/addons/zylann.hterrain/models/grass_quad_x3.obj.import deleted file mode 100644 index f358c1e..0000000 --- a/addons/zylann.hterrain/models/grass_quad_x3.obj.import +++ /dev/null @@ -1,21 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://bhjb8bijf1ql3" -path="res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad_x3.obj" -dest_files=["res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh", "res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh"] - -[params] - -generate_tangents=true -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -optimize_mesh=true diff --git a/addons/zylann.hterrain/models/grass_quad_x4.obj b/addons/zylann.hterrain/models/grass_quad_x4.obj deleted file mode 100644 index b182be6..0000000 --- a/addons/zylann.hterrain/models/grass_quad_x4.obj +++ /dev/null @@ -1,42 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass_x4.blend' -# www.blender.org -o Cube -v 0.250000 1.000000 -0.500000 -v 0.250000 0.000000 -0.500000 -v 0.250000 1.000000 0.500000 -v 0.250000 0.000000 0.500000 -v 0.500000 0.000000 -0.250000 -v 0.500000 1.000000 -0.250000 -v -0.500000 0.000000 -0.250000 -v -0.500000 1.000000 -0.250000 -v -0.250000 0.000000 0.500000 -v -0.250000 1.000000 0.500000 -v -0.250000 0.000000 -0.500000 -v -0.250000 1.000000 -0.500000 -v 0.500000 0.000000 0.250000 -v 0.500000 1.000000 0.250000 -v -0.500000 0.000000 0.250000 -v -0.500000 1.000000 0.250000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 -f 7/5/2 8/6/2 6/7/2 5/8/2 -f 11/9/1 12/10/1 10/11/1 9/12/1 -f 15/13/2 16/14/2 14/15/2 13/16/2 diff --git a/addons/zylann.hterrain/models/grass_quad_x4.obj.import b/addons/zylann.hterrain/models/grass_quad_x4.obj.import deleted file mode 100644 index 79a4caa..0000000 --- a/addons/zylann.hterrain/models/grass_quad_x4.obj.import +++ /dev/null @@ -1,21 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://cism8qe63t4tk" -path="res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad_x4.obj" -dest_files=["res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh", "res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh"] - -[params] - -generate_tangents=true -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -optimize_mesh=true diff --git a/addons/zylann.hterrain/native/.clang-format b/addons/zylann.hterrain/native/.clang-format deleted file mode 100644 index 237fd9c..0000000 --- a/addons/zylann.hterrain/native/.clang-format +++ /dev/null @@ -1,127 +0,0 @@ -# Commented out parameters are those with the same value as base LLVM style -# We can uncomment them if we want to change their value, or enforce the -# chosen value in case the base style changes (last sync: Clang 6.0.1). ---- -### General config, applies to all languages ### -BasedOnStyle: LLVM -AccessModifierOffset: -4 -AlignAfterOpenBracket: DontAlign -# AlignConsecutiveAssignments: false -# AlignConsecutiveDeclarations: false -# AlignEscapedNewlines: Right -# AlignOperands: true -AlignTrailingComments: false -AllowAllParametersOfDeclarationOnNextLine: false -# AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: true -AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: true -# AllowShortLoopsOnASingleLine: false -# AlwaysBreakAfterDefinitionReturnType: None -# AlwaysBreakAfterReturnType: None -# AlwaysBreakBeforeMultilineStrings: false -# AlwaysBreakTemplateDeclarations: false -# BinPackArguments: true -# BinPackParameters: true -# BraceWrapping: -# AfterClass: false -# AfterControlStatement: false -# AfterEnum: false -# AfterFunction: false -# AfterNamespace: false -# AfterObjCDeclaration: false -# AfterStruct: false -# AfterUnion: false -# AfterExternBlock: false -# BeforeCatch: false -# BeforeElse: false -# IndentBraces: false -# SplitEmptyFunction: true -# SplitEmptyRecord: true -# SplitEmptyNamespace: true -# BreakBeforeBinaryOperators: None -# BreakBeforeBraces: Attach -# BreakBeforeInheritanceComma: false -BreakBeforeTernaryOperators: false -# BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: AfterColon -# BreakStringLiterals: true -ColumnLimit: 0 -# CommentPragmas: '^ IWYU pragma:' -# CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 8 -ContinuationIndentWidth: 8 -Cpp11BracedListStyle: false -# DerivePointerAlignment: false -# DisableFormat: false -# ExperimentalAutoDetectBinPacking: false -# FixNamespaceComments: true -# ForEachMacros: -# - foreach -# - Q_FOREACH -# - BOOST_FOREACH -# IncludeBlocks: Preserve -IncludeCategories: - - Regex: '".*"' - Priority: 1 - - Regex: '^<.*\.h>' - Priority: 2 - - Regex: '^<.*' - Priority: 3 -# IncludeIsMainRegex: '(Test)?$' -IndentCaseLabels: true -# IndentPPDirectives: None -IndentWidth: 4 -# IndentWrappedFunctionNames: false -# JavaScriptQuotes: Leave -# JavaScriptWrapImports: true -# KeepEmptyLinesAtTheStartOfBlocks: true -# MacroBlockBegin: '' -# MacroBlockEnd: '' -# MaxEmptyLinesToKeep: 1 -# NamespaceIndentation: None -# PenaltyBreakAssignment: 2 -# PenaltyBreakBeforeFirstCallParameter: 19 -# PenaltyBreakComment: 300 -# PenaltyBreakFirstLessLess: 120 -# PenaltyBreakString: 1000 -# PenaltyExcessCharacter: 1000000 -# PenaltyReturnTypeOnItsOwnLine: 60 -# PointerAlignment: Right -# RawStringFormats: -# - Delimiter: pb -# Language: TextProto -# BasedOnStyle: google -# ReflowComments: true -# SortIncludes: true -# SortUsingDeclarations: true -# SpaceAfterCStyleCast: false -# SpaceAfterTemplateKeyword: true -# SpaceBeforeAssignmentOperators: true -# SpaceBeforeParens: ControlStatements -# SpaceInEmptyParentheses: false -# SpacesBeforeTrailingComments: 1 -# SpacesInAngles: false -# SpacesInContainerLiterals: true -# SpacesInCStyleCastParentheses: false -# SpacesInParentheses: false -# SpacesInSquareBrackets: false -TabWidth: 4 -UseTab: Always ---- -### C++ specific config ### -Language: Cpp -Standard: Cpp03 ---- -### ObjC specific config ### -Language: ObjC -Standard: Cpp03 -ObjCBlockIndentWidth: 4 -# ObjCSpaceAfterProperty: false -# ObjCSpaceBeforeProtocolList: true ---- -### Java specific config ### -Language: Java -# BreakAfterJavaFieldAnnotations: false -... diff --git a/addons/zylann.hterrain/native/.gitignore b/addons/zylann.hterrain/native/.gitignore deleted file mode 100644 index 398d727..0000000 --- a/addons/zylann.hterrain/native/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Build -# Ignored locally because there are other folders in which we want to version OBJ files -*.obj - diff --git a/addons/zylann.hterrain/native/SConstruct b/addons/zylann.hterrain/native/SConstruct deleted file mode 100644 index e36eb55..0000000 --- a/addons/zylann.hterrain/native/SConstruct +++ /dev/null @@ -1,119 +0,0 @@ -#!python -import os - -opts = Variables([], ARGUMENTS) - -# Gets the standard flags CC, CCX, etc. -env = Environment(ENV = os.environ) - -# Define our options -opts.Add(EnumVariable('target', "Compilation target", 'debug', ['debug', 'release'])) -opts.Add(EnumVariable('platform', "Compilation platform", '', ['', 'windows', 'linux', 'osx'])) -opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no')) -opts.Add(EnumVariable('macos_arch', "Target macOS architecture", 'universal', ['universal', 'x86_64', 'arm64'])) - -# Hardcoded ones -target_path = "bin/" -TARGET_NAME = "hterrain_native" - -# Local dependency paths -godot_headers_path = "godot-cpp/godot-headers/" -cpp_bindings_path = "godot-cpp/" -cpp_bindings_library = "libgodot-cpp" - -# only support 64 at this time -bits = 64 - -# Updates the environment with the option variables. -opts.Update(env) - -# Process some arguments -if env['use_llvm']: - env['CC'] = 'clang' - env['CXX'] = 'clang++' - -if env['platform'] == '': - print("No valid target platform selected.") - quit() - -# For the reference: -# - CCFLAGS are compilation flags shared between C and C++ -# - CFLAGS are for C-specific compilation flags -# - CXXFLAGS are for C++-specific compilation flags -# - CPPFLAGS are for pre-processor flags -# - CPPDEFINES are for pre-processor defines -# - LINKFLAGS are for linking flags - -# Check our platform specifics -if env['platform'] == "osx": - target_path += 'osx/' - cpp_bindings_library += '.osx' - if env['target'] == 'debug': - env.Append(CCFLAGS = ['-g', '-O2', '-arch', 'x86_64']) - env.Append(CXXFLAGS = ['-std=c++17']) - env.Append(LINKFLAGS = ['-arch', 'x86_64']) - else: - env.Append(CCFLAGS = ['-g', '-O3', '-arch', 'x86_64']) - env.Append(CXXFLAGS = ['-std=c++17']) - env.Append(LINKFLAGS = ['-arch', 'x86_64']) - -elif env['platform'] == "linux": - target_path += 'linux/' - cpp_bindings_library += '.linux' - if env['target'] == 'debug': - # -g3 means we want plenty of debug info, more than default - env.Append(CCFLAGS = ['-fPIC', '-g3', '-Og']) - env.Append(CXXFLAGS = ['-std=c++17']) - else: - env.Append(CCFLAGS = ['-fPIC', '-O3']) - env.Append(CXXFLAGS = ['-std=c++17']) - env.Append(LINKFLAGS = ['-s']) - -elif env['platform'] == "windows": - target_path += 'win64/' - cpp_bindings_library += '.windows' - # This makes sure to keep the session environment variables on windows, - # that way you can run scons in a vs 2017 prompt and it will find all the required tools - #env.Append(ENV = os.environ) - - env.Append(CPPDEFINES = ['WIN32', '_WIN32', '_WINDOWS', '_CRT_SECURE_NO_WARNINGS']) - env.Append(CCFLAGS = ['-W3', '-GR']) - if env['target'] == 'debug': - env.Append(CPPDEFINES = ['_DEBUG']) - env.Append(CCFLAGS = ['-EHsc', '-MDd', '-ZI']) - env.Append(LINKFLAGS = ['-DEBUG']) - else: - env.Append(CPPDEFINES = ['NDEBUG']) - env.Append(CCFLAGS = ['-O2', '-EHsc', '-MD']) - -if env['target'] == 'debug': - cpp_bindings_library += '.debug' -else: - cpp_bindings_library += '.release' - -if env['macos_arch'] == 'universal': - cpp_bindings_library += '.' + str(bits) -else: - cpp_bindings_library += '.' + env['macos_arch'] - -# make sure our binding library is properly included -env.Append(CPPPATH = [ - '.', - godot_headers_path, - cpp_bindings_path + 'include/', - cpp_bindings_path + 'include/core/', - cpp_bindings_path + 'include/gen/' -]) -env.Append(LIBPATH = [cpp_bindings_path + 'bin/']) -env.Append(LIBS = [cpp_bindings_library]) - -# Add source files of our library -env.Append(CPPPATH = ['src/']) -sources = Glob('src/*.cpp') - -library = env.SharedLibrary(target = target_path + TARGET_NAME , source = sources) - -Default(library) - -# Generates help for the -h scons option. -Help(opts.GenerateHelpText(env)) diff --git a/addons/zylann.hterrain/native/bin/linux/libhterrain_native.so b/addons/zylann.hterrain/native/bin/linux/libhterrain_native.so deleted file mode 100644 index b562edd..0000000 Binary files a/addons/zylann.hterrain/native/bin/linux/libhterrain_native.so and /dev/null differ diff --git a/addons/zylann.hterrain/native/bin/osx/libhterrain_native.dylib b/addons/zylann.hterrain/native/bin/osx/libhterrain_native.dylib deleted file mode 100644 index bba68dd..0000000 Binary files a/addons/zylann.hterrain/native/bin/osx/libhterrain_native.dylib and /dev/null differ diff --git a/addons/zylann.hterrain/native/bin/win64/hterrain_native.dll b/addons/zylann.hterrain/native/bin/win64/hterrain_native.dll deleted file mode 100644 index 4f2af10..0000000 Binary files a/addons/zylann.hterrain/native/bin/win64/hterrain_native.dll and /dev/null differ diff --git a/addons/zylann.hterrain/native/factory.gd b/addons/zylann.hterrain/native/factory.gd deleted file mode 100644 index d2dfe56..0000000 --- a/addons/zylann.hterrain/native/factory.gd +++ /dev/null @@ -1,55 +0,0 @@ -@tool - -const NATIVE_PATH = "res://addons/zylann.hterrain/native/" - -const HT_ImageUtilsGeneric = preload("./image_utils_generic.gd") -const HT_QuadTreeLodGeneric = preload("./quad_tree_lod_generic.gd") - -# No native code was ported when moving to Godot 4. -# It may be changed too using GDExtension. - -# See https://docs.godotengine.org/en/stable/classes/class_os.html#class-os-method-get-name -const _supported_os = { - # "Windows": true, - # "X11": true, - # "OSX": true -} -# See https://docs.godotengine.org/en/stable/tutorials/export/feature_tags.html -const _supported_archs = ["x86_64"] - - -static func _supports_current_arch() -> bool: - for arch in _supported_archs: - # This is misleading, we are querying features of the ENGINE, not the OS - if OS.has_feature(arch): - return true - return false - - -static func is_native_available() -> bool: - if not _supports_current_arch(): - return false - var os = OS.get_name() - if not _supported_os.has(os): - return false - # API changes can cause binary incompatibility - var v = Engine.get_version_info() - return v.major == 4 and v.minor == 0 - - -static func get_image_utils(): - if is_native_available(): - var HT_ImageUtilsNative = load(NATIVE_PATH + "image_utils.gdns") - # TODO Godot doesn't always return `null` when it fails so that `if` doesn't always help... - # See https://github.com/Zylann/godot_heightmap_plugin/issues/331 - if HT_ImageUtilsNative != null: - return HT_ImageUtilsNative.new() - return HT_ImageUtilsGeneric.new() - - -static func get_quad_tree_lod(): - if is_native_available(): - var HT_QuadTreeLod = load(NATIVE_PATH + "quad_tree_lod.gdns") - if HT_QuadTreeLod != null: - return HT_QuadTreeLod.new() - return HT_QuadTreeLodGeneric.new() diff --git a/addons/zylann.hterrain/native/image_utils_generic.gd b/addons/zylann.hterrain/native/image_utils_generic.gd deleted file mode 100644 index 2a8aed8..0000000 --- a/addons/zylann.hterrain/native/image_utils_generic.gd +++ /dev/null @@ -1,316 +0,0 @@ -@tool - -# These functions are the same as the ones found in the GDNative library. -# They are used if the user's platform is not supported. - -const HT_Util = preload("../util/util.gd") - -var _blur_buffer : Image - - -func get_red_range(im: Image, rect: Rect2) -> Vector2: - rect = rect.intersection(Rect2(0, 0, im.get_width(), im.get_height())) - var min_x := int(rect.position.x) - var min_y := int(rect.position.y) - var max_x := min_x + int(rect.size.x) - var max_y := min_y + int(rect.size.y) - - var min_height := im.get_pixel(min_x, min_y).r - var max_height := min_height - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var h = im.get_pixel(x, y).r - if h < min_height: - min_height = h - elif h > max_height: - max_height = h - - return Vector2(min_height, max_height) - - -func get_red_sum(im: Image, rect: Rect2) -> float: - rect = rect.intersection(Rect2(0, 0, im.get_width(), im.get_height())) - var min_x := int(rect.position.x) - var min_y := int(rect.position.y) - var max_x := min_x + int(rect.size.x) - var max_y := min_y + int(rect.size.y) - - var sum := 0.0 - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - sum += im.get_pixel(x, y).r - - return sum - - -func get_red_sum_weighted(im: Image, brush: Image, pos: Vector2, factor: float) -> float: - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - var sum = 0.0 - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - sum += im.get_pixel(x, y).r * shape_value * factor - - return sum - - -func add_red_brush(im: Image, brush: Image, pos: Vector2, factor: float): - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - var r = im.get_pixel(x, y).r + shape_value * factor - im.set_pixel(x, y, Color(r, r, r)) - - -func lerp_channel_brush(im: Image, brush: Image, pos: Vector2, - factor: float, target_value: float, channel: int): - - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - var c = im.get_pixel(x, y) - c[channel] = lerp(c[channel], target_value, shape_value * factor) - im.set_pixel(x, y, c) - - -func lerp_color_brush(im: Image, brush: Image, pos: Vector2, - factor: float, target_value: Color): - - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - var c = im.get_pixel(x, y).lerp(target_value, factor * shape_value) - im.set_pixel(x, y, c) - - -func generate_gaussian_brush(im: Image) -> float: - var sum := 0.0 - var center := Vector2(im.get_width() / 2, im.get_height() / 2) - var radius := minf(im.get_width(), im.get_height()) / 2.0 - - for y in im.get_height(): - for x in im.get_width(): - var d := Vector2(x, y).distance_to(center) / radius - var v := clampf(1.0 - d * d * d, 0.0, 1.0) - im.set_pixel(x, y, Color(v, v, v)) - sum += v; - - return sum - - -func blur_red_brush(im: Image, brush: Image, pos: Vector2, factor: float): - factor = clampf(factor, 0.0, 1.0) - - if _blur_buffer == null: - _blur_buffer = Image.new() - var buffer := _blur_buffer - - var buffer_width := brush.get_width() + 2 - var buffer_height := brush.get_height() + 2 - - if buffer_width != buffer.get_width() or buffer_height != buffer.get_height(): - buffer.create(buffer_width, buffer_height, false, Image.FORMAT_RF) - - var min_x := int(pos.x) - 1 - var min_y := int(pos.y) - 1 - var max_x := min_x + buffer.get_width() - var max_y := min_y + buffer.get_height() - - var im_clamp_w = im.get_width() - 1 - var im_clamp_h = im.get_height() - 1 - - # Copy pixels to temporary buffer - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var ix := clampi(x, 0, im_clamp_w) - var iy := clampi(y, 0, im_clamp_h) - var c = im.get_pixel(ix, iy) - buffer.set_pixel(x - min_x, y - min_y, c) - - min_x = int(pos.x) - min_y = int(pos.y) - max_x = min_x + brush.get_width() - max_y = min_y + brush.get_height() - var min_noclamp_x := min_x - var min_noclamp_y := min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - # Apply blur - for y in range(min_y, max_y): - var by := y - min_noclamp_y - - for x in range(min_x, max_x): - var bx := x - min_noclamp_x - - var shape_value := brush.get_pixel(bx, by).r * factor - - var p10 = buffer.get_pixel(bx + 1, by ).r - var p01 = buffer.get_pixel(bx, by + 1).r - var p11 = buffer.get_pixel(bx + 1, by + 1).r - var p21 = buffer.get_pixel(bx + 2, by + 1).r - var p12 = buffer.get_pixel(bx + 1, by + 2).r - - var m = (p10 + p01 + p11 + p21 + p12) * 0.2 - var p = lerpf(p11, m, shape_value * factor) - - im.set_pixel(x, y, Color(p, p, p)) - - -func paint_indexed_splat(index_map: Image, weight_map: Image, brush: Image, pos: Vector2, \ - texture_index: int, factor: float): - - var min_x := pos.x - var min_y := pos.y - var max_x := min_x + brush.get_width() - var max_y := min_y + brush.get_height() - var min_noclamp_x := min_x - var min_noclamp_y := min_y - - min_x = clampi(min_x, 0, index_map.get_width()) - min_y = clampi(min_y, 0, index_map.get_height()) - max_x = clampi(max_x, 0, index_map.get_width()) - max_y = clampi(max_y, 0, index_map.get_height()) - - var texture_index_f := float(texture_index) / 255.0 - var all_texture_index_f := Color(texture_index_f, texture_index_f, texture_index_f) - var ci := texture_index % 3 - var cm := Color(-1, -1, -1) - cm[ci] = 1 - - for y in range(min_y, max_y): - var by := y - min_noclamp_y - - for x in range(min_x, max_x): - var bx := x - min_noclamp_x - - var shape_value := brush.get_pixel(bx, by).r * factor - if shape_value == 0.0: - continue - - var i := index_map.get_pixel(x, y) - var w := weight_map.get_pixel(x, y) - - # Decompress third weight to make computations easier - w[2] = 1.0 - w[0] - w[1] - - # The index map tells which textures to blend. - # The weight map tells their blending amounts. - # This brings the limitation that up to 3 textures can blend at a time in a given pixel. - # Painting this in real time can be a challenge. - - # The approach here is a compromise for simplicity. - # Each texture is associated a fixed component of the index map (R, G or B), - # so two neighbor pixels having the same component won't be guaranteed to blend. - # In other words, texture T will not be able to blend with T + N * k, - # where k is an integer, and N is the number of components in the index map (up to 4). - # It might still be able to blend due to a special case when an area is uniform, - # but not otherwise. - - # Dynamic component assignment sounds like the alternative, however I wasn't able - # to find a painting algorithm that wasn't confusing, at least the current one is - # predictable. - - # Need to use approximation because Color is float but GDScript uses doubles... - if abs(i[ci] - texture_index_f) > 0.001: - # Pixel does not have our texture index, - # transfer its weight to other components first - if w[ci] > shape_value: - w -= cm * shape_value - - elif w[ci] >= 0.0: - w[ci] = 0.0 - i[ci] = texture_index_f - - else: - # Pixel has our texture index, increase its weight - if w[ci] + shape_value < 1.0: - w += cm * shape_value - - else: - # Pixel weight is full, we can set all components to the same index. - # Need to nullify other weights because they would otherwise never reach - # zero due to normalization - w = Color(0, 0, 0) - w[ci] = 1.0 - i = all_texture_index_f - - # No `saturate` function in Color?? - w[0] = clampf(w[0], 0.0, 1.0) - w[1] = clampf(w[1], 0.0, 1.0) - w[2] = clampf(w[2], 0.0, 1.0) - - # Renormalize - w /= w[0] + w[1] + w[2] - - index_map.set_pixel(x, y, i) - weight_map.set_pixel(x, y, w) diff --git a/addons/zylann.hterrain/native/quad_tree_lod_generic.gd b/addons/zylann.hterrain/native/quad_tree_lod_generic.gd deleted file mode 100644 index 8518965..0000000 --- a/addons/zylann.hterrain/native/quad_tree_lod_generic.gd +++ /dev/null @@ -1,188 +0,0 @@ -@tool -# Independent quad tree designed to handle LOD - -class HT_QTLQuad: - # Optional array of 4 HT_QTLQuad - var children = null - - # TODO Use Vector2i - var origin_x : int = 0 - var origin_y : int = 0 - - var data = null - - func _init(): - pass - - func clear(): - clear_children() - data = null - - func clear_children(): - children = null - - func has_children() -> bool: - return children != null - - -var _tree := HT_QTLQuad.new() -var _max_depth : int = 0 -var _base_size : int = 16 -var _split_scale : float = 2.0 - -var _make_func : Callable -var _recycle_func : Callable -var _vertical_bounds_func : Callable - - -func set_callbacks(make_cb: Callable, recycle_cb: Callable, vbounds_cb: Callable): - _make_func = make_cb - _recycle_func = recycle_cb - _vertical_bounds_func = vbounds_cb - - -func clear(): - _join_all_recursively(_tree, _max_depth) - _max_depth = 0 - _base_size = 0 - - -static func compute_lod_count(base_size: int, full_size: int) -> int: - var po : int = 0 - while full_size > base_size: - full_size = full_size >> 1 - po += 1 - return po - - -func create_from_sizes(base_size: int, full_size: int): - clear() - _base_size = base_size - _max_depth = compute_lod_count(base_size, full_size) - - -func get_lod_count() -> int: - # TODO _max_depth is a maximum, not a count. Would be better for it to be a count (+1) - return _max_depth + 1 - - -# The higher, the longer LODs will spread and higher the quality. -# The lower, the shorter LODs will spread and lower the quality. -func set_split_scale(p_split_scale: float): - var MIN := 2.0 - var MAX := 5.0 - - # Split scale must be greater than a threshold, - # otherwise lods will decimate too fast and it will look messy - _split_scale = clampf(p_split_scale, MIN, MAX) - - -func get_split_scale() -> float: - return _split_scale - - -func update(view_pos: Vector3): - _update(_tree, _max_depth, view_pos) - - # This makes sure we keep seeing the lowest LOD, - # if the tree is cleared while we are far away - if not _tree.has_children() and _tree.data == null: - _tree.data = _make_chunk(_max_depth, 0, 0) - - -func get_lod_factor(lod: int) -> int: - return 1 << lod - - -func _update(quad: HT_QTLQuad, lod: int, view_pos: Vector3): - # This function should be called regularly over frames. - - var lod_factor : int = get_lod_factor(lod) - var chunk_size : int = _base_size * lod_factor - var world_center := \ - chunk_size * (Vector3(quad.origin_x, 0, quad.origin_y) + Vector3(0.5, 0, 0.5)) - - if _vertical_bounds_func.is_valid(): - var vbounds : Vector2 = _vertical_bounds_func.call(quad.origin_x, quad.origin_y, lod) - world_center.y = (vbounds.x + vbounds.y) / 2.0 - - var split_distance := _base_size * lod_factor * _split_scale - - if not quad.has_children(): - if lod > 0 and world_center.distance_to(view_pos) < split_distance: - # Split - quad.children = [null, null, null, null] - - for i in 4: - var child := HT_QTLQuad.new() - child.origin_x = quad.origin_x * 2 + (i & 1) - child.origin_y = quad.origin_y * 2 + ((i & 2) >> 1) - quad.children[i] = child - child.data = _make_chunk(lod - 1, child.origin_x, child.origin_y) - # If the quad needs to split more, we'll ask more recycling... - - if quad.data != null: - _recycle_chunk(quad.data, quad.origin_x, quad.origin_y, lod) - quad.data = null - - else: - var no_split_child := true - - for child in quad.children: - _update(child, lod - 1, view_pos) - if child.has_children(): - no_split_child = false - - if no_split_child and world_center.distance_to(view_pos) > split_distance: - # Join - for i in 4: - var child : HT_QTLQuad = quad.children[i] - _recycle_chunk(child.data, child.origin_x, child.origin_y, lod - 1) - quad.clear_children() - quad.data = _make_chunk(lod, quad.origin_x, quad.origin_y) - - -func _join_all_recursively(quad: HT_QTLQuad, lod: int): - if quad.has_children(): - for i in 4: - _join_all_recursively(quad.children[i], lod - 1) - - quad.clear_children() - - elif quad.data != null: - _recycle_chunk(quad.data, quad.origin_x, quad.origin_y, lod) - quad.data = null - - -func _make_chunk(lod: int, origin_x: int, origin_y: int): - var chunk = null - if _make_func.is_valid(): - chunk = _make_func.call(origin_x, origin_y, lod) - return chunk - - -func _recycle_chunk(chunk, origin_x: int, origin_y: int, lod: int): - if _recycle_func.is_valid(): - _recycle_func.call(chunk, origin_x, origin_y, lod) - - -func debug_draw_tree(ci: CanvasItem): - var quad := _tree - _debug_draw_tree_recursive(ci, quad, _max_depth, 0) - - -func _debug_draw_tree_recursive(ci: CanvasItem, quad: HT_QTLQuad, lod_index: int, child_index: int): - if quad.has_children(): - for i in 4: - _debug_draw_tree_recursive(ci, quad.children[i], lod_index - 1, i) - else: - var size : int = get_lod_factor(lod_index) - var checker : int = 0 - if child_index == 1 or child_index == 2: - checker = 1 - var chunk_indicator : int = 0 - if quad.data != null: - chunk_indicator = 1 - var r := Rect2(Vector2(quad.origin_x, quad.origin_y) * size, Vector2(size, size)) - ci.draw_rect(r, Color(1.0 - lod_index * 0.2, 0.2 * checker, chunk_indicator, 1)) - diff --git a/addons/zylann.hterrain/native/src/.gdignore b/addons/zylann.hterrain/native/src/.gdignore deleted file mode 100644 index e69de29..0000000 diff --git a/addons/zylann.hterrain/native/src/gd_library.cpp b/addons/zylann.hterrain/native/src/gd_library.cpp deleted file mode 100644 index d39387f..0000000 --- a/addons/zylann.hterrain/native/src/gd_library.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "image_utils.h" -#include "quad_tree_lod.h" - -extern "C" { - -void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { -#ifdef _DEBUG - printf("godot_gdnative_init hterrain_native\n"); -#endif - godot::Godot::gdnative_init(o); -} - -void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) { -#ifdef _DEBUG - printf("godot_gdnative_terminate hterrain_native\n"); -#endif - godot::Godot::gdnative_terminate(o); -} - -void GDN_EXPORT godot_nativescript_init(void *handle) { -#ifdef _DEBUG - printf("godot_nativescript_init hterrain_native\n"); -#endif - godot::Godot::nativescript_init(handle); - - godot::register_tool_class(); - godot::register_tool_class(); -} - -} // extern "C" diff --git a/addons/zylann.hterrain/native/src/image_utils.cpp b/addons/zylann.hterrain/native/src/image_utils.cpp deleted file mode 100644 index 9131307..0000000 --- a/addons/zylann.hterrain/native/src/image_utils.cpp +++ /dev/null @@ -1,364 +0,0 @@ -#include "image_utils.h" -#include "int_range_2d.h" -#include "math_funcs.h" - -namespace godot { - -template -inline void generic_brush_op(Image &image, Image &brush, Vector2 p_pos, float factor, F op) { - IntRange2D range = IntRange2D::from_min_max(p_pos, brush.get_size()); - int min_x_noclamp = range.min_x; - int min_y_noclamp = range.min_y; - range.clip(Vector2i(image.get_size())); - - image.lock(); - brush.lock(); - - for (int y = range.min_y; y < range.max_y; ++y) { - int by = y - min_y_noclamp; - - for (int x = range.min_x; x < range.max_x; ++x) { - int bx = x - min_x_noclamp; - - float b = brush.get_pixel(bx, by).r * factor; - op(image, x, y, b); - } - } - - image.unlock(); - brush.unlock(); -} - -ImageUtils::ImageUtils() { -#ifdef _DEBUG - Godot::print("Constructing ImageUtils"); -#endif -} - -ImageUtils::~ImageUtils() { -#ifdef _DEBUG - // TODO Cannot print shit here, see https://github.com/godotengine/godot/issues/37417 - // Means only the console will print this - //Godot::print("Destructing ImageUtils"); - printf("Destructing ImageUtils\n"); -#endif -} - -void ImageUtils::_init() { -} - -Vector2 ImageUtils::get_red_range(Ref image_ref, Rect2 rect) const { - ERR_FAIL_COND_V(image_ref.is_null(), Vector2()); - Image &image = **image_ref; - - IntRange2D range(rect); - range.clip(Vector2i(image.get_size())); - - image.lock(); - - float min_value = image.get_pixel(range.min_x, range.min_y).r; - float max_value = min_value; - - for (int y = range.min_y; y < range.max_y; ++y) { - for (int x = range.min_x; x < range.max_x; ++x) { - float v = image.get_pixel(x, y).r; - - if (v > max_value) { - max_value = v; - } else if (v < min_value) { - min_value = v; - } - } - } - - image.unlock(); - - return Vector2(min_value, max_value); -} - -float ImageUtils::get_red_sum(Ref image_ref, Rect2 rect) const { - ERR_FAIL_COND_V(image_ref.is_null(), 0.f); - Image &image = **image_ref; - - IntRange2D range(rect); - range.clip(Vector2i(image.get_size())); - - image.lock(); - - float sum = 0.f; - - for (int y = range.min_y; y < range.max_y; ++y) { - for (int x = range.min_x; x < range.max_x; ++x) { - sum += image.get_pixel(x, y).r; - } - } - - image.unlock(); - - return sum; -} - -float ImageUtils::get_red_sum_weighted(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const { - ERR_FAIL_COND_V(image_ref.is_null(), 0.f); - ERR_FAIL_COND_V(brush_ref.is_null(), 0.f); - Image &image = **image_ref; - Image &brush = **brush_ref; - - float sum = 0.f; - generic_brush_op(image, brush, p_pos, factor, [&sum](Image &image, int x, int y, float b) { - sum += image.get_pixel(x, y).r * b; - }); - - return sum; -} - -void ImageUtils::add_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - generic_brush_op(image, brush, p_pos, factor, [](Image &image, int x, int y, float b) { - float r = image.get_pixel(x, y).r + b; - image.set_pixel(x, y, Color(r, r, r)); - }); -} - -void ImageUtils::lerp_channel_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, float target_value, int channel) const { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - generic_brush_op(image, brush, p_pos, factor, [target_value, channel](Image &image, int x, int y, float b) { - Color c = image.get_pixel(x, y); - c[channel] = Math::lerp(c[channel], target_value, b); - image.set_pixel(x, y, c); - }); -} - -void ImageUtils::lerp_color_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, Color target_value) const { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - generic_brush_op(image, brush, p_pos, factor, [target_value](Image &image, int x, int y, float b) { - const Color c = image.get_pixel(x, y).linear_interpolate(target_value, b); - image.set_pixel(x, y, c); - }); -} - -// TODO Smooth (each pixel being box-filtered, contrary to the existing smooth) - -float ImageUtils::generate_gaussian_brush(Ref image_ref) const { - ERR_FAIL_COND_V(image_ref.is_null(), 0.f); - Image &image = **image_ref; - - int w = static_cast(image.get_width()); - int h = static_cast(image.get_height()); - Vector2 center(w / 2, h / 2); - float radius = Math::min(w, h) / 2; - - ERR_FAIL_COND_V(radius <= 0.1f, 0.f); - - float sum = 0.f; - image.lock(); - - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - float d = Vector2(x, y).distance_to(center) / radius; - float v = Math::clamp(1.f - d * d * d, 0.f, 1.f); - image.set_pixel(x, y, Color(v, v, v)); - sum += v; - } - } - - image.unlock(); - return sum; -} - -void ImageUtils::blur_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - factor = Math::clamp(factor, 0.f, 1.f); - - // Relative to the image - IntRange2D buffer_range = IntRange2D::from_pos_size(p_pos, brush.get_size()); - buffer_range.pad(1); - - const int image_width = static_cast(image.get_width()); - const int image_height = static_cast(image.get_height()); - - const int buffer_width = static_cast(buffer_range.get_width()); - const int buffer_height = static_cast(buffer_range.get_height()); - _blur_buffer.resize(buffer_width * buffer_height); - - image.lock(); - - // Cache pixels, because they will be queried more than once and written to later - int buffer_i = 0; - for (int y = buffer_range.min_y; y < buffer_range.max_y; ++y) { - for (int x = buffer_range.min_x; x < buffer_range.max_x; ++x) { - const int ix = Math::clamp(x, 0, image_width - 1); - const int iy = Math::clamp(y, 0, image_height - 1); - _blur_buffer[buffer_i] = image.get_pixel(ix, iy).r; - ++buffer_i; - } - } - - IntRange2D range = IntRange2D::from_min_max(p_pos, brush.get_size()); - const int min_x_noclamp = range.min_x; - const int min_y_noclamp = range.min_y; - range.clip(Vector2i(image.get_size())); - - const int buffer_offset_left = -1; - const int buffer_offset_right = 1; - const int buffer_offset_top = -buffer_width; - const int buffer_offset_bottom = buffer_width; - - brush.lock(); - - // Apply blur - for (int y = range.min_y; y < range.max_y; ++y) { - const int brush_y = y - min_y_noclamp; - - for (int x = range.min_x; x < range.max_x; ++x) { - const int brush_x = x - min_x_noclamp; - - const float brush_value = brush.get_pixel(brush_x, brush_y).r * factor; - - buffer_i = (brush_x + 1) + (brush_y + 1) * buffer_width; - - const float p10 = _blur_buffer[buffer_i + buffer_offset_top]; - const float p01 = _blur_buffer[buffer_i + buffer_offset_left]; - const float p11 = _blur_buffer[buffer_i]; - const float p21 = _blur_buffer[buffer_i + buffer_offset_right]; - const float p12 = _blur_buffer[buffer_i + buffer_offset_bottom]; - - // Average - float m = (p10 + p01 + p11 + p21 + p12) * 0.2f; - float p = Math::lerp(p11, m, brush_value); - - image.set_pixel(x, y, Color(p, p, p)); - } - } - - image.unlock(); - brush.unlock(); -} - -void ImageUtils::paint_indexed_splat(Ref index_map_ref, Ref weight_map_ref, - Ref brush_ref, Vector2 p_pos, int texture_index, float factor) { - - ERR_FAIL_COND(index_map_ref.is_null()); - ERR_FAIL_COND(weight_map_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &index_map = **index_map_ref; - Image &weight_map = **weight_map_ref; - Image &brush = **brush_ref; - - ERR_FAIL_COND(index_map.get_size() != weight_map.get_size()); - - factor = Math::clamp(factor, 0.f, 1.f); - - IntRange2D range = IntRange2D::from_min_max(p_pos, brush.get_size()); - const int min_x_noclamp = range.min_x; - const int min_y_noclamp = range.min_y; - range.clip(Vector2i(index_map.get_size())); - - const float texture_index_f = float(texture_index) / 255.f; - const Color all_texture_index_f(texture_index_f, texture_index_f, texture_index_f); - const int ci = texture_index % 3; - Color cm(-1, -1, -1); - cm[ci] = 1; - - brush.lock(); - index_map.lock(); - weight_map.lock(); - - for (int y = range.min_y; y < range.max_y; ++y) { - const int brush_y = y - min_y_noclamp; - - for (int x = range.min_x; x < range.max_x; ++x) { - const int brush_x = x - min_x_noclamp; - - const float brush_value = brush.get_pixel(brush_x, brush_y).r * factor; - - if (brush_value == 0.f) { - continue; - } - - Color i = index_map.get_pixel(x, y); - Color w = weight_map.get_pixel(x, y); - - // Decompress third weight to make computations easier - w[2] = 1.f - w[0] - w[1]; - - if (std::abs(i[ci] - texture_index_f) > 0.001f) { - // Pixel does not have our texture index, - // transfer its weight to other components first - if (w[ci] > brush_value) { - w[0] -= cm[0] * brush_value; - w[1] -= cm[1] * brush_value; - w[2] -= cm[2] * brush_value; - - } else if (w[ci] >= 0.f) { - w[ci] = 0.f; - i[ci] = texture_index_f; - } - - } else { - // Pixel has our texture index, increase its weight - if (w[ci] + brush_value < 1.f) { - w[0] += cm[0] * brush_value; - w[1] += cm[1] * brush_value; - w[2] += cm[2] * brush_value; - - } else { - // Pixel weight is full, we can set all components to the same index. - // Need to nullify other weights because they would otherwise never reach - // zero due to normalization - w = Color(0, 0, 0); - w[ci] = 1.0; - i = all_texture_index_f; - } - } - - // No `saturate` function in Color?? - w[0] = Math::clamp(w[0], 0.f, 1.f); - w[1] = Math::clamp(w[1], 0.f, 1.f); - w[2] = Math::clamp(w[2], 0.f, 1.f); - - // Renormalize - const float sum = w[0] + w[1] + w[2]; - w[0] /= sum; - w[1] /= sum; - w[2] /= sum; - - index_map.set_pixel(x, y, i); - weight_map.set_pixel(x, y, w); - } - } - - brush.lock(); - index_map.unlock(); - weight_map.unlock(); -} - -void ImageUtils::_register_methods() { - register_method("get_red_range", &ImageUtils::get_red_range); - register_method("get_red_sum", &ImageUtils::get_red_sum); - register_method("get_red_sum_weighted", &ImageUtils::get_red_sum_weighted); - register_method("add_red_brush", &ImageUtils::add_red_brush); - register_method("lerp_channel_brush", &ImageUtils::lerp_channel_brush); - register_method("lerp_color_brush", &ImageUtils::lerp_color_brush); - register_method("generate_gaussian_brush", &ImageUtils::generate_gaussian_brush); - register_method("blur_red_brush", &ImageUtils::blur_red_brush); - register_method("paint_indexed_splat", &ImageUtils::paint_indexed_splat); -} - -} // namespace godot diff --git a/addons/zylann.hterrain/native/src/image_utils.h b/addons/zylann.hterrain/native/src/image_utils.h deleted file mode 100644 index 5cbe399..0000000 --- a/addons/zylann.hterrain/native/src/image_utils.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef IMAGE_UTILS_H -#define IMAGE_UTILS_H - -#include -#include -#include -#include - -namespace godot { - -class ImageUtils : public Reference { - GODOT_CLASS(ImageUtils, Reference) -public: - static void _register_methods(); - - ImageUtils(); - ~ImageUtils(); - - void _init(); - - Vector2 get_red_range(Ref image_ref, Rect2 rect) const; - float get_red_sum(Ref image_ref, Rect2 rect) const; - float get_red_sum_weighted(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const; - void add_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const; - void lerp_channel_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, float target_value, int channel) const; - void lerp_color_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, Color target_value) const; - float generate_gaussian_brush(Ref image_ref) const; - void blur_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor); - void paint_indexed_splat(Ref index_map_ref, Ref weight_map_ref, Ref brush_ref, Vector2 p_pos, int texture_index, float factor); - //void erode_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor); - -private: - std::vector _blur_buffer; -}; - -} // namespace godot - -#endif // IMAGE_UTILS_H diff --git a/addons/zylann.hterrain/native/src/int_range_2d.h b/addons/zylann.hterrain/native/src/int_range_2d.h deleted file mode 100644 index 8072bea..0000000 --- a/addons/zylann.hterrain/native/src/int_range_2d.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef INT_RANGE_2D_H -#define INT_RANGE_2D_H - -#include "math_funcs.h" -#include "vector2i.h" -#include - -struct IntRange2D { - int min_x; - int min_y; - int max_x; - int max_y; - - static inline IntRange2D from_min_max(godot::Vector2 min_pos, godot::Vector2 max_pos) { - return IntRange2D(godot::Rect2(min_pos, max_pos)); - } - - static inline IntRange2D from_pos_size(godot::Vector2 min_pos, godot::Vector2 size) { - return IntRange2D(godot::Rect2(min_pos, size)); - } - - IntRange2D(godot::Rect2 rect) { - min_x = static_cast(rect.position.x); - min_y = static_cast(rect.position.y); - max_x = static_cast(rect.position.x + rect.size.x); - max_y = static_cast(rect.position.y + rect.size.y); - } - - inline bool is_inside(Vector2i size) const { - return min_x >= size.x && - min_y >= size.y && - max_x <= size.x && - max_y <= size.y; - } - - inline void clip(Vector2i size) { - min_x = Math::clamp(min_x, 0, size.x); - min_y = Math::clamp(min_y, 0, size.y); - max_x = Math::clamp(max_x, 0, size.x); - max_y = Math::clamp(max_y, 0, size.y); - } - - inline void pad(int p) { - min_x -= p; - min_y -= p; - max_x += p; - max_y += p; - } - - inline int get_width() const { - return max_x - min_x; - } - - inline int get_height() const { - return max_y - min_y; - } -}; - -#endif // INT_RANGE_2D_H diff --git a/addons/zylann.hterrain/native/src/math_funcs.h b/addons/zylann.hterrain/native/src/math_funcs.h deleted file mode 100644 index 34c9071..0000000 --- a/addons/zylann.hterrain/native/src/math_funcs.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MATH_FUNCS_H -#define MATH_FUNCS_H - -namespace Math { - -inline float lerp(float minv, float maxv, float t) { - return minv + t * (maxv - minv); -} - -template -inline T clamp(T x, T minv, T maxv) { - if (x < minv) { - return minv; - } - if (x > maxv) { - return maxv; - } - return x; -} - -template -inline T min(T a, T b) { - return a < b ? a : b; -} - -} // namespace Math - -#endif // MATH_FUNCS_H diff --git a/addons/zylann.hterrain/native/src/quad_tree_lod.cpp b/addons/zylann.hterrain/native/src/quad_tree_lod.cpp deleted file mode 100644 index 592375e..0000000 --- a/addons/zylann.hterrain/native/src/quad_tree_lod.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "quad_tree_lod.h" - -namespace godot { - -void QuadTreeLod::set_callbacks(Ref make_cb, Ref recycle_cb, Ref vbounds_cb) { - _make_func = make_cb; - _recycle_func = recycle_cb; - _vertical_bounds_func = vbounds_cb; -} - -int QuadTreeLod::get_lod_count() { - // TODO make this a count, not max - return _max_depth + 1; -} - -int QuadTreeLod::get_lod_factor(int lod) { - return 1 << lod; -} - -int QuadTreeLod::compute_lod_count(int base_size, int full_size) { - int po = 0; - while (full_size > base_size) { - full_size = full_size >> 1; - po += 1; - } - return po; -} - -// The higher, the longer LODs will spread and higher the quality. -// The lower, the shorter LODs will spread and lower the quality. -void QuadTreeLod::set_split_scale(real_t p_split_scale) { - real_t MIN = 2.0f; - real_t MAX = 5.0f; - - // Split scale must be greater than a threshold, - // otherwise lods will decimate too fast and it will look messy - if (p_split_scale < MIN) - p_split_scale = MIN; - if (p_split_scale > MAX) - p_split_scale = MAX; - - _split_scale = p_split_scale; -} - -real_t QuadTreeLod::get_split_scale() { - return _split_scale; -} - -void QuadTreeLod::clear() { - _join_all_recursively(ROOT, _max_depth); - _max_depth = 0; - _base_size = 0; -} - -void QuadTreeLod::create_from_sizes(int base_size, int full_size) { - clear(); - _base_size = base_size; - _max_depth = compute_lod_count(base_size, full_size); - - // Total qty of nodes is (N^L - 1) / (N - 1). -1 for root, where N=num children, L=levels including the root - int node_count = ((static_cast(pow(4, _max_depth+1)) - 1) / (4 - 1)) - 1; - _node_pool.resize(node_count); // e.g. ((4^6 -1) / 3 ) - 1 = 1364 excluding root - - _free_indices.resize((node_count / 4)); // 1364 / 4 = 341 - for (int i = 0; i < _free_indices.size(); i++) // i = 0 to 340, *4 = 0 to 1360 - _free_indices[i] = 4 * i; // _node_pool[4*0 + i0] is first child, [4*340 + i3] is last -} - -void QuadTreeLod::update(Vector3 view_pos) { - _update(ROOT, _max_depth, view_pos); - - // This makes sure we keep seeing the lowest LOD, - // if the tree is cleared while we are far away - Quad *root = _get_root(); - if (!root->has_children() && root->is_null()) - root->set_data(_make_chunk(_max_depth, 0, 0)); -} - -void QuadTreeLod::debug_draw_tree(CanvasItem *ci) { - if (ci != nullptr) - _debug_draw_tree_recursive(ci, ROOT, _max_depth, 0); -} - -// Intention is to only clear references to children -void QuadTreeLod::_clear_children(unsigned int index) { - Quad *quad = _get_node(index); - if (quad->has_children()) { - _recycle_children(quad->first_child); - quad->first_child = NO_CHILDREN; - } -} - -// Returns the index of the first_child. Allocates from _free_indices. -unsigned int QuadTreeLod::_allocate_children() { - if (_free_indices.size() == 0) { - return NO_CHILDREN; - } - - unsigned int i0 = _free_indices[_free_indices.size() - 1]; - _free_indices.pop_back(); - return i0; -} - -// Pass the first_child index, not the parent index. Stores back in _free_indices. -void QuadTreeLod::_recycle_children(unsigned int i0) { - // Debug check, there is no use case in recycling a node which is not a first child - CRASH_COND(i0 % 4 != 0); - - for (int i = 0; i < 4; ++i) { - _node_pool[i0 + i].init(); - } - - _free_indices.push_back(i0); -} - -Variant QuadTreeLod::_make_chunk(int lod, int origin_x, int origin_y) { - if (_make_func.is_valid()) { - return _make_func->call_func(origin_x, origin_y, lod); - } else { - return Variant(); - } -} - -void QuadTreeLod::_recycle_chunk(unsigned int quad_index, int lod) { - Quad *quad = _get_node(quad_index); - if (_recycle_func.is_valid()) { - _recycle_func->call_func(quad->get_data(), quad->origin_x, quad->origin_y, lod); - } -} - -void QuadTreeLod::_join_all_recursively(unsigned int quad_index, int lod) { - Quad *quad = _get_node(quad_index); - - if (quad->has_children()) { - for (int i = 0; i < 4; i++) { - _join_all_recursively(quad->first_child + i, lod - 1); - } - _clear_children(quad_index); - - } else if (quad->is_valid()) { - _recycle_chunk(quad_index, lod); - quad->clear_data(); - } -} - -void QuadTreeLod::_update(unsigned int quad_index, int lod, Vector3 view_pos) { - // This function should be called regularly over frames. - Quad *quad = _get_node(quad_index); - int lod_factor = get_lod_factor(lod); - int chunk_size = _base_size * lod_factor; - Vector3 world_center = static_cast(chunk_size) * (Vector3(static_cast(quad->origin_x), 0.f, static_cast(quad->origin_y)) + Vector3(0.5f, 0.f, 0.5f)); - - if (_vertical_bounds_func.is_valid()) { - Variant result = _vertical_bounds_func->call_func(quad->origin_x, quad->origin_y, lod); - ERR_FAIL_COND(result.get_type() != Variant::VECTOR2); - Vector2 vbounds = static_cast(result); - world_center.y = (vbounds.x + vbounds.y) / 2.0f; - } - - int split_distance = _base_size * lod_factor * static_cast(_split_scale); - - if (!quad->has_children()) { - if (lod > 0 && world_center.distance_to(view_pos) < split_distance) { - // Split - unsigned int new_idx = _allocate_children(); - ERR_FAIL_COND(new_idx == NO_CHILDREN); - quad->first_child = new_idx; - - for (int i = 0; i < 4; i++) { - Quad *child = _get_node(quad->first_child + i); - child->origin_x = quad->origin_x * 2 + (i & 1); - child->origin_y = quad->origin_y * 2 + ((i & 2) >> 1); - child->set_data(_make_chunk(lod - 1, child->origin_x, child->origin_y)); - // If the quad needs to split more, we'll ask more recycling... - } - - if (quad->is_valid()) { - _recycle_chunk(quad_index, lod); - quad->clear_data(); - } - } - } else { - bool no_split_child = true; - - for (int i = 0; i < 4; i++) { - _update(quad->first_child + i, lod - 1, view_pos); - - if (_get_node(quad->first_child + i)->has_children()) - no_split_child = false; - } - - if (no_split_child && world_center.distance_to(view_pos) > split_distance) { - // Join - for (int i = 0; i < 4; i++) { - _recycle_chunk(quad->first_child + i, lod - 1); - } - _clear_children(quad_index); - quad->set_data(_make_chunk(lod, quad->origin_x, quad->origin_y)); - } - } -} // _update - -void QuadTreeLod::_debug_draw_tree_recursive(CanvasItem *ci, unsigned int quad_index, int lod_index, int child_index) { - Quad *quad = _get_node(quad_index); - - if (quad->has_children()) { - int ch_index = quad->first_child; - for (int i = 0; i < 4; i++) { - _debug_draw_tree_recursive(ci, ch_index + i, lod_index - 1, i); - } - - } else { - real_t size = static_cast(get_lod_factor(lod_index)); - int checker = 0; - if (child_index == 1 || child_index == 2) - checker = 1; - - int chunk_indicator = 0; - if (quad->is_valid()) - chunk_indicator = 1; - - Rect2 rect2(Vector2(static_cast(quad->origin_x), static_cast(quad->origin_y)) * size, - Vector2(size, size)); - Color color(1.0f - static_cast(lod_index) * 0.2f, 0.2f * static_cast(checker), static_cast(chunk_indicator), 1.0f); - ci->draw_rect(rect2, color); - } -} - -void QuadTreeLod::_register_methods() { - register_method("set_callbacks", &QuadTreeLod::set_callbacks); - register_method("get_lod_count", &QuadTreeLod::get_lod_count); - register_method("get_lod_factor", &QuadTreeLod::get_lod_factor); - register_method("compute_lod_count", &QuadTreeLod::compute_lod_count); - register_method("set_split_scale", &QuadTreeLod::set_split_scale); - register_method("get_split_scale", &QuadTreeLod::get_split_scale); - register_method("clear", &QuadTreeLod::clear); - register_method("create_from_sizes", &QuadTreeLod::create_from_sizes); - register_method("update", &QuadTreeLod::update); - register_method("debug_draw_tree", &QuadTreeLod::debug_draw_tree); -} - -} // namespace godot diff --git a/addons/zylann.hterrain/native/src/quad_tree_lod.h b/addons/zylann.hterrain/native/src/quad_tree_lod.h deleted file mode 100644 index a4132ec..0000000 --- a/addons/zylann.hterrain/native/src/quad_tree_lod.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef QUAD_TREE_LOD_H -#define QUAD_TREE_LOD_H - -#include -#include -#include - -#include - -namespace godot { - -class QuadTreeLod : public Reference { - GODOT_CLASS(QuadTreeLod, Reference) -public: - static void _register_methods(); - - QuadTreeLod() {} - ~QuadTreeLod() {} - - void _init() {} - - void set_callbacks(Ref make_cb, Ref recycle_cb, Ref vbounds_cb); - int get_lod_count(); - int get_lod_factor(int lod); - int compute_lod_count(int base_size, int full_size); - void set_split_scale(real_t p_split_scale); - real_t get_split_scale(); - void clear(); - void create_from_sizes(int base_size, int full_size); - void update(Vector3 view_pos); - void debug_draw_tree(CanvasItem *ci); - -private: - static const unsigned int NO_CHILDREN = -1; - static const unsigned int ROOT = -1; - - class Quad { - public: - unsigned int first_child = NO_CHILDREN; - int origin_x = 0; - int origin_y = 0; - - Quad() { - init(); - } - - ~Quad() { - } - - inline void init() { - first_child = NO_CHILDREN; - origin_x = 0; - origin_y = 0; - clear_data(); - } - - inline void clear_data() { - _data = Variant(); - } - - inline bool has_children() { - return first_child != NO_CHILDREN; - } - - inline bool is_null() { - return _data.get_type() == Variant::NIL; - } - - inline bool is_valid() { - return _data.get_type() != Variant::NIL; - } - - inline Variant get_data() { - return _data; - } - - inline void set_data(Variant p_data) { - _data = p_data; - } - - private: - Variant _data; // Type is HTerrainChunk.gd : Object - }; - - Quad _root; - std::vector _node_pool; - std::vector _free_indices; - - int _max_depth = 0; - int _base_size = 16; - real_t _split_scale = 2.0f; - - Ref _make_func; - Ref _recycle_func; - Ref _vertical_bounds_func; - - inline Quad *_get_root() { - return &_root; - } - - inline Quad *_get_node(unsigned int index) { - if (index == ROOT) { - return &_root; - } else { - return &_node_pool[index]; - } - } - - void _clear_children(unsigned int index); - unsigned int _allocate_children(); - void _recycle_children(unsigned int i0); - Variant _make_chunk(int lod, int origin_x, int origin_y); - void _recycle_chunk(unsigned int quad_index, int lod); - void _join_all_recursively(unsigned int quad_index, int lod); - void _update(unsigned int quad_index, int lod, Vector3 view_pos); - void _debug_draw_tree_recursive(CanvasItem *ci, unsigned int quad_index, int lod_index, int child_index); -}; // class QuadTreeLod - -} // namespace godot - -#endif // QUAD_TREE_LOD_H diff --git a/addons/zylann.hterrain/native/src/vector2i.h b/addons/zylann.hterrain/native/src/vector2i.h deleted file mode 100644 index 3eb60d6..0000000 --- a/addons/zylann.hterrain/native/src/vector2i.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef VECTOR2I_H -#define VECTOR2I_H - -#include - -struct Vector2i { - int x; - int y; - - Vector2i(godot::Vector2 v) : - x(static_cast(v.x)), - y(static_cast(v.y)) {} - - bool any_zero() const { - return x == 0 || y == 0; - } -}; - -#endif // VECTOR2I_H diff --git a/addons/zylann.hterrain/plugin.cfg b/addons/zylann.hterrain/plugin.cfg deleted file mode 100644 index 54ffba7..0000000 --- a/addons/zylann.hterrain/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="Heightmap Terrain" -description="Heightmap-based terrain" -author="Marc Gilleron" -version="1.7.2" -script="tools/plugin.gd" diff --git a/addons/zylann.hterrain/shaders/array.gdshader b/addons/zylann.hterrain/shaders/array.gdshader deleted file mode 100644 index fbbac13..0000000 --- a/addons/zylann.hterrain/shaders/array.gdshader +++ /dev/null @@ -1,170 +0,0 @@ -shader_type spatial; - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splat_index_map; -uniform sampler2D u_terrain_splat_weight_map; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; -uniform sampler2DArray u_ground_normal_roughness_array; - -// TODO Have UV scales for each texture in an array? -uniform float u_ground_uv_scale; -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; -uniform bool u_depth_blending = true; - -varying float v_hole; -varying vec3 v_tint; -varying vec2 v_ground_uv; -varying float v_distance_to_camera; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec3 get_depth_blended_weights(vec3 splat, vec3 bumps) { - float dh = 0.2; - - vec3 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec3 d = h + dh; - d.r -= max(h.g, h.b); - d.g -= max(h.r, h.b); - d.b -= max(h.g, h.r); - - vec3 w = clamp(d, 0, 1); - // Had to normalize, since this approach does not preserve components summing to 1 - return w / (w.x + w.y + w.z); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv = base_ground_uv.xz / u_ground_uv_scale; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint = tint.rgb; - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - float globalmap_factor = - clamp((v_distance_to_camera - u_globalmap_blend_start) * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 tex_splat_indexes = texture(u_terrain_splat_index_map, UV); - vec4 tex_splat_weights = texture(u_terrain_splat_weight_map, UV); - // TODO Can't use texelFetch! - // https://github.com/godotengine/godot/issues/31732 - - vec3 splat_indexes = tex_splat_indexes.rgb * 255.0; - vec3 splat_weights = vec3( - tex_splat_weights.r, - tex_splat_weights.g, - 1.0 - tex_splat_weights.r - tex_splat_weights.g - ); - - vec4 ab0 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv, splat_indexes.x)); - vec4 ab1 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv, splat_indexes.y)); - vec4 ab2 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv, splat_indexes.z)); - - vec4 nr0 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv, splat_indexes.x)); - vec4 nr1 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv, splat_indexes.y)); - vec4 nr2 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv, splat_indexes.z)); - - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - splat_weights = get_depth_blended_weights(splat_weights, vec3(ab0.a, ab1.a, ab2.a)); - } - - ALBEDO = v_tint * ( - ab0.rgb * splat_weights.x - + ab1.rgb * splat_weights.y - + ab2.rgb * splat_weights.z - ); - - ROUGHNESS = - nr0.a * splat_weights.x - + nr1.a * splat_weights.y - + nr2.a * splat_weights.z; - - vec3 normal0 = unpack_normal(nr0); - vec3 normal1 = unpack_normal(nr1); - vec3 normal2 = unpack_normal(nr2); - - vec3 ground_normal = - normal0 * splat_weights.x - + normal1 * splat_weights.y - + normal2 * splat_weights.z; - - // Combine terrain normals with detail normals (not sure if correct but looks ok) - normal = normalize(vec3( - terrain_normal_world.x + ground_normal.x, - terrain_normal_world.y, - terrain_normal_world.z + ground_normal.z)); - - normal = mix(normal, terrain_normal_world, globalmap_factor); - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - //ALBEDO = vec3(splat_weight0, splat_weight1, splat_weight2); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - } - - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; -} diff --git a/addons/zylann.hterrain/shaders/array_global.gdshader b/addons/zylann.hterrain/shaders/array_global.gdshader deleted file mode 100644 index b72dc53..0000000 --- a/addons/zylann.hterrain/shaders/array_global.gdshader +++ /dev/null @@ -1,87 +0,0 @@ -// This shader is used to bake the global albedo map. -// It exposes a subset of the main shader API, so uniform names were not modified. - -shader_type spatial; - -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splat_index_map; -uniform sampler2D u_terrain_splat_weight_map; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; - -// TODO Have UV scales for each texture in an array? -uniform float u_ground_uv_scale; -// Keep depth blending because it has a high effect on the final result -uniform bool u_depth_blending = true; - - -vec3 get_depth_blended_weights(vec3 splat, vec3 bumps) { - float dh = 0.2; - - vec3 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec3 d = h + dh; - d.r -= max(h.g, h.b); - d.g -= max(h.r, h.b); - d.b -= max(h.g, h.r); - - vec3 w = clamp(d, 0, 1); - // Had to normalize, since this approach does not preserve components summing to 1 - return w / (w.x + w.y + w.z); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = wpos.xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = (cell_coords / vec2(textureSize(u_terrain_splat_index_map, 0))); -} - -void fragment() { - vec4 tint = texture(u_terrain_colormap, UV); - vec4 tex_splat_indexes = texture(u_terrain_splat_index_map, UV); - vec4 tex_splat_weights = texture(u_terrain_splat_weight_map, UV); - // TODO Can't use texelFetch! - // https://github.com/godotengine/godot/issues/31732 - - vec3 splat_indexes = tex_splat_indexes.rgb * 255.0; - - // Get bump at normal resolution so depth blending is accurate - vec2 ground_uv = UV / u_ground_uv_scale; - float b0 = texture(u_ground_albedo_bump_array, vec3(ground_uv, splat_indexes.x)).a; - float b1 = texture(u_ground_albedo_bump_array, vec3(ground_uv, splat_indexes.y)).a; - float b2 = texture(u_ground_albedo_bump_array, vec3(ground_uv, splat_indexes.z)).a; - - // Take the center of the highest mip as color, because we can't see details from far away. - vec2 ndc_center = vec2(0.5, 0.5); - vec3 a0 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, splat_indexes.x), 10.0).rgb; - vec3 a1 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, splat_indexes.y), 10.0).rgb; - vec3 a2 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, splat_indexes.z), 10.0).rgb; - - vec3 splat_weights = vec3( - tex_splat_weights.r, - tex_splat_weights.g, - 1.0 - tex_splat_weights.r - tex_splat_weights.g - ); - - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - splat_weights = get_depth_blended_weights(splat_weights, vec3(b0, b1, b2)); - } - - ALBEDO = tint.rgb * ( - a0 * splat_weights.x - + a1 * splat_weights.y - + a2 * splat_weights.z - ); -} diff --git a/addons/zylann.hterrain/shaders/detail.gdshader b/addons/zylann.hterrain/shaders/detail.gdshader deleted file mode 100644 index dbd1422..0000000 --- a/addons/zylann.hterrain/shaders/detail.gdshader +++ /dev/null @@ -1,107 +0,0 @@ -shader_type spatial; -render_mode cull_disabled; - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_detailmap; -uniform sampler2D u_terrain_normalmap; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2D u_albedo_alpha : source_color; -uniform float u_view_distance = 100.0; -uniform float u_globalmap_tint_bottom : hint_range(0.0, 1.0); -uniform float u_globalmap_tint_top : hint_range(0.0, 1.0); -uniform float u_bottom_ao : hint_range(0.0, 1.0); -uniform vec2 u_ambient_wind; // x: amplitude, y: time -uniform vec3 u_instance_scale = vec3(1.0, 1.0, 1.0); -uniform float u_roughness = 0.9; - -varying vec3 v_normal; -varying vec2 v_map_uv; - -float get_hash(vec2 c) { - return fract(sin(dot(c.xy, vec2(12.9898,78.233))) * 43758.5453); -} - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - n.z *= -1.0; - return n; -} - -vec3 get_ambient_wind_displacement(vec2 uv, float hash) { - // TODO This is an initial basic implementation. It may be improved in the future, especially for strong wind. - float t = u_ambient_wind.y; - float amp = u_ambient_wind.x * (1.0 - uv.y); - // Main displacement - vec3 disp = amp * vec3(cos(t), 0, sin(t * 1.2)); - // Fine displacement - float fine_disp_frequency = 2.0; - disp += 0.2 * amp * vec3(cos(t * (fine_disp_frequency + hash)), 0, sin(t * (fine_disp_frequency + hash) * 1.2)); - return disp; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -void vertex() { - vec4 obj_pos = MODEL_MATRIX * vec4(0, 1, 0, 1); - vec3 cell_coords = (u_terrain_inverse_transform * obj_pos).xyz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords.xz += vec2(0.5); - - vec2 map_uv = cell_coords.xz / vec2(textureSize(u_terrain_heightmap, 0)); - v_map_uv = map_uv; - - //float density = 0.5 + 0.5 * sin(4.0*TIME); // test - float density = texture(u_terrain_detailmap, map_uv).r; - float hash = get_hash(obj_pos.xz); - - if (density > hash) { - vec3 normal = normalize( - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, map_uv))); - - // Snap model to the terrain - float height = get_height(u_terrain_heightmap, map_uv) / cell_coords.y; - VERTEX *= u_instance_scale; - VERTEX.y += height; - - VERTEX += get_ambient_wind_displacement(UV, hash); - - // Fade alpha with distance - vec3 wpos = (MODEL_MATRIX * vec4(VERTEX, 1)).xyz; - float dr = distance(wpos, CAMERA_POSITION_WORLD) / u_view_distance; - COLOR.a = clamp(1.0 - dr * dr * dr, 0.0, 1.0); - - // When using billboards, - // the normal is the same as the terrain regardless of face orientation - v_normal = normal; - - } else { - // Discard, output degenerate triangles - VERTEX = vec3(0, 0, 0); - } -} - -void fragment() { - NORMAL = (VIEW_MATRIX * (MODEL_MATRIX * vec4(v_normal, 0.0))).xyz; - ALPHA_SCISSOR_THRESHOLD = 0.5; - ROUGHNESS = u_roughness; - - vec4 col = texture(u_albedo_alpha, UV); - ALPHA = col.a * COLOR.a;// - clamp(1.4 - UV.y, 0.0, 1.0);//* 0.5 + 0.5*cos(2.0*TIME); - - ALBEDO = COLOR.rgb * col.rgb; - - // Blend with ground color - float nh = sqrt(max(1.0 - UV.y, 0.0)); - ALBEDO = mix(ALBEDO, texture(u_terrain_globalmap, v_map_uv).rgb, mix(u_globalmap_tint_bottom, u_globalmap_tint_top, nh)); - - // Fake bottom AO - ALBEDO = ALBEDO * mix(1.0, 1.0 - u_bottom_ao, UV.y * UV.y); -} diff --git a/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc b/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc deleted file mode 100644 index c023e52..0000000 --- a/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc +++ /dev/null @@ -1,66 +0,0 @@ - -// Use functions from this file everywhere a heightmap is used, -// so it is easy to track and change the format - -float sample_heightmap(sampler2D spl, vec2 pos) { - // RF - return texture(spl, pos).r; -} - -vec4 encode_height_to_viewport(float h) { - //return vec4(encode_height_to_rgb8_unorm(h), 1.0); - - // Encode regular floats into an assumed RGBA8 output color. - // This is used because Godot 4.0 doesn't support RF viewports, - // and the irony is, even if float viewports get supported, it's likely it will end up RGBAF, - // which is wasting bandwidth because we are only interested in R... - uint u = floatBitsToUint(h); - return vec4( - float((u >> 0u) & 255u), - float((u >> 8u) & 255u), - float((u >> 16u) & 255u), - float((u >> 24u) & 255u) - ) / vec4(255.0); -} - -float decode_height_from_viewport(vec4 c) { - uint u = uint(c.r * 255.0) - | (uint(c.g * 255.0) << 8u) - | (uint(c.b * 255.0) << 16u) - | (uint(c.a * 255.0) << 24u); - return uintBitsToFloat(u); -} - -float sample_height_from_viewport(sampler2D screen, vec2 uv) { - ivec2 ts = textureSize(screen, 0); - vec2 norm_to_px = vec2(ts); - - // Convert to pixels and apply a small offset so we interpolate from pixel centers - vec2 uv_px_f = uv * norm_to_px - vec2(0.5); - - ivec2 uv_px = ivec2(uv_px_f); - - // Get interpolation pixel positions - ivec2 p00 = uv_px; - ivec2 p10 = uv_px + ivec2(1, 0); - ivec2 p01 = uv_px + ivec2(0, 1); - ivec2 p11 = uv_px + ivec2(1, 1); - - // Get pixels - vec4 c00 = texelFetch(screen, p00, 0); - vec4 c10 = texelFetch(screen, p10, 0); - vec4 c01 = texelFetch(screen, p01, 0); - vec4 c11 = texelFetch(screen, p11, 0); - - // Decode heights - float h00 = decode_height_from_viewport(c00); - float h10 = decode_height_from_viewport(c10); - float h01 = decode_height_from_viewport(c01); - float h11 = decode_height_from_viewport(c11); - - // Linear filter - vec2 f = fract(uv_px_f); - float h = mix(mix(h00, h10, f.x), mix(h01, h11, f.x), f.y); - - return h; -} diff --git a/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc b/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc deleted file mode 100644 index bb30ebe..0000000 --- a/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc +++ /dev/null @@ -1,57 +0,0 @@ - -const float V2_UNIT_STEPS = 1024.0; -const float V2_MIN = -8192.0; -const float V2_MAX = 8191.0; -const float V2_DF = 255.0 / V2_UNIT_STEPS; - -float decode_height_from_rgb8_unorm_2(vec3 c) { - return (c.r * 0.25 + c.g * 64.0 + c.b * 16384.0) * (4.0 * V2_DF) + V2_MIN; -} - -vec3 encode_height_to_rgb8_unorm_2(float h) { - // TODO Check if this has float precision issues - // TODO Modulo operator might be a performance/compatibility issue - h -= V2_MIN; - int i = int(h * V2_UNIT_STEPS); - int r = i % 256; - int g = (i / 256) % 256; - int b = i / 65536; - return vec3(float(r), float(g), float(b)) / 255.0; -} - -float decode_height_from_rgb8_unorm(vec3 c) { - return decode_height_from_rgb8_unorm_2(c); -} - -vec3 encode_height_to_rgb8_unorm(float h) { - return encode_height_to_rgb8_unorm_2(h); -} - -// TODO Remove for now? -// Bilinear filtering appears to work well enough without doing this. -// There are some artifacts, but we could easily live with them, -// and I suspect they could be easy to patch somehow in the encoding/decoding. -// -// In case bilinear filtering is required. -// This is slower than if we had a native float format. -// Unfortunately, Godot 4 removed support for 2D HDR viewports. They were used -// to edit this format natively. Using compute shaders would force users to -// have Vulkan. So we had to downgrade performance a bit using a technique from the GLES2 era... -float sample_height_bilinear_rgb8_unorm(sampler2D heightmap, vec2 uv) { - vec2 ts = vec2(textureSize(heightmap, 0)); - vec2 p00f = uv * ts; - ivec2 p00 = ivec2(p00f); - - vec3 s00 = texelFetch(heightmap, p00, 0).rgb; - vec3 s10 = texelFetch(heightmap, p00 + ivec2(1, 0), 0).rgb; - vec3 s01 = texelFetch(heightmap, p00 + ivec2(0, 1), 0).rgb; - vec3 s11 = texelFetch(heightmap, p00 + ivec2(1, 1), 0).rgb; - - float h00 = decode_height_from_rgb8_unorm(s00); - float h10 = decode_height_from_rgb8_unorm(s10); - float h01 = decode_height_from_rgb8_unorm(s01); - float h11 = decode_height_from_rgb8_unorm(s11); - - vec2 f = p00f - vec2(p00); - return mix(mix(h00, h10, f.x), mix(h01, h11, f.x), f.y); -} diff --git a/addons/zylann.hterrain/shaders/lookdev.gdshader b/addons/zylann.hterrain/shaders/lookdev.gdshader deleted file mode 100644 index fede393..0000000 --- a/addons/zylann.hterrain/shaders/lookdev.gdshader +++ /dev/null @@ -1,71 +0,0 @@ -shader_type spatial; - -// Development shader used to debug or help authoring. - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_map; // This map will control color -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -varying float v_hole; - - -vec3 unpack_normal(vec4 rgba) { - // If we consider texture space starts from top-left corner and Y goes down, - // then Y+ in pixel space corresponds to Z+ in terrain space, - // while X+ also corresponds to X+ in terrain space. - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); -} - -void fragment() { - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - vec4 value = texture(u_map, UV); - // TODO Blend toward checker pattern to show the alpha channel - - ALBEDO = value.rgb; - ROUGHNESS = 0.5; - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; -} diff --git a/addons/zylann.hterrain/shaders/low_poly.gdshader b/addons/zylann.hterrain/shaders/low_poly.gdshader deleted file mode 100644 index 6c98104..0000000 --- a/addons/zylann.hterrain/shaders/low_poly.gdshader +++ /dev/null @@ -1,63 +0,0 @@ -shader_type spatial; - -// This is a very simple shader for a low-poly coloured visual, without textures - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap;// : hint_albedo; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -varying flat vec4 v_tint; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -void vertex() { - vec2 cell_coords = (u_terrain_inverse_transform * MODEL_MATRIX * vec4(VERTEX, 1)).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - v_tint = texture(u_terrain_colormap, UV); - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); -} - -void fragment() { - if (v_tint.a < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - - ALBEDO = v_tint.rgb; - ROUGHNESS = 1.0; - NORMAL = normalize(cross(dFdy(VERTEX), dFdx(VERTEX))); -} - diff --git a/addons/zylann.hterrain/shaders/multisplat16.gdshader b/addons/zylann.hterrain/shaders/multisplat16.gdshader deleted file mode 100644 index 6e08052..0000000 --- a/addons/zylann.hterrain/shaders/multisplat16.gdshader +++ /dev/null @@ -1,373 +0,0 @@ -shader_type spatial; - -// WIP -// This shader uses a texture array with multiple splatmaps, allowing up to 16 textures. -// Only the 4 textures having highest blending weight are sampled. - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_splatmap_1; -uniform sampler2D u_terrain_splatmap_2; -uniform sampler2D u_terrain_splatmap_3; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; -uniform sampler2DArray u_ground_normal_roughness_array; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; -uniform bool u_tile_reduction = false; - -varying float v_hole; -varying vec3 v_tint; -varying vec2 v_terrain_uv; -varying vec3 v_ground_uv; -varying float v_distance_to_camera; - -// TODO Can't put this in a constant: https://github.com/godotengine/godot/issues/44145 -//const int TEXTURE_COUNT = 16; - - -vec3 unpack_normal(vec4 rgba) { - // If we consider texture space starts from top-left corner and Y goes down, - // then Y+ in pixel space corresponds to Z+ in terrain space, - // while X+ also corresponds to X+ in terrain space. - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec4 pack_normal(vec3 n, float a) { - n.z *= -1.0; - return vec4((n.xzy + vec3(1.0)) * 0.5, a); -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -void get_splat_weights(vec2 uv, out vec4 out_high_indices, out vec4 out_high_weights) { - vec4 ew0 = texture(u_terrain_splatmap, uv); - vec4 ew1 = texture(u_terrain_splatmap_1, uv); - vec4 ew2 = texture(u_terrain_splatmap_2, uv); - vec4 ew3 = texture(u_terrain_splatmap_3, uv); - - float weights[16] = { - ew0.r, ew0.g, ew0.b, ew0.a, - ew1.r, ew1.g, ew1.b, ew1.a, - ew2.r, ew2.g, ew2.b, ew2.a, - ew3.r, ew3.g, ew3.b, ew3.a - }; - -// float weights_sum = 0.0; -// for (int i = 0; i < 16; ++i) { -// weights_sum += weights[i]; -// } -// for (int i = 0; i < 16; ++i) { -// weights_sum /= weights_sum; -// } -// weights_sum=1.1; - - // Now we have to pick the 4 highest weights and use them to blend textures. - - // Using arrays because Godot's shader version doesn't support dynamic indexing of vectors - // TODO We should not need to initialize, but apparently we don't always find 4 weights - int high_indices_array[4] = {0, 0, 0, 0}; - float high_weights_array[4] = {0.0, 0.0, 0.0, 0.0}; - int count = 0; - // We know weights are supposed to be normalized. - // That means the highest value of the pivot above which we can find 4 results - // is 1.0 / 4.0. However that would mean exactly 4 textures have exactly that weight, - // which is very unlikely. If we consider 1.0 / 5.0, we are a bit more likely to find - // 4 results, and finding 5 results remains almost impossible. - float pivot = /*weights_sum*/1.0 / 5.0; - - for (int i = 0; i < 16; ++i) { - if (weights[i] > pivot) { - high_weights_array[count] = weights[i]; - high_indices_array[count] = i; - weights[i] = 0.0; - ++count; - } - } - - while (count < 4 && pivot > 0.0) { - float max_weight = 0.0; - int max_index = 0; - - for (int i = 0; i < 16; ++i) { - if (/*weights[i] <= pivot && */weights[i] > max_weight) { - max_weight = weights[i]; - max_index = i; - weights[i] = 0.0; - } - } - - high_indices_array[count] = max_index; - high_weights_array[count] = max_weight; - ++count; - pivot = max_weight; - } - - out_high_weights = vec4( - high_weights_array[0], high_weights_array[1], - high_weights_array[2], high_weights_array[3]); - - out_high_indices = vec4( - float(high_indices_array[0]), float(high_indices_array[1]), - float(high_indices_array[2]), float(high_indices_array[3])); - - out_high_weights /= - out_high_weights.r + out_high_weights.g + out_high_weights.b + out_high_weights.a; -} - -vec4 depth_blend2(vec4 a_value, float a_bump, vec4 b_value, float b_bump, float t) { - // https://www.gamasutra.com - // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php - float d = 0.1; - float ma = max(a_bump + (1.0 - t), b_bump + t) - d; - float ba = max(a_bump + (1.0 - t) - ma, 0.0); - float bb = max(b_bump + t - ma, 0.0); - return (a_value * ba + b_value * bb) / (ba + bb); -} - -vec2 rotate(vec2 v, float cosa, float sina) { - return vec2(cosa * v.x - sina * v.y, sina * v.x + cosa * v.y); -} - -vec4 texture_array_antitile(sampler2DArray albedo_tex, sampler2DArray normal_tex, vec3 uv, - out vec4 out_normal) { - - float frequency = 2.0; - float scale = 1.3; - float sharpness = 0.7; - - // Rotate and scale UV - float rot = 3.14 * 0.6; - float cosa = cos(rot); - float sina = sin(rot); - vec3 uv2 = vec3(rotate(uv.xy, cosa, sina) * scale, uv.z); - - vec4 col0 = texture(albedo_tex, uv); - vec4 col1 = texture(albedo_tex, uv2); - vec4 nrm0 = texture(normal_tex, uv); - vec4 nrm1 = texture(normal_tex, uv2); - //col0 = vec4(0.0, 0.5, 0.5, 1.0); // Highlights variations - - // Normals have to be rotated too since we are rotating the texture... - // TODO Probably not the most efficient but understandable for now - vec3 n = unpack_normal(nrm1); - // Had to negate the Y axis for some reason. I never remember the myriad of conventions around - n.xz = rotate(n.xz, cosa, -sina); - nrm1 = pack_normal(n, nrm1.a); - - // Periodically alternate between the two versions using a warped checker pattern - float t = 1.1 + 0.5 - * sin(uv2.x * frequency + sin(uv.x) * 2.0) - * cos(uv2.y * frequency + sin(uv.y) * 2.0); // Result in [0..2] - t = smoothstep(sharpness, 2.0 - sharpness, t); - - // Using depth blend because classic alpha blending smoothes out details. - out_normal = depth_blend2(nrm0, col0.a, nrm1, col1.a, t); - return depth_blend2(col0, col0.a, col1, col1.a, t); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv = base_ground_uv / u_ground_uv_scale; - - // Putting this in vertex saves a fetch from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate it, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint = tint.rgb; - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * (unpack_normal(texture(u_terrain_normalmap, UV))); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - float globalmap_factor = clamp((v_distance_to_camera - u_globalmap_blend_start) - * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 high_indices; - vec4 high_weights; - get_splat_weights(UV, high_indices, high_weights); - - vec4 ab0, ab1, ab2, ab3; - vec4 nr0, nr1, nr2, nr3; - - if (u_tile_reduction) { - ab0 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.x), nr0); - ab1 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.y), nr1); - ab2 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.z), nr2); - ab3 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.w), nr3); - - } else { - ab0 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.x)); - ab1 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.y)); - ab2 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.z)); - ab3 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.w)); - - nr0 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.x)); - nr1 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.y)); - nr2 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.z)); - nr3 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.w)); - } - - vec3 col0 = ab0.rgb * v_tint; - vec3 col1 = ab1.rgb * v_tint; - vec3 col2 = ab2.rgb * v_tint; - vec3 col3 = ab3.rgb * v_tint; - - vec4 rough = vec4(nr0.a, nr1.a, nr2.a, nr3.a); - - vec3 normal0 = unpack_normal(nr0); - vec3 normal1 = unpack_normal(nr1); - vec3 normal2 = unpack_normal(nr2); - vec3 normal3 = unpack_normal(nr3); - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(high_weights, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = high_weights; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ROUGHNESS = ( - w.r * rough.r + - w.g * rough.g + - w.b * rough.b + - w.a * rough.a) / w_sum; - - vec3 ground_normal = /*u_terrain_normal_basis **/ ( - w.r * normal0 + - w.g * normal1 + - w.b * normal2 + - w.a * normal3) / w_sum; - // If no splat textures are defined, normal vectors will default to (1,1,1), - // which is incorrect, and causes the terrain to be shaded wrongly in some directions. - // However, this should not be a problem to fix in the shader, - // because there MUST be at least one splat texture set. - //ground_normal = normalize(ground_normal); - // TODO Make the plugin insert a default normalmap if it's empty - - // Combine terrain normals with detail normals (not sure if correct but looks ok) - normal = normalize(vec3( - terrain_normal_world.x + ground_normal.x, - terrain_normal_world.y, - terrain_normal_world.z + ground_normal.z)); - - normal = mix(normal, terrain_normal_world, globalmap_factor); - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - -// if(count < 3) { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - // Show splatmap weights - //ALBEDO = w.rgb; - } - // Highlight all pixels undergoing no splatmap at all -// else { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; -} diff --git a/addons/zylann.hterrain/shaders/multisplat16_global.gdshader b/addons/zylann.hterrain/shaders/multisplat16_global.gdshader deleted file mode 100644 index dbe60c5..0000000 --- a/addons/zylann.hterrain/shaders/multisplat16_global.gdshader +++ /dev/null @@ -1,173 +0,0 @@ -shader_type spatial; - -// This shader uses a texture array with multiple splatmaps, allowing up to 16 textures. -// Only the 4 textures having highest blending weight are sampled. - -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_splatmap_1; -uniform sampler2D u_terrain_splatmap_2; -uniform sampler2D u_terrain_splatmap_3; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; - -// TODO Can't put this in a constant: https://github.com/godotengine/godot/issues/44145 -//const int TEXTURE_COUNT = 16; - - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -void get_splat_weights(vec2 uv, out vec4 out_high_indices, out vec4 out_high_weights) { - vec4 ew0 = texture(u_terrain_splatmap, uv); - vec4 ew1 = texture(u_terrain_splatmap_1, uv); - vec4 ew2 = texture(u_terrain_splatmap_2, uv); - vec4 ew3 = texture(u_terrain_splatmap_3, uv); - - float weights[16] = { - ew0.r, ew0.g, ew0.b, ew0.a, - ew1.r, ew1.g, ew1.b, ew1.a, - ew2.r, ew2.g, ew2.b, ew2.a, - ew3.r, ew3.g, ew3.b, ew3.a - }; - -// float weights_sum = 0.0; -// for (int i = 0; i < 16; ++i) { -// weights_sum += weights[i]; -// } -// for (int i = 0; i < 16; ++i) { -// weights_sum /= weights_sum; -// } -// weights_sum=1.1; - - // Now we have to pick the 4 highest weights and use them to blend textures. - - // Using arrays because Godot's shader version doesn't support dynamic indexing of vectors - // TODO We should not need to initialize, but apparently we don't always find 4 weights - int high_indices_array[4] = {0, 0, 0, 0}; - float high_weights_array[4] = {0.0, 0.0, 0.0, 0.0}; - int count = 0; - // We know weights are supposed to be normalized. - // That means the highest value of the pivot above which we can find 4 results - // is 1.0 / 4.0. However that would mean exactly 4 textures have exactly that weight, - // which is very unlikely. If we consider 1.0 / 5.0, we are a bit more likely to find - // 4 results, and finding 5 results remains almost impossible. - float pivot = /*weights_sum*/1.0 / 5.0; - - for (int i = 0; i < 16; ++i) { - if (weights[i] > pivot) { - high_weights_array[count] = weights[i]; - high_indices_array[count] = i; - weights[i] = 0.0; - ++count; - } - } - - while (count < 4 && pivot > 0.0) { - float max_weight = 0.0; - int max_index = 0; - - for (int i = 0; i < 16; ++i) { - if (/*weights[i] <= pivot && */weights[i] > max_weight) { - max_weight = weights[i]; - max_index = i; - weights[i] = 0.0; - } - } - - high_indices_array[count] = max_index; - high_weights_array[count] = max_weight; - ++count; - pivot = max_weight; - } - - out_high_weights = vec4( - high_weights_array[0], high_weights_array[1], - high_weights_array[2], high_weights_array[3]); - - out_high_indices = vec4( - float(high_indices_array[0]), float(high_indices_array[1]), - float(high_indices_array[2]), float(high_indices_array[3])); - - out_high_weights /= - out_high_weights.r + out_high_weights.g + out_high_weights.b + out_high_weights.a; -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = wpos.xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_splatmap, 0)); -} - -void fragment() { - // These were moved from vertex to fragment, - // so we can generate part of the global map with just one quad and we get full quality - vec3 tint = texture(u_terrain_colormap, UV).rgb; - vec4 splat = texture(u_terrain_splatmap, UV); - - vec4 high_indices; - vec4 high_weights; - get_splat_weights(UV, high_indices, high_weights); - - // Get bump at normal resolution so depth blending is accurate - vec2 ground_uv = UV / u_ground_uv_scale; - float b0 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.x)).a; - float b1 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.y)).a; - float b2 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.z)).a; - float b3 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.w)).a; - - // Take the center of the highest mip as color, because we can't see details from far away. - vec2 ndc_center = vec2(0.5, 0.5); - vec3 a0 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.x), 10.0).rgb; - vec3 a1 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.y), 10.0).rgb; - vec3 a2 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.z), 10.0).rgb; - vec3 a3 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.w), 10.0).rgb; - - vec3 col0 = a0 * tint; - vec3 col1 = a1 * tint; - vec3 col2 = a2 * tint; - vec3 col3 = a3 * tint; - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(high_weights, vec4(b0, b1, b2, b3)); - } else { - w = high_weights; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; -} diff --git a/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader b/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader deleted file mode 100644 index b667496..0000000 --- a/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader +++ /dev/null @@ -1,254 +0,0 @@ -shader_type spatial; - -// WIP -// This shader uses a texture array with multiple splatmaps, allowing up to 16 textures. -// Only the 4 textures having highest blending weight are sampled. - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_splatmap_1; -uniform sampler2D u_terrain_splatmap_2; -uniform sampler2D u_terrain_splatmap_3; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; - -varying float v_hole; -varying vec3 v_tint; -varying vec2 v_terrain_uv; -varying vec3 v_ground_uv; -varying float v_distance_to_camera; - -// TODO Can't put this in a constant: https://github.com/godotengine/godot/issues/44145 -//const int TEXTURE_COUNT = 16; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -void get_splat_weights(vec2 uv, out vec4 out_high_indices, out vec4 out_high_weights) { - vec4 ew0 = texture(u_terrain_splatmap, uv); - vec4 ew1 = texture(u_terrain_splatmap_1, uv); - vec4 ew2 = texture(u_terrain_splatmap_2, uv); - vec4 ew3 = texture(u_terrain_splatmap_3, uv); - - float weights[16] = { - ew0.r, ew0.g, ew0.b, ew0.a, - ew1.r, ew1.g, ew1.b, ew1.a, - ew2.r, ew2.g, ew2.b, ew2.a, - ew3.r, ew3.g, ew3.b, ew3.a - }; - -// float weights_sum = 0.0; -// for (int i = 0; i < 16; ++i) { -// weights_sum += weights[i]; -// } -// for (int i = 0; i < 16; ++i) { -// weights_sum /= weights_sum; -// } -// weights_sum=1.1; - - // Now we have to pick the 4 highest weights and use them to blend textures. - - // Using arrays because Godot's shader version doesn't support dynamic indexing of vectors - // TODO We should not need to initialize, but apparently we don't always find 4 weights - int high_indices_array[4] = {0, 0, 0, 0}; - float high_weights_array[4] = {0.0, 0.0, 0.0, 0.0}; - int count = 0; - // We know weights are supposed to be normalized. - // That means the highest value of the pivot above which we can find 4 results - // is 1.0 / 4.0. However that would mean exactly 4 textures have exactly that weight, - // which is very unlikely. If we consider 1.0 / 5.0, we are a bit more likely to find - // 4 results, and finding 5 results remains almost impossible. - float pivot = /*weights_sum*/1.0 / 5.0; - - for (int i = 0; i < 16; ++i) { - if (weights[i] > pivot) { - high_weights_array[count] = weights[i]; - high_indices_array[count] = i; - weights[i] = 0.0; - ++count; - } - } - - while (count < 4 && pivot > 0.0) { - float max_weight = 0.0; - int max_index = 0; - - for (int i = 0; i < 16; ++i) { - if (/*weights[i] <= pivot && */weights[i] > max_weight) { - max_weight = weights[i]; - max_index = i; - weights[i] = 0.0; - } - } - - high_indices_array[count] = max_index; - high_weights_array[count] = max_weight; - ++count; - pivot = max_weight; - } - - out_high_weights = vec4( - high_weights_array[0], high_weights_array[1], - high_weights_array[2], high_weights_array[3]); - - out_high_indices = vec4( - float(high_indices_array[0]), float(high_indices_array[1]), - float(high_indices_array[2]), float(high_indices_array[3])); - - out_high_weights /= - out_high_weights.r + out_high_weights.g + out_high_weights.b + out_high_weights.a; -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv = base_ground_uv / u_ground_uv_scale; - - // Putting this in vertex saves a fetch from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate it, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint = tint.rgb; - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - - float globalmap_factor = clamp((v_distance_to_camera - u_globalmap_blend_start) - * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 high_indices; - vec4 high_weights; - get_splat_weights(UV, high_indices, high_weights); - - vec4 ab0 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.x)); - vec4 ab1 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.y)); - vec4 ab2 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.z)); - vec4 ab3 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.w)); - - vec3 col0 = ab0.rgb * v_tint; - vec3 col1 = ab1.rgb * v_tint; - vec3 col2 = ab2.rgb * v_tint; - vec3 col3 = ab3.rgb * v_tint; - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(high_weights, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = high_weights; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - -// if(count < 3) { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - // Show splatmap weights - //ALBEDO = w.rgb; - } - // Highlight all pixels undergoing no splatmap at all -// else { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - - NORMAL = (VIEW_MATRIX * (vec4(terrain_normal_world, 0.0))).xyz; -} diff --git a/addons/zylann.hterrain/shaders/simple4.gdshader b/addons/zylann.hterrain/shaders/simple4.gdshader deleted file mode 100644 index 6c28b77..0000000 --- a/addons/zylann.hterrain/shaders/simple4.gdshader +++ /dev/null @@ -1,329 +0,0 @@ -shader_type spatial; - -// This is the reference shader of the plugin, and has the most features. -// it should be preferred for high-end graphics cards. -// For less features but lower-end targets, see the lite version. - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -// the reason bump is preferred with albedo is, roughness looks better with normal maps. -// If we want no normal mapping, roughness would only give flat mirror surfaces, -// while bump still allows to do depth-blending for free. -uniform sampler2D u_ground_albedo_bump_0 : source_color; -uniform sampler2D u_ground_albedo_bump_1 : source_color; -uniform sampler2D u_ground_albedo_bump_2 : source_color; -uniform sampler2D u_ground_albedo_bump_3 : source_color; - -uniform sampler2D u_ground_normal_roughness_0; -uniform sampler2D u_ground_normal_roughness_1; -uniform sampler2D u_ground_normal_roughness_2; -uniform sampler2D u_ground_normal_roughness_3; - -// Had to give this uniform a suffix, because it's declared as a simple float -// in other shaders, and its type cannot be inferred by the plugin. -// See https://github.com/godotengine/godot/issues/24488 -uniform vec4 u_ground_uv_scale_per_texture = vec4(20.0, 20.0, 20.0, 20.0); - -uniform bool u_depth_blending = true; -uniform bool u_triplanar = false; -// Each component corresponds to a ground texture. Set greater than zero to enable. -uniform vec4 u_tile_reduction = vec4(0.0, 0.0, 0.0, 0.0); - -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; - -uniform vec4 u_colormap_opacity_per_texture = vec4(1.0, 1.0, 1.0, 1.0); - -varying float v_hole; -varying vec3 v_tint0; -varying vec3 v_tint1; -varying vec3 v_tint2; -varying vec3 v_tint3; -varying vec4 v_splat; -varying vec2 v_ground_uv0; -varying vec2 v_ground_uv1; -varying vec2 v_ground_uv2; -varying vec3 v_ground_uv3; -varying float v_distance_to_camera; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec4 pack_normal(vec3 n, float a) { - n.z *= -1.0; - return vec4((n.xzy + vec3(1.0)) * 0.5, a); -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -vec4 depth_blend2(vec4 a_value, float a_bump, vec4 b_value, float b_bump, float t) { - // https://www.gamasutra.com - // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php - float d = 0.1; - float ma = max(a_bump + (1.0 - t), b_bump + t) - d; - float ba = max(a_bump + (1.0 - t) - ma, 0.0); - float bb = max(b_bump + t - ma, 0.0); - return (a_value * ba + b_value * bb) / (ba + bb); -} - -vec2 rotate(vec2 v, float cosa, float sina) { - return vec2(cosa * v.x - sina * v.y, sina * v.x + cosa * v.y); -} - -vec4 texture_antitile(sampler2D albedo_tex, sampler2D normal_tex, vec2 uv, out vec4 out_normal) { - float frequency = 2.0; - float scale = 1.3; - float sharpness = 0.7; - - // Rotate and scale UV - float rot = 3.14 * 0.6; - float cosa = cos(rot); - float sina = sin(rot); - vec2 uv2 = rotate(uv, cosa, sina) * scale; - - vec4 col0 = texture(albedo_tex, uv); - vec4 col1 = texture(albedo_tex, uv2); - vec4 nrm0 = texture(normal_tex, uv); - vec4 nrm1 = texture(normal_tex, uv2); - //col0 = vec4(0.0, 0.5, 0.5, 1.0); // Highlights variations - - // Normals have to be rotated too since we are rotating the texture... - // TODO Probably not the most efficient but understandable for now - vec3 n = unpack_normal(nrm1); - // Had to negate the Y axis for some reason. I never remember the myriad of conventions around - n.xz = rotate(n.xz, cosa, -sina); - nrm1 = pack_normal(n, nrm1.a); - - // Periodically alternate between the two versions using a warped checker pattern - float t = 1.2 + - sin(uv2.x * frequency + sin(uv.x) * 2.0) - * cos(uv2.y * frequency + sin(uv.y) * 2.0); // Result in [0..2] - t = smoothstep(sharpness, 2.0 - sharpness, t); - - // Using depth blend because classic alpha blending smoothes out details. - out_normal = depth_blend2(nrm0, col0.a, nrm1, col1.a, t); - return depth_blend2(col0, col0.a, col1, col1.a, t); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv0 = base_ground_uv.xz / u_ground_uv_scale_per_texture.x; - v_ground_uv1 = base_ground_uv.xz / u_ground_uv_scale_per_texture.y; - v_ground_uv2 = base_ground_uv.xz / u_ground_uv_scale_per_texture.z; - v_ground_uv3 = base_ground_uv / u_ground_uv_scale_per_texture.w; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint0 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.x); - v_tint1 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.y); - v_tint2 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.z); - v_tint3 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.w); - v_splat = texture(u_terrain_splatmap, UV); - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - float globalmap_factor = clamp((v_distance_to_camera - u_globalmap_blend_start) - * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 ab0, ab1, ab2, ab3; - vec4 nr0, nr1, nr2, nr3; - - if (u_triplanar) { - // Only do triplanar on one texture slot, - // because otherwise it would be very expensive and cost many more ifs. - // I chose the last slot because first slot is the default on new splatmaps, - // and that's a feature used for cliffs, which are usually designed later. - - vec3 blending = get_triplanar_blend(terrain_normal_world); - - ab3 = texture_triplanar(u_ground_albedo_bump_3, v_ground_uv3, blending); - nr3 = texture_triplanar(u_ground_normal_roughness_3, v_ground_uv3, blending); - - } else { - if (u_tile_reduction[3] > 0.0) { - ab3 = texture_antitile( - u_ground_albedo_bump_3, u_ground_normal_roughness_3, v_ground_uv3.xz, nr3); - } else { - ab3 = texture(u_ground_albedo_bump_3, v_ground_uv3.xz); - nr3 = texture(u_ground_normal_roughness_3, v_ground_uv3.xz); - } - } - - if (u_tile_reduction[0] > 0.0) { - ab0 = texture_antitile( - u_ground_albedo_bump_0, u_ground_normal_roughness_0, v_ground_uv0, nr0); - } else { - ab0 = texture(u_ground_albedo_bump_0, v_ground_uv0); - nr0 = texture(u_ground_normal_roughness_0, v_ground_uv0); - } - if (u_tile_reduction[1] > 0.0) { - ab1 = texture_antitile( - u_ground_albedo_bump_1, u_ground_normal_roughness_1, v_ground_uv1, nr1); - } else { - ab1 = texture(u_ground_albedo_bump_1, v_ground_uv1); - nr1 = texture(u_ground_normal_roughness_1, v_ground_uv1); - } - if (u_tile_reduction[2] > 0.0) { - ab2 = texture_antitile( - u_ground_albedo_bump_2, u_ground_normal_roughness_2, v_ground_uv2, nr2); - } else { - ab2 = texture(u_ground_albedo_bump_2, v_ground_uv2); - nr2 = texture(u_ground_normal_roughness_2, v_ground_uv2); - } - - vec3 col0 = ab0.rgb * v_tint0; - vec3 col1 = ab1.rgb * v_tint1; - vec3 col2 = ab2.rgb * v_tint2; - vec3 col3 = ab3.rgb * v_tint3; - - vec4 rough = vec4(nr0.a, nr1.a, nr2.a, nr3.a); - - vec3 normal0 = unpack_normal(nr0); - vec3 normal1 = unpack_normal(nr1); - vec3 normal2 = unpack_normal(nr2); - vec3 normal3 = unpack_normal(nr3); - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(v_splat, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = v_splat.rgba; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ROUGHNESS = ( - w.r * rough.r + - w.g * rough.g + - w.b * rough.b + - w.a * rough.a) / w_sum; - - vec3 ground_normal = /*u_terrain_normal_basis **/ ( - w.r * normal0 + - w.g * normal1 + - w.b * normal2 + - w.a * normal3) / w_sum; - // If no splat textures are defined, normal vectors will default to (1,1,1), - // which is incorrect, and causes the terrain to be shaded wrongly in some directions. - // However, this should not be a problem to fix in the shader, - // because there MUST be at least one splat texture set. - //ground_normal = normalize(ground_normal); - // TODO Make the plugin insert a default normalmap if it's empty - - // Combine terrain normals with detail normals (not sure if correct but looks ok) - normal = normalize(vec3( - terrain_normal_world.x + ground_normal.x, - terrain_normal_world.y, - terrain_normal_world.z + ground_normal.z)); - - normal = mix(normal, terrain_normal_world, globalmap_factor); - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - - // Show splatmap weights - //ALBEDO = w.rgb; - } - // Highlight all pixels undergoing no splatmap at all -// else { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; -} diff --git a/addons/zylann.hterrain/shaders/simple4_global.gdshader b/addons/zylann.hterrain/shaders/simple4_global.gdshader deleted file mode 100644 index f504c48..0000000 --- a/addons/zylann.hterrain/shaders/simple4_global.gdshader +++ /dev/null @@ -1,83 +0,0 @@ -shader_type spatial; - -// This shader is used to bake the global albedo map. -// It exposes a subset of the main shader API, so uniform names were not modified. - -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap;// : hint_albedo; -uniform sampler2D u_terrain_splatmap; - -uniform sampler2D u_ground_albedo_bump_0 : source_color; -uniform sampler2D u_ground_albedo_bump_1 : source_color; -uniform sampler2D u_ground_albedo_bump_2 : source_color; -uniform sampler2D u_ground_albedo_bump_3 : source_color; - -// Keep depth blending because it has a high effect on the final result -uniform bool u_depth_blending = true; -uniform float u_ground_uv_scale = 20.0; - - -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = wpos.xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = (cell_coords / vec2(textureSize(u_terrain_splatmap, 0))); -} - -void fragment() { - // These were moved from vertex to fragment, - // so we can generate part of the global map with just one quad and we get full quality - vec4 tint = texture(u_terrain_colormap, UV); - vec4 splat = texture(u_terrain_splatmap, UV); - - // Get bump at normal resolution so depth blending is accurate - vec2 ground_uv = UV / u_ground_uv_scale; - float b0 = texture(u_ground_albedo_bump_0, ground_uv).a; - float b1 = texture(u_ground_albedo_bump_1, ground_uv).a; - float b2 = texture(u_ground_albedo_bump_2, ground_uv).a; - float b3 = texture(u_ground_albedo_bump_3, ground_uv).a; - - // Take the center of the highest mip as color, because we can't see details from far away. - vec2 ndc_center = vec2(0.5, 0.5); - vec3 col0 = textureLod(u_ground_albedo_bump_0, ndc_center, 10.0).rgb; - vec3 col1 = textureLod(u_ground_albedo_bump_1, ndc_center, 10.0).rgb; - vec3 col2 = textureLod(u_ground_albedo_bump_2, ndc_center, 10.0).rgb; - vec3 col3 = textureLod(u_ground_albedo_bump_3, ndc_center, 10.0).rgb; - - vec4 w; - if (u_depth_blending) { - w = get_depth_blended_weights(splat, vec4(b0, b1, b2, b3)); - } else { - w = splat.rgba; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = tint.rgb * ( - w.r * col0 + - w.g * col1 + - w.b * col2 + - w.a * col3) / w_sum; -} - diff --git a/addons/zylann.hterrain/shaders/simple4_lite.gdshader b/addons/zylann.hterrain/shaders/simple4_lite.gdshader deleted file mode 100644 index dcd660c..0000000 --- a/addons/zylann.hterrain/shaders/simple4_lite.gdshader +++ /dev/null @@ -1,211 +0,0 @@ -shader_type spatial; - -// This is a shader with less textures, in case the main one doesn't run on your GPU. -// It's mostly a big copy/paste, because Godot doesn't support #include or #ifdef... - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap;// : hint_albedo; -uniform sampler2D u_terrain_splatmap; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2D u_ground_albedo_bump_0 : source_color; -uniform sampler2D u_ground_albedo_bump_1 : source_color; -uniform sampler2D u_ground_albedo_bump_2 : source_color; -uniform sampler2D u_ground_albedo_bump_3 : source_color; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; -uniform bool u_triplanar = false; -// Each component corresponds to a ground texture. Set greater than zero to enable. -uniform vec4 u_tile_reduction = vec4(0.0, 0.0, 0.0, 0.0); - -varying vec4 v_tint; -varying vec4 v_splat; -varying vec3 v_ground_uv; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -vec4 depth_blend2(vec4 a, vec4 b, float t) { - // https://www.gamasutra.com - // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php - float d = 0.1; - float ma = max(a.a + (1.0 - t), b.a + t) - d; - float ba = max(a.a + (1.0 - t) - ma, 0.0); - float bb = max(b.a + t - ma, 0.0); - return (a * ba + b * bb) / (ba + bb); -} - -vec4 texture_antitile(sampler2D tex, vec2 uv) { - float frequency = 2.0; - float scale = 1.3; - float sharpness = 0.7; - - // Rotate and scale UV - float rot = 3.14 * 0.6; - float cosa = cos(rot); - float sina = sin(rot); - vec2 uv2 = vec2(cosa * uv.x - sina * uv.y, sina * uv.x + cosa * uv.y) * scale; - - vec4 col0 = texture(tex, uv); - vec4 col1 = texture(tex, uv2); - //col0 = vec4(0.0, 0.0, 1.0, 1.0); - // Periodically alternate between the two versions using a warped checker pattern - float t = 0.5 + 0.5 - * sin(uv2.x * frequency + sin(uv.x) * 2.0) - * cos(uv2.y * frequency + sin(uv.y) * 2.0); - // Using depth blend because classic alpha blending smoothes out details - return depth_blend2(col0, col1, smoothstep(0.5 * sharpness, 1.0 - 0.5 * sharpness, t)); -} - -void vertex() { - vec2 cell_coords = (u_terrain_inverse_transform * MODEL_MATRIX * vec4(VERTEX, 1)).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results. - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - - v_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y) / u_ground_uv_scale; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - v_tint = texture(u_terrain_colormap, UV); - v_splat = texture(u_terrain_splatmap, UV); - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); -} - -void fragment() { - if (v_tint.a < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - - // TODO Detail should only be rasterized on nearby chunks (needs proximity management to switch shaders) - - vec2 ground_uv = v_ground_uv.xz; - - vec4 ab0, ab1, ab2, ab3; - if (u_triplanar) { - // Only do triplanar on one texture slot, - // because otherwise it would be very expensive and cost many more ifs. - // I chose the last slot because first slot is the default on new splatmaps, - // and that's a feature used for cliffs, which are usually designed later. - - vec3 blending = get_triplanar_blend(terrain_normal_world); - - ab3 = texture_triplanar(u_ground_albedo_bump_3, v_ground_uv, blending); - - } else { - if (u_tile_reduction[3] > 0.0) { - ab3 = texture(u_ground_albedo_bump_3, ground_uv); - } else { - ab3 = texture_antitile(u_ground_albedo_bump_3, ground_uv); - } - } - - if (u_tile_reduction[0] > 0.0) { - ab0 = texture_antitile(u_ground_albedo_bump_0, ground_uv); - } else { - ab0 = texture(u_ground_albedo_bump_0, ground_uv); - } - if (u_tile_reduction[1] > 0.0) { - ab1 = texture_antitile(u_ground_albedo_bump_1, ground_uv); - } else { - ab1 = texture(u_ground_albedo_bump_1, ground_uv); - } - if (u_tile_reduction[2] > 0.0) { - ab2 = texture_antitile(u_ground_albedo_bump_2, ground_uv); - } else { - ab2 = texture(u_ground_albedo_bump_2, ground_uv); - } - - vec3 col0 = ab0.rgb; - vec3 col1 = ab1.rgb; - vec3 col2 = ab2.rgb; - vec3 col3 = ab3.rgb; - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(v_splat, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = v_splat.rgba; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = v_tint.rgb * ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ROUGHNESS = 1.0; - - NORMAL = (VIEW_MATRIX * (vec4(terrain_normal_world, 0.0))).xyz; - - //ALBEDO = w.rgb; - //ALBEDO = v_ground_uv.xyz; -} - diff --git a/addons/zylann.hterrain/tools/about/about_dialog.gd b/addons/zylann.hterrain/tools/about/about_dialog.gd deleted file mode 100644 index 20ec8f8..0000000 --- a/addons/zylann.hterrain/tools/about/about_dialog.gd +++ /dev/null @@ -1,28 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../util/util.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_Errors = preload("../../util/errors.gd") - -const PLUGIN_CFG_PATH = "res://addons/zylann.hterrain/plugin.cfg" - - -@onready var _about_rich_text_label : RichTextLabel = $VB/HB2/TC/About - -var _logger = HT_Logger.get_for(self) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - var plugin_cfg = ConfigFile.new() - var err := plugin_cfg.load(PLUGIN_CFG_PATH) - if err != OK: - _logger.error("Could not load {0}: {1}" \ - .format([PLUGIN_CFG_PATH, HT_Errors.get_message(err)])) - return - var version = plugin_cfg.get_value("plugin", "version", "--.--.--") - - _about_rich_text_label.text = _about_rich_text_label.text.format({"version": version}) diff --git a/addons/zylann.hterrain/tools/about/about_dialog.tscn b/addons/zylann.hterrain/tools/about/about_dialog.tscn deleted file mode 100644 index efeda7a..0000000 --- a/addons/zylann.hterrain/tools/about/about_dialog.tscn +++ /dev/null @@ -1,85 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://cvuubd08805oa"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/about/about_dialog.gd" id="1"] -[ext_resource type="Texture2D" uid="uid://sdaddk8wxjin" path="res://addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg" id="2"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd" id="3"] - -[node name="AboutDialog" type="AcceptDialog"] -size = Vector2i(516, 357) -script = ExtResource("1") - -[node name="VB" type="VBoxContainer" parent="."] -custom_minimum_size = Vector2(500, 300) -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -49.0 - -[node name="HB2" type="HBoxContainer" parent="VB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="TextureRect" type="TextureRect" parent="VB/HB2"] -layout_mode = 2 -texture = ExtResource("2") -stretch_mode = 2 - -[node name="TC" type="TabContainer" parent="VB/HB2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="About" type="RichTextLabel" parent="VB/HB2/TC"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -bbcode_enabled = true -text = "Version: {version} -Author: Marc Gilleron -Repository: https://github.com/Zylann/godot_heightmap_plugin -Issue tracker: https://github.com/Zylann/godot_heightmap_plugin/issues - -Gold supporters: - -Aaron Franke (aaronfranke) - -Silver supporters: - -TheConceptBoy -Chris Bolton (yochrisbolton) -Gamerfiend (Snowminx) -greenlion (Justin Swanhart) -segfault-god (jp.owo.Manda) -RonanZe -Phyronnaz -NoFr1ends (Lynx) - -Bronze supporters: - -rcorre (Ryan Roden-Corrent) -duchainer (Raphaël Duchaîne) -MadMartian -stackdump (stackdump.eth) -Treer -MrGreaterThan -lenis0012 -" -script = ExtResource("3") - -[node name="License" type="RichTextLabel" parent="VB/HB2/TC"] -visible = false -layout_mode = 2 -text = "Copyright (c) 2016-2023 Marc Gilleron - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -" - -[node name="HB" type="HBoxContainer" parent="VB"] -layout_mode = 2 -alignment = 1 diff --git a/addons/zylann.hterrain/tools/brush/brush.gd b/addons/zylann.hterrain/tools/brush/brush.gd deleted file mode 100644 index 73d447f..0000000 --- a/addons/zylann.hterrain/tools/brush/brush.gd +++ /dev/null @@ -1,217 +0,0 @@ -@tool - -# Brush properties (shape, transform, timing and opacity). -# Other attributes like color, height or texture index are tool-specific, -# while brush properties apply to all of them. -# This is separate from Painter because it could apply to multiple Painters at once. - -const HT_Errors = preload("../../util/errors.gd") -const HT_Painter = preload("./painter.gd") - -const SHAPES_DIR = "addons/zylann.hterrain/tools/brush/shapes" -const DEFAULT_BRUSH_TEXTURE_PATH = SHAPES_DIR + "/round2.exr" -# Reasonable size for sliders to be usable -const MAX_SIZE_FOR_SLIDERS = 500 -# Absolute size limit. Terrains can't be larger than that, and it will be very slow to paint -const MAX_SIZE = 4000 - -signal size_changed(new_size) -signal shapes_changed -signal shape_index_changed - -var _size := 32 -var _opacity := 1.0 -var _random_rotation := false -var _pressure_enabled := false -var _pressure_over_scale := 0.5 -var _pressure_over_opacity := 0.5 -# TODO Rename stamp_*? -var _frequency_distance := 0.0 -var _frequency_time_ms := 0 -# Array of greyscale textures -var _shapes : Array[Texture2D] = [] - -var _shape_index := 0 -var _shape_cycling_enabled := false -var _prev_position := Vector2(-999, -999) -var _prev_time_ms := 0 - - -func set_size(size: int): - if size < 1: - size = 1 - if size != _size: - _size = size - size_changed.emit(_size) - - -func get_size() -> int: - return _size - - -func set_opacity(opacity: float): - _opacity = clampf(opacity, 0.0, 1.0) - - -func get_opacity() -> float: - return _opacity - - -func set_random_rotation_enabled(enabled: bool): - _random_rotation = enabled - - -func is_random_rotation_enabled() -> bool: - return _random_rotation - - -func set_pressure_enabled(enabled: bool): - _pressure_enabled = enabled - - -func is_pressure_enabled() -> bool: - return _pressure_enabled - - -func set_pressure_over_scale(amount: float): - _pressure_over_scale = clampf(amount, 0.0, 1.0) - - -func get_pressure_over_scale() -> float: - return _pressure_over_scale - - -func set_pressure_over_opacity(amount: float): - _pressure_over_opacity = clampf(amount, 0.0, 1.0) - - -func get_pressure_over_opacity() -> float: - return _pressure_over_opacity - - -func set_frequency_distance(d: float): - _frequency_distance = maxf(d, 0.0) - - -func get_frequency_distance() -> float: - return _frequency_distance - - -func set_frequency_time_ms(t: int): - if t < 0: - t = 0 - _frequency_time_ms = t - - -func get_frequency_time_ms() -> int: - return _frequency_time_ms - - -func set_shapes(shapes: Array[Texture2D]): - assert(len(shapes) >= 1) - for s in shapes: - assert(s != null) - assert(s is Texture2D) - _shapes = shapes.duplicate(false) - if _shape_index >= len(_shapes): - _shape_index = len(_shapes) - 1 - shapes_changed.emit() - - -func get_shapes() -> Array[Texture2D]: - return _shapes.duplicate(false) - - -func get_shape(i: int) -> Texture2D: - return _shapes[i] - - -func get_shape_index() -> int: - return _shape_index - - -func set_shape_index(i: int): - assert(i >= 0) - assert(i < len(_shapes)) - _shape_index = i - shape_index_changed.emit() - - -func set_shape_cycling_enabled(enable: bool): - _shape_cycling_enabled = enable - - -func is_shape_cycling_enabled() -> bool: - return _shape_cycling_enabled - - -static func load_shape_from_image_file(fpath: String, logger, retries := 1) -> Texture2D: - var im := Image.new() - var err := im.load(fpath) - if err != OK: - if retries > 0: - # TODO There is a bug with Godot randomly being unable to load images. - # See https://github.com/Zylann/godot_heightmap_plugin/issues/219 - # Attempting to workaround this by retrying (I suspect it's because of non-initialized - # variable in Godot's C++ code...) - logger.error("Could not load image at '{0}', error {1}. Retrying..." \ - .format([fpath, HT_Errors.get_message(err)])) - return load_shape_from_image_file(fpath, logger, retries - 1) - else: - logger.error("Could not load image at '{0}', error {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return null - var tex := ImageTexture.create_from_image(im) - return tex - - -# Call this while handling mouse or pen input. -# If it returns false, painting should not run. -func configure_paint_input(painters: Array[HT_Painter], position: Vector2, pressure: float) -> bool: - assert(len(_shapes) != 0) - - # DEBUG - #pressure = 0.5 + 0.5 * sin(OS.get_ticks_msec() / 200.0) - - if position.distance_to(_prev_position) < _frequency_distance: - return false - var now := Time.get_ticks_msec() - if (now - _prev_time_ms) < _frequency_time_ms: - return false - _prev_position = position - _prev_time_ms = now - - for painter_index in len(painters): - var painter : HT_Painter = painters[painter_index] - - if _random_rotation: - painter.set_brush_rotation(randf_range(-PI, PI)) - else: - painter.set_brush_rotation(0.0) - - painter.set_brush_texture(_shapes[_shape_index]) - painter.set_brush_size(_size) - - if _pressure_enabled: - painter.set_brush_scale(lerpf(1.0, pressure, _pressure_over_scale)) - painter.set_brush_opacity(_opacity * lerpf(1.0, pressure, _pressure_over_opacity)) - else: - painter.set_brush_scale(1.0) - painter.set_brush_opacity(_opacity) - - #painter.paint_input(position) - - if _shape_cycling_enabled: - _shape_index += 1 - if _shape_index >= len(_shapes): - _shape_index = 0 - - return true - - -# Call this when the user releases the pen or mouse button -func on_paint_end(): - _prev_position = Vector2(-999, -999) - _prev_time_ms = 0 - - diff --git a/addons/zylann.hterrain/tools/brush/brush_editor.gd b/addons/zylann.hterrain/tools/brush/brush_editor.gd deleted file mode 100644 index 1e645a3..0000000 --- a/addons/zylann.hterrain/tools/brush/brush_editor.gd +++ /dev/null @@ -1,234 +0,0 @@ -@tool -extends Control - -const HT_TerrainPainter = preload("./terrain_painter.gd") -const HT_Brush = preload("./brush.gd") -const HT_Errors = preload("../../util/errors.gd") -#const NativeFactory = preload("../../native/factory.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_IntervalSlider = preload("../util/interval_slider.gd") - -const HT_BrushSettingsDialogScene = preload("./settings_dialog/brush_settings_dialog.tscn") -const HT_BrushSettingsDialog = preload("./settings_dialog/brush_settings_dialog.gd") - - -@onready var _size_slider : Slider = $GridContainer/BrushSizeControl/Slider -@onready var _size_value_label : Label = $GridContainer/BrushSizeControl/Label -#onready var _size_label = _params_container.get_node("BrushSizeLabel") - -@onready var _opacity_slider : Slider = $GridContainer/BrushOpacityControl/Slider -@onready var _opacity_value_label : Label = $GridContainer/BrushOpacityControl/Label -@onready var _opacity_control : Control = $GridContainer/BrushOpacityControl -@onready var _opacity_label : Label = $GridContainer/BrushOpacityLabel - -@onready var _flatten_height_container : Control = $GridContainer/HB -@onready var _flatten_height_box : SpinBox = $GridContainer/HB/FlattenHeightControl -@onready var _flatten_height_label : Label = $GridContainer/FlattenHeightLabel -@onready var _flatten_height_pick_button : Button = $GridContainer/HB/FlattenHeightPickButton - -@onready var _color_picker : ColorPickerButton = $GridContainer/ColorPickerButton -@onready var _color_label : Label = $GridContainer/ColorLabel - -@onready var _density_slider : Slider = $GridContainer/DensitySlider -@onready var _density_label : Label = $GridContainer/DensityLabel - -@onready var _holes_label : Label = $GridContainer/HoleLabel -@onready var _holes_checkbox : CheckBox = $GridContainer/HoleCheckbox - -@onready var _slope_limit_label : Label = $GridContainer/SlopeLimitLabel -@onready var _slope_limit_control : HT_IntervalSlider = $GridContainer/SlopeLimit - -@onready var _shape_texture_rect : TextureRect = get_node("BrushShapeButton/TextureRect") - -var _terrain_painter : HT_TerrainPainter -var _brush_settings_dialog : HT_BrushSettingsDialog = null -var _logger = HT_Logger.get_for(self) - -# TODO This is an ugly workaround for https://github.com/godotengine/godot/issues/19479 -@onready var _temp_node = get_node("Temp") -@onready var _grid_container = get_node("GridContainer") -func _set_visibility_of(node: Control, v: bool): - node.get_parent().remove_child(node) - if v: - _grid_container.add_child(node) - else: - _temp_node.add_child(node) - node.visible = v - - -func _ready(): - _size_slider.value_changed.connect(_on_size_slider_value_changed) - _opacity_slider.value_changed.connect(_on_opacity_slider_value_changed) - _flatten_height_box.value_changed.connect(_on_flatten_height_box_value_changed) - _color_picker.color_changed.connect(_on_color_picker_color_changed) - _density_slider.value_changed.connect(_on_density_slider_changed) - _holes_checkbox.toggled.connect(_on_holes_checkbox_toggled) - _slope_limit_control.changed.connect(_on_slope_limit_changed) - - _size_slider.max_value = HT_Brush.MAX_SIZE_FOR_SLIDERS - #if NativeFactory.is_native_available(): - # _size_slider.max_value = 200 - #else: - # _size_slider.max_value = 50 - - -func setup_dialogs(base_control: Node): - assert(_brush_settings_dialog == null) - _brush_settings_dialog = HT_BrushSettingsDialogScene.instantiate() - base_control.add_child(_brush_settings_dialog) - - # That dialog has sub-dialogs - _brush_settings_dialog.setup_dialogs(base_control) - _brush_settings_dialog.set_brush(_terrain_painter.get_brush()) - - -func _exit_tree(): - if _brush_settings_dialog != null: - _brush_settings_dialog.queue_free() - _brush_settings_dialog = null - -# Testing display modes -#var mode = 0 -#func _input(event): -# if event is InputEventKey: -# if event.pressed: -# set_display_mode(mode) -# mode += 1 -# if mode >= Brush.MODE_COUNT: -# mode = 0 - -func set_terrain_painter(terrain_painter: HT_TerrainPainter): - if _terrain_painter != null: - _terrain_painter.flatten_height_changed.disconnect(_on_flatten_height_changed) - _terrain_painter.get_brush().shapes_changed.disconnect(_on_brush_shapes_changed) - _terrain_painter.get_brush().shape_index_changed.disconnect(_on_brush_shape_index_changed) - - _terrain_painter = terrain_painter - - if _terrain_painter != null: - # TODO Had an issue in Godot 3.2.3 where mismatching type would silently cast to null... - # It happens if the argument went through a Variant (for example if call_deferred is used) - assert(_terrain_painter != null) - - if _terrain_painter != null: - # Initial brush params - _size_slider.value = _terrain_painter.get_brush().get_size() - _opacity_slider.ratio = _terrain_painter.get_brush().get_opacity() - # Initial specific params - _flatten_height_box.value = _terrain_painter.get_flatten_height() - _color_picker.get_picker().color = _terrain_painter.get_color() - _density_slider.value = _terrain_painter.get_detail_density() - _holes_checkbox.button_pressed = not _terrain_painter.get_mask_flag() - - var low := rad_to_deg(_terrain_painter.get_slope_limit_low_angle()) - var high := rad_to_deg(_terrain_painter.get_slope_limit_high_angle()) - _slope_limit_control.set_values(low, high) - - set_display_mode(_terrain_painter.get_mode()) - - # Load default brush - var brush := _terrain_painter.get_brush() - var default_shape_fpath := HT_Brush.DEFAULT_BRUSH_TEXTURE_PATH - var default_shape := HT_Brush.load_shape_from_image_file(default_shape_fpath, _logger) - brush.set_shapes([default_shape]) - _update_shape_preview() - - _terrain_painter.flatten_height_changed.connect(_on_flatten_height_changed) - brush.shapes_changed.connect(_on_brush_shapes_changed) - brush.shape_index_changed.connect(_on_brush_shape_index_changed) - - -func _on_flatten_height_changed(): - _flatten_height_box.value = _terrain_painter.get_flatten_height() - _flatten_height_pick_button.button_pressed = false - - -func _on_brush_shapes_changed(): - _update_shape_preview() - - -func _on_brush_shape_index_changed(): - _update_shape_preview() - - -func _update_shape_preview(): - var brush := _terrain_painter.get_brush() - var i := brush.get_shape_index() - _shape_texture_rect.texture = brush.get_shape(i) - - -func set_display_mode(mode: int): - var show_flatten := mode == HT_TerrainPainter.MODE_FLATTEN - var show_color := mode == HT_TerrainPainter.MODE_COLOR - var show_density := mode == HT_TerrainPainter.MODE_DETAIL - var show_opacity := mode != HT_TerrainPainter.MODE_MASK - var show_holes := mode == HT_TerrainPainter.MODE_MASK - var show_slope_limit := \ - mode == HT_TerrainPainter.MODE_SPLAT or mode == HT_TerrainPainter.MODE_DETAIL - - _set_visibility_of(_opacity_label, show_opacity) - _set_visibility_of(_opacity_control, show_opacity) - - _set_visibility_of(_color_label, show_color) - _set_visibility_of(_color_picker, show_color) - - _set_visibility_of(_flatten_height_label, show_flatten) - _set_visibility_of(_flatten_height_container, show_flatten) - - _set_visibility_of(_density_label, show_density) - _set_visibility_of(_density_slider, show_density) - - _set_visibility_of(_holes_label, show_holes) - _set_visibility_of(_holes_checkbox, show_holes) - - _set_visibility_of(_slope_limit_label, show_slope_limit) - _set_visibility_of(_slope_limit_control, show_slope_limit) - - _flatten_height_pick_button.button_pressed = false - - -func _on_size_slider_value_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_brush_size(int(v)) - _size_value_label.text = str(v) - - -func _on_opacity_slider_value_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_opacity(_opacity_slider.ratio) - _opacity_value_label.text = str(v) - - -func _on_flatten_height_box_value_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_flatten_height(v) - - -func _on_color_picker_color_changed(v: Color): - if _terrain_painter != null: - _terrain_painter.set_color(v) - - -func _on_density_slider_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_detail_density(v) - - -func _on_holes_checkbox_toggled(v: bool): - if _terrain_painter != null: - # When checked, we draw holes. When unchecked, we clear holes - _terrain_painter.set_mask_flag(not v) - - -func _on_BrushShapeButton_pressed(): - _brush_settings_dialog.popup_centered() - - -func _on_FlattenHeightPickButton_pressed(): - _terrain_painter.set_meta("pick_height", true) - - -func _on_slope_limit_changed(): - var low = deg_to_rad(_slope_limit_control.get_low_value()) - var high = deg_to_rad(_slope_limit_control.get_high_value()) - _terrain_painter.set_slope_limit_angles(low, high) diff --git a/addons/zylann.hterrain/tools/brush/brush_editor.tscn b/addons/zylann.hterrain/tools/brush/brush_editor.tscn deleted file mode 100644 index 42ef980..0000000 --- a/addons/zylann.hterrain/tools/brush/brush_editor.tscn +++ /dev/null @@ -1,130 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://bd42ig216p216"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/brush_editor.gd" id="1"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/util/interval_slider.gd" id="3"] - -[sub_resource type="CanvasItemMaterial" id="1"] -blend_mode = 1 - -[node name="BrushEditor" type="HBoxContainer"] -custom_minimum_size = Vector2(200, 0) -offset_right = 293.0 -offset_bottom = 211.0 -script = ExtResource("1") - -[node name="BrushShapeButton" type="Button" parent="."] -custom_minimum_size = Vector2(50, 0) -layout_mode = 2 - -[node name="TextureRect" type="TextureRect" parent="BrushShapeButton"] -material = SubResource("1") -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 2 -expand_mode = 1 -stretch_mode = 5 - -[node name="GridContainer" type="GridContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -columns = 2 - -[node name="BrushSizeLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Brush size" - -[node name="BrushSizeControl" type="HBoxContainer" parent="GridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -mouse_filter = 0 - -[node name="Slider" type="HSlider" parent="GridContainer/BrushSizeControl"] -custom_minimum_size = Vector2(60, 0) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 1 -min_value = 2.0 -max_value = 500.0 -value = 2.0 -exp_edit = true -rounded = true - -[node name="Label" type="Label" parent="GridContainer/BrushSizeControl"] -layout_mode = 2 -text = "999" - -[node name="BrushOpacityLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Brush opacity" - -[node name="BrushOpacityControl" type="HBoxContainer" parent="GridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Slider" type="HSlider" parent="GridContainer/BrushOpacityControl"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 1 - -[node name="Label" type="Label" parent="GridContainer/BrushOpacityControl"] -layout_mode = 2 -text = "999" - -[node name="FlattenHeightLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Flatten height" - -[node name="HB" type="HBoxContainer" parent="GridContainer"] -layout_mode = 2 - -[node name="FlattenHeightControl" type="SpinBox" parent="GridContainer/HB"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = -500.0 -max_value = 500.0 -step = 0.01 - -[node name="FlattenHeightPickButton" type="Button" parent="GridContainer/HB"] -layout_mode = 2 -toggle_mode = true -text = "Pick" - -[node name="ColorLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Color" - -[node name="ColorPickerButton" type="ColorPickerButton" parent="GridContainer"] -layout_mode = 2 -toggle_mode = false -color = Color(1, 1, 1, 1) - -[node name="DensityLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Detail density" - -[node name="DensitySlider" type="HSlider" parent="GridContainer"] -layout_mode = 2 -max_value = 1.0 -step = 0.1 - -[node name="HoleLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Draw holes" - -[node name="HoleCheckbox" type="CheckBox" parent="GridContainer"] -layout_mode = 2 - -[node name="SlopeLimitLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Slope limit" - -[node name="SlopeLimit" type="Control" parent="GridContainer"] -layout_mode = 2 -script = ExtResource("3") -range = Vector2(0, 90) - -[node name="Temp" type="Node" parent="."] - -[connection signal="pressed" from="BrushShapeButton" to="." method="_on_BrushShapeButton_pressed"] -[connection signal="pressed" from="GridContainer/HB/FlattenHeightPickButton" to="." method="_on_FlattenHeightPickButton_pressed"] diff --git a/addons/zylann.hterrain/tools/brush/decal.gd b/addons/zylann.hterrain/tools/brush/decal.gd deleted file mode 100644 index 13433ed..0000000 --- a/addons/zylann.hterrain/tools/brush/decal.gd +++ /dev/null @@ -1,121 +0,0 @@ -@tool -# Shows a cursor on top of the terrain to preview where the brush will paint - -# TODO Use an actual decal node, it wasn't available in Godot 3 - -const HT_DirectMeshInstance = preload("../../util/direct_mesh_instance.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Util = preload("../../util/util.gd") - -var _mesh_instance : HT_DirectMeshInstance -var _mesh : PlaneMesh -var _material = ShaderMaterial.new() -#var _debug_mesh = CubeMesh.new() -#var _debug_mesh_instance = null - -var _terrain : HTerrain = null - - -func _init(): - _material.shader = load("res://addons/zylann.hterrain/tools/brush/decal.gdshader") - _mesh_instance = HT_DirectMeshInstance.new() - _mesh_instance.set_material(_material) - - _mesh = PlaneMesh.new() - _mesh_instance.set_mesh(_mesh) - - #_debug_mesh_instance = DirectMeshInstance.new() - #_debug_mesh_instance.set_mesh(_debug_mesh) - - -func set_size(size: float): - _mesh.size = Vector2(size, size) - # Must line up to terrain vertex policy, so must apply an off-by-one. - # If I don't do that, the brush will appear to wobble above the ground - var ss := size - 1 - # Don't subdivide too much - while ss > 50: - ss /= 2 - _mesh.subdivide_width = ss - _mesh.subdivide_depth = ss - - -#func set_shape(shape_image): -# set_size(shape_image.get_width()) - - -func _on_terrain_transform_changed(terrain_global_trans: Transform3D): - var inv = terrain_global_trans.affine_inverse() - _material.set_shader_parameter("u_terrain_inverse_transform", inv) - - var normal_basis = terrain_global_trans.basis.inverse().transposed() - _material.set_shader_parameter("u_terrain_normal_basis", normal_basis) - - -func set_terrain(terrain: HTerrain): - if _terrain == terrain: - return - - if _terrain != null: - _terrain.transform_changed.disconnect(_on_terrain_transform_changed) - _mesh_instance.exit_world() - #_debug_mesh_instance.exit_world() - - _terrain = terrain - - if _terrain != null: - _terrain.transform_changed.connect(_on_terrain_transform_changed) - _on_terrain_transform_changed(_terrain.get_internal_transform()) - _mesh_instance.enter_world(terrain.get_world_3d()) - #_debug_mesh_instance.enter_world(terrain.get_world()) - - update_visibility() - - -func set_position(p_local_pos: Vector3): - assert(_terrain != null) - assert(typeof(p_local_pos) == TYPE_VECTOR3) - - # Set custom AABB (in local cells) because the decal is displaced by shader - var data = _terrain.get_data() - if data != null: - var r = _mesh.size / 2 - var aabb = data.get_region_aabb( \ - int(p_local_pos.x - r.x), \ - int(p_local_pos.z - r.y), \ - int(2 * r.x), \ - int(2 * r.y)) - aabb.position = Vector3(-r.x, aabb.position.y, -r.y) - _mesh.custom_aabb = aabb - #_debug_mesh.size = aabb.size - - var trans = Transform3D(Basis(), p_local_pos) - var terrain_gt = _terrain.get_internal_transform() - trans = terrain_gt * trans - _mesh_instance.set_transform(trans) - #_debug_mesh_instance.set_transform(trans) - - -# This is called very often so it should be cheap -func update_visibility(): - var heightmap = _get_heightmap(_terrain) - if heightmap == null: - # I do this for refcounting because heightmaps are large resources - _material.set_shader_parameter("u_terrain_heightmap", null) - _mesh_instance.set_visible(false) - #_debug_mesh_instance.set_visible(false) - else: - _material.set_shader_parameter("u_terrain_heightmap", heightmap) - _mesh_instance.set_visible(true) - #_debug_mesh_instance.set_visible(true) - - -func _get_heightmap(terrain): - if terrain == null: - return null - var data = terrain.get_data() - if data == null: - return null - return data.get_texture(HTerrainData.CHANNEL_HEIGHT) - diff --git a/addons/zylann.hterrain/tools/brush/decal.gdshader b/addons/zylann.hterrain/tools/brush/decal.gdshader deleted file mode 100644 index b56f43a..0000000 --- a/addons/zylann.hterrain/tools/brush/decal.gdshader +++ /dev/null @@ -1,41 +0,0 @@ -shader_type spatial; -render_mode unshaded;//, depth_test_disable; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -void vertex() { - vec2 cell_coords = (u_terrain_inverse_transform * MODEL_MATRIX * vec4(VERTEX, 1)).xz; - - vec2 ps = vec2(1.0) / vec2(textureSize(u_terrain_heightmap, 0)); - vec2 uv = ps * cell_coords; - - // Get terrain normal - float k = 1.0; - float left = get_height(u_terrain_heightmap, uv + vec2(-ps.x, 0)) * k; - float right = get_height(u_terrain_heightmap, uv + vec2(ps.x, 0)) * k; - float back = get_height(u_terrain_heightmap, uv + vec2(0, -ps.y)) * k; - float fore = get_height(u_terrain_heightmap, uv + vec2(0, ps.y)) * k; - vec3 n = normalize(vec3(left - right, 2.0, back - fore)); - - n = u_terrain_normal_basis * n; - - float h = get_height(u_terrain_heightmap, uv); - VERTEX.y = h; - VERTEX += 1.0 * n; - NORMAL = n;//vec3(0.0, 1.0, 0.0); -} - -void fragment() { - float len = length(2.0 * UV - 1.0); - float g = clamp(1.0 - 15.0 * abs(0.9 - len), 0.0, 1.0); - ALBEDO = vec3(1.0, 0.1, 0.1); - ALPHA = g; -} diff --git a/addons/zylann.hterrain/tools/brush/no_blend.gdshader b/addons/zylann.hterrain/tools/brush/no_blend.gdshader deleted file mode 100644 index 8ae0f84..0000000 --- a/addons/zylann.hterrain/tools/brush/no_blend.gdshader +++ /dev/null @@ -1,6 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -void fragment() { - COLOR = texture(TEXTURE, UV); -} diff --git a/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader b/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader deleted file mode 100644 index d0460de..0000000 --- a/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader +++ /dev/null @@ -1,9 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -void fragment() { - float h = sample_heightmap(TEXTURE, UV); - COLOR = encode_height_to_viewport(h); -} diff --git a/addons/zylann.hterrain/tools/brush/painter.gd b/addons/zylann.hterrain/tools/brush/painter.gd deleted file mode 100644 index fa4be98..0000000 --- a/addons/zylann.hterrain/tools/brush/painter.gd +++ /dev/null @@ -1,399 +0,0 @@ - -# Core logic to paint a texture using shaders, with undo/redo support. -# Operations are delayed so results are only available the next frame. -# This doesn't implement UI or brush behavior, only rendering logic. -# -# Note: due to the absence of channel separation function in Image, -# you may need to use multiple painters at once if your application exploits multiple channels. -# Example: when painting a heightmap, it would be doable to output height in R, normalmap in GB, and -# then separate channels in two images at the end. - -@tool -extends Node - -const HT_Logger = preload("../../util/logger.gd") -const HT_Util = preload("../../util/util.gd") -const HT_NoBlendShader = preload("./no_blend.gdshader") -const HT_NoBlendRFShader = preload("./no_blend_rf.gdshader") - -const UNDO_CHUNK_SIZE = 64 - -# All painting shaders can use these common parameters -const SHADER_PARAM_SRC_TEXTURE = "u_src_texture" -const SHADER_PARAM_SRC_RECT = "u_src_rect" -const SHADER_PARAM_OPACITY = "u_opacity" - -const _API_SHADER_PARAMS = [ - SHADER_PARAM_SRC_TEXTURE, - SHADER_PARAM_SRC_RECT, - SHADER_PARAM_OPACITY -] - -# Emitted when a region of the painted texture actually changed. -# Note 1: the image might not have changed yet at this point. -# Note 2: the user could still be in the middle of dragging the brush. -signal texture_region_changed(rect) - -# Godot doesn't support 32-bit float rendering, so painting is limited to 16-bit depth. -# We should get this in Godot 4.0, either as Compute or renderer improvement -const _hdr_formats = [ - Image.FORMAT_RH, - Image.FORMAT_RGH, - Image.FORMAT_RGBH, - Image.FORMAT_RGBAH -] - -const _supported_formats = [ - Image.FORMAT_R8, - Image.FORMAT_RG8, - Image.FORMAT_RGB8, - Image.FORMAT_RGBA8 - # No longer supported since Godot 4 removed support for it in 2D viewports... -# Image.FORMAT_RH, -# Image.FORMAT_RGH, -# Image.FORMAT_RGBH, -# Image.FORMAT_RGBAH -] - -# - SubViewport (size of edited region + margin to allow quad rotation) -# |- Background -# | Fills pixels with unmodified source image. -# |- Brush sprite -# Size of actual brush, scaled/rotated, modifies source image. -# Assigned texture is the brush texture, src image is a shader param - -var _viewport : SubViewport -var _viewport_bg_sprite : Sprite2D -var _viewport_brush_sprite : Sprite2D -var _brush_size := 32 -var _brush_scale := 1.0 -var _brush_position := Vector2() -var _brush_opacity := 1.0 -var _brush_texture : Texture -var _last_brush_position := Vector2() -var _brush_material := ShaderMaterial.new() -var _no_blend_material : ShaderMaterial -var _image : Image -var _texture : ImageTexture -var _cmd_paint := false -var _pending_paint_render := false -var _modified_chunks := {} -var _modified_shader_params := {} - -var _debug_display : TextureRect -var _logger = HT_Logger.get_for(self) - - -func _init(): - _viewport = SubViewport.new() - _viewport.size = Vector2(_brush_size, _brush_size) - _viewport.render_target_update_mode = SubViewport.UPDATE_ONCE - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - #_viewport.hdr = false - # Require 4 components (RGBA) - _viewport.transparent_bg = true - # Apparently HDR doesn't work if this is set to 2D... so let's waste a depth buffer :/ - #_viewport.usage = Viewport.USAGE_2D - #_viewport.keep_3d_linear - - # There is no "blend_disabled" option on standard CanvasItemMaterial... - _no_blend_material = ShaderMaterial.new() - _no_blend_material.shader = HT_NoBlendShader - _viewport_bg_sprite = Sprite2D.new() - _viewport_bg_sprite.centered = false - _viewport_bg_sprite.material = _no_blend_material - _viewport.add_child(_viewport_bg_sprite) - - _viewport_brush_sprite = Sprite2D.new() - _viewport_brush_sprite.centered = true - _viewport_brush_sprite.material = _brush_material - _viewport_brush_sprite.position = _viewport.size / 2.0 - _viewport.add_child(_viewport_brush_sprite) - - add_child(_viewport) - - -func set_debug_display(dd: TextureRect): - _debug_display = dd - _debug_display.texture = _viewport.get_texture() - - -func set_image(image: Image, texture: ImageTexture): - assert((image == null and texture == null) or (image != null and texture != null)) - _image = image - _texture = texture - _viewport_bg_sprite.texture = _texture - _brush_material.set_shader_parameter(SHADER_PARAM_SRC_TEXTURE, _texture) - if image != null: - if image.get_format() == Image.FORMAT_RF: - # In case of RF all shaders must encode their fragment outputs in RGBA8, - # including the unmodified background, as Godot 4.0 does not support RF viewports - _no_blend_material.shader = HT_NoBlendRFShader - else: - _no_blend_material.shader = HT_NoBlendShader - # TODO HDR is required in order to paint heightmaps. - # Seems Godot 4.0 does not support it, so we have to wait for Godot 4.1... - #_viewport.hdr = image.get_format() in _hdr_formats - if (image.get_format() in _hdr_formats) and image.get_format() != Image.FORMAT_RF: - push_error("Godot 4.0 does not support HDR viewports for GPU-editing heightmaps! " + - "Only RF is supported using a bit packing hack.") - #print("PAINTER VIEWPORT HDR: ", _viewport.hdr) - - -# Sets the size of the brush in pixels. -# This will cause the internal viewport to resize, which is expensive. -# If you need to frequently change brush size during a paint stroke, prefer using scale instead. -func set_brush_size(new_size: int): - _brush_size = new_size - - -func get_brush_size() -> int: - return _brush_size - - -func set_brush_rotation(rotation: float): - _viewport_brush_sprite.rotation = rotation - - -func get_brush_rotation() -> float: - return _viewport_bg_sprite.rotation - - -# The difference between size and scale, is that size is in pixels, while scale is a multiplier. -# Scale is also a lot cheaper to change, so you may prefer changing it instead of size if that -# happens often during a painting stroke. -func set_brush_scale(s: float): - _brush_scale = clampf(s, 0.0, 1.0) - #_viewport_brush_sprite.scale = Vector2(s, s) - - -func get_brush_scale() -> float: - return _viewport_bg_sprite.scale.x - - -func set_brush_opacity(opacity: float): - _brush_opacity = clampf(opacity, 0.0, 1.0) - - -func get_brush_opacity() -> float: - return _brush_opacity - - -func set_brush_texture(texture: Texture): - _viewport_brush_sprite.texture = texture - - -func set_brush_shader(shader: Shader): - if _brush_material.shader != shader: - _brush_material.shader = shader - - -func set_brush_shader_param(p: String, v): - assert(not _API_SHADER_PARAMS.has(p)) - _modified_shader_params[p] = true - _brush_material.set_shader_parameter(p, v) - - -func clear_brush_shader_params(): - for key in _modified_shader_params: - _brush_material.set_shader_parameter(key, null) - _modified_shader_params.clear() - - -# If we want to be able to rotate the brush quad every frame, -# we must prepare a bigger viewport otherwise the quad will not fit inside -static func _get_size_fit_for_rotation(src_size: Vector2) -> Vector2i: - var d = int(ceilf(src_size.length())) - return Vector2i(d, d) - - -# You must call this from an `_input` function or similar. -func paint_input(center_pos: Vector2): - var vp_size := _get_size_fit_for_rotation(Vector2(_brush_size, _brush_size)) - if _viewport.size != vp_size: - # Do this lazily so the brush slider won't lag while adjusting it - # TODO An "sliding_ended" handling might produce better user experience - _viewport.size = vp_size - _viewport_brush_sprite.position = _viewport.size / 2.0 - - # Need to floor the position in case the brush has an odd size - var brush_pos := (center_pos - _viewport.size * 0.5).round() - _viewport.render_target_update_mode = SubViewport.UPDATE_ONCE - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - _viewport_bg_sprite.position = -brush_pos - _brush_position = brush_pos - _cmd_paint = true - - # We want this quad to have a specific size, regardless of the texture assigned to it - _viewport_brush_sprite.scale = \ - _brush_scale * Vector2(_brush_size, _brush_size) \ - / Vector2(_viewport_brush_sprite.texture.get_size()) - - # Using a Color because Godot doesn't understand vec4 - var rect := Color() - rect.r = brush_pos.x / _texture.get_width() - rect.g = brush_pos.y / _texture.get_height() - rect.b = float(_viewport.size.x) / float(_texture.get_width()) - rect.a = float(_viewport.size.y) / float(_texture.get_height()) - # In order to make sure that u_brush_rect is never bigger than the brush: - # 1. we ceil() the result of lower-left corner - # 2. we floor() the result of upper-right corner - # and then rederive width and height from the result -# var half_brush:Vector2 = Vector2(_brush_size, _brush_size) / 2 -# var brush_LL := (center_pos - half_brush).ceil() -# var brush_UR := (center_pos + half_brush).floor() -# rect.r = brush_LL.x / _texture.get_width() -# rect.g = brush_LL.y / _texture.get_height() -# rect.b = (brush_UR.x - brush_LL.x) / _texture.get_width() -# rect.a = (brush_UR.y - brush_LL.y) / _texture.get_height() - _brush_material.set_shader_parameter(SHADER_PARAM_SRC_RECT, rect) - _brush_material.set_shader_parameter(SHADER_PARAM_OPACITY, _brush_opacity) - - -# Don't commit until this is false -func is_operation_pending() -> bool: - return _pending_paint_render or _cmd_paint - - -# Applies changes to the Image, and returns modified chunks for UndoRedo. -func commit() -> Dictionary: - if is_operation_pending(): - _logger.error("Painter commit() was called while an operation is still pending") - return _commit_modified_chunks() - - -func has_modified_chunks() -> bool: - return len(_modified_chunks) > 0 - - -func _process(delta: float): - if _pending_paint_render: - _pending_paint_render = false - - #print("Paint result at frame ", Engine.get_frames_drawn()) - var viewport_image := _viewport.get_texture().get_image() - - if _image.get_format() == Image.FORMAT_RF: - # Reinterpret RGBA8 as RF. This assumes painting shaders encode the output properly. - assert(viewport_image.get_format() == Image.FORMAT_RGBA8) - viewport_image = Image.create_from_data( - viewport_image.get_width(), viewport_image.get_height(), false, Image.FORMAT_RF, - viewport_image.get_data()) - else: - viewport_image.convert(_image.get_format()) - - var brush_pos := _last_brush_position - - var dst_x : int = clamp(brush_pos.x, 0, _texture.get_width()) - var dst_y : int = clamp(brush_pos.y, 0, _texture.get_height()) - - var src_x : int = maxf(-brush_pos.x, 0) - var src_y : int = maxf(-brush_pos.y, 0) - var src_w : int = minf(maxf(_viewport.size.x - src_x, 0), _texture.get_width() - dst_x) - var src_h : int = minf(maxf(_viewport.size.y - src_y, 0), _texture.get_height() - dst_y) - - if src_w != 0 and src_h != 0: - _mark_modified_chunks(dst_x, dst_y, src_w, src_h) - HT_Util.update_texture_partial(_texture, viewport_image, - Rect2i(src_x, src_y, src_w, src_h), Vector2i(dst_x, dst_y)) - texture_region_changed.emit(Rect2(dst_x, dst_y, src_w, src_h)) - - # Input is handled just before process, so we still have to wait till next frame - if _cmd_paint: - _pending_paint_render = true - _last_brush_position = _brush_position - # Consume input - _cmd_paint = false - - -func _mark_modified_chunks(bx: int, by: int, bw: int, bh: int): - var cs := UNDO_CHUNK_SIZE - - var cmin_x := bx / cs - var cmin_y := by / cs - var cmax_x := (bx + bw - 1) / cs + 1 - var cmax_y := (by + bh - 1) / cs + 1 - - for cy in range(cmin_y, cmax_y): - for cx in range(cmin_x, cmax_x): - #print("Marking chunk ", Vector2(cx, cy)) - _modified_chunks[Vector2(cx, cy)] = true - - -func _commit_modified_chunks() -> Dictionary: - var time_before := Time.get_ticks_msec() - - var cs := UNDO_CHUNK_SIZE - var chunks_positions := [] - var chunks_initial_data := [] - var chunks_final_data := [] - - #_logger.debug("About to commit ", len(_modified_chunks), " chunks") - - # TODO get_data_partial() would be nice... - var final_image := _texture.get_image() - for cpos in _modified_chunks: - var cx : int = cpos.x - var cy : int = cpos.y - - var x := cx * cs - var y := cy * cs - var w : int = mini(cs, _image.get_width() - x) - var h : int = mini(cs, _image.get_height() - y) - - var rect := Rect2i(x, y, w, h) - var initial_data := _image.get_region(rect) - var final_data := final_image.get_region(rect) - - chunks_positions.append(cpos) - chunks_initial_data.append(initial_data) - chunks_final_data.append(final_data) - #_image_equals(initial_data, final_data) - - # TODO We could also just replace the image with `final_image`... - # TODO Use `final_data` instead? - _image.blit_rect(final_image, rect, rect.position) - - _modified_chunks.clear() - - var time_spent := Time.get_ticks_msec() - time_before - _logger.debug("Spent {0} ms to commit paint operation".format([time_spent])) - - return { - "chunk_positions": chunks_positions, - "chunk_initial_datas": chunks_initial_data, - "chunk_final_datas": chunks_final_data - } - - -# DEBUG -#func _input(event): -# if event is InputEventKey: -# if event.pressed: -# if event.control and event.scancode == KEY_SPACE: -# print("Saving painter viewport ", name) -# var im = _viewport.get_texture().get_data() -# im.convert(Image.FORMAT_RGBA8) -# im.save_png(str("test_painter_viewport_", name, ".png")) - - -#static func _image_equals(im_a: Image, im_b: Image) -> bool: -# if im_a.get_size() != im_b.get_size(): -# print("Diff size: ", im_a.get_size, ", ", im_b.get_size()) -# return false -# if im_a.get_format() != im_b.get_format(): -# print("Diff format: ", im_a.get_format(), ", ", im_b.get_format()) -# return false -# im_a.lock() -# im_b.lock() -# for y in im_a.get_height(): -# for x in im_a.get_width(): -# var ca = im_a.get_pixel(x, y) -# var cb = im_b.get_pixel(x, y) -# if ca != cb: -# print("Diff pixel ", x, ", ", y) -# return false -# im_a.unlock() -# im_b.unlock() -# print("SAME") -# return true diff --git a/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd b/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd deleted file mode 100644 index 71f81d1..0000000 --- a/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd +++ /dev/null @@ -1,280 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../../util/util.gd") -const HT_Brush = preload("../brush.gd") -const HT_Logger = preload("../../../util/logger.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_SpinSlider = preload("../../util/spin_slider.gd") -const HT_Scratchpad = preload("./preview_scratchpad.gd") - -@onready var _scratchpad : HT_Scratchpad = $VB/HB/VB3/PreviewScratchpad - -@onready var _shape_list : ItemList = $VB/HB/VB/ShapeList -@onready var _remove_shape_button : Button = $VB/HB/VB/HBoxContainer/RemoveShape -@onready var _change_shape_button : Button = $VB/HB/VB/ChangeShape - -@onready var _size_slider : HT_SpinSlider = $VB/HB/VB2/Settings/Size -@onready var _opacity_slider : HT_SpinSlider = $VB/HB/VB2/Settings/Opacity -@onready var _pressure_enabled_checkbox : CheckBox = $VB/HB/VB2/Settings/PressureEnabled -@onready var _pressure_over_size_slider : HT_SpinSlider = $VB/HB/VB2/Settings/PressureOverSize -@onready var _pressure_over_opacity_slider : HT_SpinSlider = $VB/HB/VB2/Settings/PressureOverOpacity -@onready var _frequency_distance_slider : HT_SpinSlider = $VB/HB/VB2/Settings/FrequencyDistance -@onready var _frequency_time_slider : HT_SpinSlider = $VB/HB/VB2/Settings/FrequencyTime -@onready var _random_rotation_checkbox : CheckBox = $VB/HB/VB2/Settings/RandomRotation -@onready var _shape_cycling_checkbox : CheckBox = $VB/HB/VB2/Settings/ShapeCycling - -var _brush : HT_Brush -# This is a `EditorFileDialog`, -# but cannot type it because I want to be able to test it by running the scene. -# And when I run it, Godot does not allow to use `EditorFileDialog`. -var _load_image_dialog -# -1 means add, otherwise replace -var _load_image_index := -1 -var _logger = HT_Logger.get_for(self) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - _size_slider.set_max_value(HT_Brush.MAX_SIZE_FOR_SLIDERS) - _size_slider.set_greater_max_value(HT_Brush.MAX_SIZE) - - # TESTING - if not Engine.is_editor_hint(): - setup_dialogs(self) - call_deferred("popup") - - -func set_brush(brush : HT_Brush): - assert(brush != null) - _brush = brush - _update_controls_from_brush() - - -# `base_control` can no longer be hinted as a `Control` because in Godot 4 it could be a -# window or dialog, which are no longer controls... -func setup_dialogs(base_control: Node): - assert(_load_image_dialog == null) - _load_image_dialog = HT_EditorUtil.create_open_file_dialog() - _load_image_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - _load_image_dialog.add_filter("*.exr ; EXR files") - _load_image_dialog.unresizable = false - _load_image_dialog.access = EditorFileDialog.ACCESS_FILESYSTEM - _load_image_dialog.current_dir = HT_Brush.SHAPES_DIR - _load_image_dialog.file_selected.connect(_on_LoadImageDialog_file_selected) - _load_image_dialog.files_selected.connect(_on_LoadImageDialog_files_selected) - #base_control.add_child(_load_image_dialog) - # When a dialog opens another dialog, we get this error: - # "Transient parent has another exclusive child." - # Which is worked around by making the other dialog a child of the first one (I don't know why) - add_child(_load_image_dialog) - - -func _exit_tree(): - if _load_image_dialog != null: - _load_image_dialog.queue_free() - _load_image_dialog = null - - -func _get_shapes_from_gui() -> Array[Texture2D]: - var shapes : Array[Texture2D] = [] - for i in _shape_list.get_item_count(): - var icon : Texture2D = _shape_list.get_item_icon(i) - assert(icon != null) - shapes.append(icon) - return shapes - - -func _update_shapes_gui(shapes: Array[Texture2D]): - _shape_list.clear() - for shape in shapes: - assert(shape != null) - assert(shape is Texture2D) - _shape_list.add_icon_item(shape) - _update_shape_list_buttons() - - -func _on_AddShape_pressed(): - _load_image_index = -1 - _load_image_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILES - _load_image_dialog.popup_centered_ratio(0.7) - - -func _on_RemoveShape_pressed(): - var selected_indices := _shape_list.get_selected_items() - if len(selected_indices) == 0: - return - - var index : int = selected_indices[0] - _shape_list.remove_item(index) - - var shapes := _get_shapes_from_gui() - for brush in _get_brushes(): - brush.set_shapes(shapes) - - _update_shape_list_buttons() - - -func _on_ShapeList_item_activated(index: int): - _request_modify_shape(index) - - -func _on_ChangeShape_pressed(): - var selected = _shape_list.get_selected_items() - if len(selected) == 0: - return - _request_modify_shape(selected[0]) - - -func _request_modify_shape(index: int): - _load_image_index = index - _load_image_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - _load_image_dialog.popup_centered_ratio(0.7) - - -func _on_LoadImageDialog_files_selected(fpaths: PackedStringArray): - var shapes := _get_shapes_from_gui() - - for fpath in fpaths: - var tex := HT_Brush.load_shape_from_image_file(fpath, _logger) - if tex == null: - # Failed - continue - shapes.append(tex) - - for brush in _get_brushes(): - brush.set_shapes(shapes) - - _update_shapes_gui(shapes) - - -func _on_LoadImageDialog_file_selected(fpath: String): - var tex := HT_Brush.load_shape_from_image_file(fpath, _logger) - if tex == null: - # Failed - return - - var shapes := _get_shapes_from_gui() - if _load_image_index == -1 or _load_image_index >= len(shapes): - # Add - shapes.append(tex) - else: - # Replace - assert(_load_image_index >= 0) - shapes[_load_image_index] = tex - - for brush in _get_brushes(): - brush.set_shapes(shapes) - - _update_shapes_gui(shapes) - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - # Testing the scratchpad because visibility can not only change before entering the tree - # since Godot 4 port, it can also change between entering the tree and being _ready... - if visible and _scratchpad != null: - _update_controls_from_brush() - - -func _update_controls_from_brush(): - var brush := _brush - - if brush == null: - # To allow testing - brush = _scratchpad.get_painter().get_brush() - - _update_shapes_gui(brush.get_shapes()) - - _size_slider.set_value(brush.get_size(), false) - _opacity_slider.set_value(brush.get_opacity() * 100.0, false) - _pressure_enabled_checkbox.button_pressed = brush.is_pressure_enabled() - _pressure_over_size_slider.set_value(brush.get_pressure_over_scale() * 100.0, false) - _pressure_over_opacity_slider.set_value(brush.get_pressure_over_opacity() * 100.0, false) - _frequency_distance_slider.set_value(brush.get_frequency_distance(), false) - _frequency_time_slider.set_value( - 1000.0 / maxf(0.1, float(brush.get_frequency_time_ms())), false) - _random_rotation_checkbox.button_pressed = brush.is_random_rotation_enabled() - _shape_cycling_checkbox.button_pressed = brush.is_shape_cycling_enabled() - - -func _on_ClearScratchpad_pressed(): - _scratchpad.reset_image() - - -func _on_Size_value_changed(value: float): - for brush in _get_brushes(): - brush.set_size(value) - - -func _on_Opacity_value_changed(value): - for brush in _get_brushes(): - brush.set_opacity(value / 100.0) - - -func _on_PressureEnabled_toggled(button_pressed): - for brush in _get_brushes(): - brush.set_pressure_enabled(button_pressed) - - -func _on_PressureOverSize_value_changed(value): - for brush in _get_brushes(): - brush.set_pressure_over_scale(value / 100.0) - - -func _on_PressureOverOpacity_value_changed(value): - for brush in _get_brushes(): - brush.set_pressure_over_opacity(value / 100.0) - - -func _on_FrequencyDistance_value_changed(value): - for brush in _get_brushes(): - brush.set_frequency_distance(value) - - -func _on_FrequencyTime_value_changed(fps): - fps = max(1.0, fps) - var ms = 1000.0 / fps - if is_equal_approx(fps, 60.0): - ms = 0 - for brush in _get_brushes(): - brush.set_frequency_time_ms(ms) - - -func _on_RandomRotation_toggled(button_pressed: bool): - for brush in _get_brushes(): - brush.set_random_rotation_enabled(button_pressed) - - -func _on_shape_cycling_toggled(button_pressed: bool): - for brush in _get_brushes(): - brush.set_shape_cycling_enabled(button_pressed) - - -func _get_brushes() -> Array[HT_Brush]: - if _brush != null: - # We edit both the preview brush and the terrain brush - # TODO Could we simply share the brush? - return [_brush, _scratchpad.get_painter().get_brush()] - # When testing the dialog in isolation, the edited brush might be null - return [_scratchpad.get_painter().get_brush()] - - -func _on_ShapeList_item_selected(index): - _update_shape_list_buttons() - for brush in _get_brushes(): - brush.set_shape_index(index) - - -func _update_shape_list_buttons(): - var selected_count := len(_shape_list.get_selected_items()) - # There must be at least one shape - _remove_shape_button.disabled = _shape_list.get_item_count() == 1 or selected_count == 0 - _change_shape_button.disabled = selected_count == 0 - - -func _on_shape_list_empty_clicked(at_position, mouse_button_index): - _update_shape_list_buttons() - diff --git a/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.tscn b/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.tscn deleted file mode 100644 index 7d7e07d..0000000 --- a/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.tscn +++ /dev/null @@ -1,211 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://d2rt3wj8xkhp2"] - -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/spin_slider.tscn" id="2"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd" id="3"] -[ext_resource type="PackedScene" uid="uid://ng00jipfeucy" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn" id="4"] - -[node name="BrushSettingsDialog" type="AcceptDialog"] -title = "Brush settings" -size = Vector2i(700, 422) -min_size = Vector2i(700, 400) -script = ExtResource("3") - -[node name="VB" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -49.0 - -[node name="HB" type="HBoxContainer" parent="VB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VB" type="VBoxContainer" parent="VB/HB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Label" type="Label" parent="VB/HB/VB"] -layout_mode = 2 -text = "Shapes" - -[node name="ShapeList" type="ItemList" parent="VB/HB/VB"] -layout_mode = 2 -size_flags_vertical = 3 -fixed_icon_size = Vector2i(100, 100) - -[node name="ChangeShape" type="Button" parent="VB/HB/VB"] -layout_mode = 2 -disabled = true -text = "Change..." - -[node name="HBoxContainer" type="HBoxContainer" parent="VB/HB/VB"] -layout_mode = 2 - -[node name="AddShape" type="Button" parent="VB/HB/VB/HBoxContainer"] -layout_mode = 2 -text = "Add..." - -[node name="RemoveShape" type="Button" parent="VB/HB/VB/HBoxContainer"] -layout_mode = 2 -disabled = true -text = "Remove" - -[node name="VB2" type="VBoxContainer" parent="VB/HB"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Label" type="Label" parent="VB/HB/VB2"] -layout_mode = 2 - -[node name="Settings" type="VBoxContainer" parent="VB/HB/VB2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Size" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -size_flags_horizontal = 3 -value = 32.0 -min_value = 2.0 -max_value = 500.0 -prefix = "Size:" -suffix = "px" -rounded = true -centered = true -allow_greater = true -greater_max_value = 4000.0 - -[node name="Opacity" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -size_flags_horizontal = 3 -value = 100.0 -max_value = 100.0 -prefix = "Opacity" -suffix = "%" -rounded = true -centered = true -greater_max_value = 10000.0 - -[node name="PressureEnabled" type="CheckBox" parent="VB/HB/VB2/Settings"] -layout_mode = 2 -text = "Enable pressure (pen tablets)" - -[node name="PressureOverSize" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -value = 50.0 -max_value = 100.0 -prefix = "Pressure affects size:" -suffix = "%" -centered = true -greater_max_value = 10000.0 - -[node name="PressureOverOpacity" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -value = 50.0 -max_value = 100.0 -prefix = "Pressure affects opacity:" -suffix = "%" -centered = true -greater_max_value = 10000.0 - -[node name="FrequencyTime" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -value = 60.0 -min_value = 1.0 -max_value = 60.0 -prefix = "Frequency time:" -suffix = "fps" -centered = true -greater_max_value = 10000.0 - -[node name="FrequencyDistance" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -max_value = 100.0 -prefix = "Frequency distance:" -suffix = "px" -centered = true -greater_max_value = 4000.0 - -[node name="RandomRotation" type="CheckBox" parent="VB/HB/VB2/Settings"] -layout_mode = 2 -text = "Random rotation" - -[node name="ShapeCycling" type="CheckBox" parent="VB/HB/VB2/Settings"] -layout_mode = 2 -text = "Shape cycling" - -[node name="HSeparator" type="HSeparator" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="SizeLimitHB" type="HBoxContainer" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/HB/VB2/Settings/SizeLimitHB"] -layout_mode = 2 -mouse_filter = 0 -text = "Size limit:" - -[node name="SizeLimit" type="SpinBox" parent="VB/HB/VB2/Settings/SizeLimitHB"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = 1.0 -max_value = 1000.0 -value = 200.0 - -[node name="HSeparator2" type="HSeparator" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="Button" type="Button" parent="VB/HB/VB2/Settings/HB"] -layout_mode = 2 -text = "Load preset..." - -[node name="Button2" type="Button" parent="VB/HB/VB2/Settings/HB"] -layout_mode = 2 -text = "Save preset..." - -[node name="VB3" type="VBoxContainer" parent="VB/HB"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/HB/VB3"] -layout_mode = 2 -text = "Scratchpad" - -[node name="PreviewScratchpad" parent="VB/HB/VB3" instance=ExtResource("4")] -custom_minimum_size = Vector2(200, 300) -layout_mode = 2 - -[node name="ClearScratchpad" type="Button" parent="VB/HB/VB3"] -layout_mode = 2 -text = "Clear" - -[connection signal="empty_clicked" from="VB/HB/VB/ShapeList" to="." method="_on_shape_list_empty_clicked"] -[connection signal="item_activated" from="VB/HB/VB/ShapeList" to="." method="_on_ShapeList_item_activated"] -[connection signal="item_selected" from="VB/HB/VB/ShapeList" to="." method="_on_ShapeList_item_selected"] -[connection signal="pressed" from="VB/HB/VB/ChangeShape" to="." method="_on_ChangeShape_pressed"] -[connection signal="pressed" from="VB/HB/VB/HBoxContainer/AddShape" to="." method="_on_AddShape_pressed"] -[connection signal="pressed" from="VB/HB/VB/HBoxContainer/RemoveShape" to="." method="_on_RemoveShape_pressed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/Size" to="." method="_on_Size_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/Opacity" to="." method="_on_Opacity_value_changed"] -[connection signal="toggled" from="VB/HB/VB2/Settings/PressureEnabled" to="." method="_on_PressureEnabled_toggled"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/PressureOverSize" to="." method="_on_PressureOverSize_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/PressureOverOpacity" to="." method="_on_PressureOverOpacity_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/FrequencyTime" to="." method="_on_FrequencyTime_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/FrequencyDistance" to="." method="_on_FrequencyDistance_value_changed"] -[connection signal="toggled" from="VB/HB/VB2/Settings/RandomRotation" to="." method="_on_RandomRotation_toggled"] -[connection signal="toggled" from="VB/HB/VB2/Settings/ShapeCycling" to="." method="_on_shape_cycling_toggled"] -[connection signal="pressed" from="VB/HB/VB3/ClearScratchpad" to="." method="_on_ClearScratchpad_pressed"] diff --git a/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd b/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd deleted file mode 100644 index be52072..0000000 --- a/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd +++ /dev/null @@ -1,41 +0,0 @@ -@tool -extends Node - -const HT_Painter = preload("./../painter.gd") -const HT_Brush = preload("./../brush.gd") - -const HT_ColorShader = preload("../shaders/color.gdshader") - -var _painter : HT_Painter -var _brush : HT_Brush - - -func _init(): - var p = HT_Painter.new() - # The name is just for debugging - p.set_name("Painter") - add_child(p) - _painter = p - - _brush = HT_Brush.new() - - -func set_image_texture(image: Image, texture: ImageTexture): - _painter.set_image(image, texture) - - -func get_brush() -> HT_Brush: - return _brush - - -# This may be called from an `_input` callback -func paint_input(position: Vector2, pressure: float): - var p : HT_Painter = _painter - - if not _brush.configure_paint_input([p], position, pressure): - return - - p.set_brush_shader(HT_ColorShader) - p.set_brush_shader_param("u_color", Color(0,0,0,1)) - #p.set_image(_image, _texture) - p.paint_input(position) diff --git a/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd b/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd deleted file mode 100644 index cec0728..0000000 --- a/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd +++ /dev/null @@ -1,70 +0,0 @@ -@tool -extends Control - -const HT_PreviewPainter = preload("./preview_painter.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_DefaultBrushTexture = preload("../shapes/round2.exr") -const HT_Brush = preload("../brush.gd") -const HT_Logger = preload("../../../util/logger.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_Util = preload("../../../util/util.gd") - -@onready var _texture_rect : TextureRect = $TextureRect -@onready var _painter : HT_PreviewPainter = $Painter - -var _logger := HT_Logger.get_for(self) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - # If it runs in the edited scene, - # saving the scene would also save the ImageTexture in it... - return - reset_image() - # Default so it doesn't crash when painting and can be tested - var default_brush_texture = \ - HT_EditorUtil.load_texture(HT_Brush.DEFAULT_BRUSH_TEXTURE_PATH, _logger) - _painter.get_brush().set_shapes([default_brush_texture]) - - -func reset_image(): - var image = Image.create(_texture_rect.size.x, _texture_rect.size.y, false, Image.FORMAT_RGB8) - image.fill(Color(1,1,1)) - - # TEST -# var fnl = FastNoiseLite.new() -# for y in image.get_height(): -# for x in image.get_width(): -# var g = 0.5 + 0.5 * fnl.get_noise_2d(x, y) -# image.set_pixel(x, y, Color(g, g, g, 1.0)) - - var texture = ImageTexture.create_from_image(image) - _texture_rect.texture = texture - _painter.set_image_texture(image, texture) - - -func get_painter() -> HT_PreviewPainter: - return _painter - - -func _gui_input(event): - if event is InputEventMouseMotion: - if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): - _painter.paint_input(event.position, event.pressure) - queue_redraw() - - elif event is InputEventMouseButton: - if event.button_index == MOUSE_BUTTON_LEFT: - if event.pressed: - # TODO `pressure` is not available on button events - # So I have to assume zero... which means clicks do not paint anything? - _painter.paint_input(event.position, 0.0) - else: - _painter.get_brush().on_paint_end() - - -func _draw(): - var mpos = get_local_mouse_position() - var brush = _painter.get_brush() - draw_arc(mpos, 0.5 * brush.get_size(), -PI, PI, 32, Color(1, 0.2, 0.2), 2.0, true) - diff --git a/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn b/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn deleted file mode 100644 index 0b50c91..0000000 --- a/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn +++ /dev/null @@ -1,22 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://ng00jipfeucy"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd" id="1"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd" id="2"] - -[node name="PreviewScratchpad" type="Control"] -clip_contents = true -layout_mode = 3 -anchors_preset = 0 -offset_right = 200.0 -offset_bottom = 274.0 -script = ExtResource("1") - -[node name="Painter" type="Node" parent="."] -script = ExtResource("2") - -[node name="TextureRect" type="TextureRect" parent="."] -show_behind_parent = true -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -stretch_mode = 5 diff --git a/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader b/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader deleted file mode 100644 index f8a05c5..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader +++ /dev/null @@ -1,19 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_value = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec4 src = texture(u_src_texture, get_src_uv(SCREEN_UV)); - COLOR = vec4(src.rgb, mix(src.a, u_value, brush_value)); -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/color.gdshader b/addons/zylann.hterrain/tools/brush/shaders/color.gdshader deleted file mode 100644 index eec65f5..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/color.gdshader +++ /dev/null @@ -1,68 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_color = vec4(1.0); -uniform sampler2D u_heightmap; -uniform float u_normal_min_y = 0.0; -uniform float u_normal_max_y = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -vec3 get_normal(sampler2D heightmap, vec2 pos) { - vec2 ps = vec2(1.0) / vec2(textureSize(heightmap, 0)); - float hnx = get_height(heightmap, pos + vec2(-ps.x, 0.0)); - float hpx = get_height(heightmap, pos + vec2(ps.x, 0.0)); - float hny = get_height(heightmap, pos + vec2(0.0, -ps.y)); - float hpy = get_height(heightmap, pos + vec2(0.0, ps.y)); - return normalize(vec3(hnx - hpx, 2.0, hpy - hny)); -} - -// Limits painting based on the slope, with a bit of falloff -float apply_slope_limit(float brush_value, vec3 normal, float normal_min_y, float normal_max_y) { - float normal_falloff = 0.2; - - // If an edge is at min/max, make sure it won't be affected by falloff - normal_min_y = normal_min_y <= 0.0 ? -2.0 : normal_min_y; - normal_max_y = normal_max_y >= 1.0 ? 2.0 : normal_max_y; - - brush_value *= 1.0 - smoothstep( - normal_max_y - normal_falloff, - normal_max_y + normal_falloff, normal.y); - - brush_value *= smoothstep( - normal_min_y - normal_falloff, - normal_min_y + normal_falloff, normal.y); - - return brush_value; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec3 normal = get_normal(u_heightmap, src_uv); - brush_value = apply_slope_limit(brush_value, normal, u_normal_min_y, u_normal_max_y); - - vec4 src = texture(u_src_texture, src_uv); - - // Despite hints, albedo textures render darker. - // Trying to undo sRGB does not work because of 8-bit precision loss - // that would occur either in texture, or on the source image. - // So it's not possible to use viewports to paint albedo... - //src.rgb = pow(src.rgb, vec3(0.4545)); - - vec4 col = vec4(mix(src.rgb, u_color.rgb, brush_value), src.a); - COLOR = col; -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader b/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader deleted file mode 100644 index 669f4d7..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader +++ /dev/null @@ -1,64 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_color = vec4(1.0); - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -// float get_noise(vec2 pos) { -// return fract(sin(dot(pos.xy ,vec2(12.9898,78.233))) * 43758.5453); -// } - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -float erode(sampler2D heightmap, vec2 uv, vec2 pixel_size, float weight) { - float r = 3.0; - - // Divide so the shader stays neighbor dependent 1 pixel across. - // For this to work, filtering must be enabled. - vec2 eps = pixel_size / (0.99 * r); - - float h = get_height(heightmap, uv); - float eh = h; - //float dh = h; - - // Morphology with circular structuring element - for (float y = -r; y <= r; ++y) { - for (float x = -r; x <= r; ++x) { - - vec2 p = vec2(x, y); - float nh = get_height(heightmap, uv + p * eps); - - float s = max(length(p) - r, 0); - eh = min(eh, nh + s); - - //s = min(r - length(p), 0); - //dh = max(dh, nh + s); - } - } - - eh = mix(h, eh, weight); - //dh = mix(h, dh, u_weight); - - float ph = eh;//mix(eh, dh, u_dilation); - - return ph; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - vec2 src_pixel_size = 1.0 / vec2(textureSize(u_src_texture, 0)); - float ph = erode(u_src_texture, get_src_uv(SCREEN_UV), src_pixel_size, brush_value); - //ph += brush_value * 0.35; - COLOR = encode_height_to_viewport(ph); -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader b/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader deleted file mode 100644 index c51f03a..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader +++ /dev/null @@ -1,22 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_flatten_value; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - float src_h = sample_heightmap(u_src_texture, get_src_uv(SCREEN_UV)); - float h = mix(src_h, u_flatten_value, brush_value); - COLOR = encode_height_to_viewport(h); -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/level.gdshader b/addons/zylann.hterrain/tools/brush/shaders/level.gdshader deleted file mode 100644 index 4721b43..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/level.gdshader +++ /dev/null @@ -1,45 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_factor = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -// TODO Could actually level to whatever height the brush was at the beginning of the stroke? - -void fragment() { - float brush_value = u_factor * u_opacity * texture(TEXTURE, UV).r; - - // The heightmap does not have mipmaps, - // so we need to use an approximation of average. - // This is not a very good one though... - float dst_h = 0.0; - vec2 uv_min = vec2(u_src_rect.xy); - vec2 uv_max = vec2(u_src_rect.xy + u_src_rect.zw); - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 5; ++j) { - float x = mix(uv_min.x, uv_max.x, float(i) / 4.0); - float y = mix(uv_min.y, uv_max.y, float(j) / 4.0); - float h = get_height(u_src_texture, vec2(x, y)); - dst_h += h; - } - } - dst_h /= (5.0 * 5.0); - - // TODO I have no idea if this will check out - float src_h = get_height(u_src_texture, get_src_uv(SCREEN_UV)); - float h = mix(src_h, dst_h, brush_value); - COLOR = encode_height_to_viewport(h); -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader b/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader deleted file mode 100644 index 10ee982..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader +++ /dev/null @@ -1,22 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_factor = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_factor * u_opacity * texture(TEXTURE, UV).r; - - float src_h = sample_heightmap(u_src_texture, get_src_uv(SCREEN_UV)); - float h = src_h + brush_value; - COLOR = encode_height_to_viewport(h); -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader b/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader deleted file mode 100644 index 27123e4..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader +++ /dev/null @@ -1,34 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_factor = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -void fragment() { - float brush_value = u_factor * u_opacity * texture(TEXTURE, UV).r; - - vec2 src_pixel_size = 1.0 / vec2(textureSize(u_src_texture, 0)); - vec2 src_uv = get_src_uv(SCREEN_UV); - vec2 offset = src_pixel_size; - float src_nx = get_height(u_src_texture, src_uv - vec2(offset.x, 0.0)); - float src_px = get_height(u_src_texture, src_uv + vec2(offset.x, 0.0)); - float src_ny = get_height(u_src_texture, src_uv - vec2(0.0, offset.y)); - float src_py = get_height(u_src_texture, src_uv + vec2(0.0, offset.y)); - float src_h = get_height(u_src_texture, src_uv); - float dst_h = (src_h + src_nx + src_px + src_ny + src_py) * 0.2; - float h = mix(src_h, dst_h, brush_value); - COLOR = encode_height_to_viewport(h); -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader b/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader deleted file mode 100644 index 68ebaa8..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader +++ /dev/null @@ -1,81 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_splat = vec4(1.0, 0.0, 0.0, 0.0); -uniform sampler2D u_other_splatmap_1; -uniform sampler2D u_other_splatmap_2; -uniform sampler2D u_other_splatmap_3; -uniform sampler2D u_heightmap; -uniform float u_normal_min_y = 0.0; -uniform float u_normal_max_y = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float sum(vec4 v) { - return v.x + v.y + v.z + v.w; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -vec3 get_normal(sampler2D heightmap, vec2 pos) { - vec2 ps = vec2(1.0) / vec2(textureSize(heightmap, 0)); - float hnx = get_height(heightmap, pos + vec2(-ps.x, 0.0)); - float hpx = get_height(heightmap, pos + vec2(ps.x, 0.0)); - float hny = get_height(heightmap, pos + vec2(0.0, -ps.y)); - float hpy = get_height(heightmap, pos + vec2(0.0, ps.y)); - return normalize(vec3(hnx - hpx, 2.0, hpy - hny)); -} - -// Limits painting based on the slope, with a bit of falloff -float apply_slope_limit(float brush_value, vec3 normal, float normal_min_y, float normal_max_y) { - float normal_falloff = 0.2; - - // If an edge is at min/max, make sure it won't be affected by falloff - normal_min_y = normal_min_y <= 0.0 ? -2.0 : normal_min_y; - normal_max_y = normal_max_y >= 1.0 ? 2.0 : normal_max_y; - - brush_value *= 1.0 - smoothstep( - normal_max_y - normal_falloff, - normal_max_y + normal_falloff, normal.y); - - brush_value *= smoothstep( - normal_min_y - normal_falloff, - normal_min_y + normal_falloff, normal.y); - - return brush_value; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec3 normal = get_normal(u_heightmap, src_uv); - brush_value = apply_slope_limit(brush_value, normal, u_normal_min_y, u_normal_max_y); - - // It is assumed 3 other renders are done the same with the other 3 - vec4 src0 = texture(u_src_texture, src_uv); - vec4 src1 = texture(u_other_splatmap_1, src_uv); - vec4 src2 = texture(u_other_splatmap_2, src_uv); - vec4 src3 = texture(u_other_splatmap_3, src_uv); - float t = brush_value; - vec4 s0 = mix(src0, u_splat, t); - vec4 s1 = mix(src1, vec4(0.0), t); - vec4 s2 = mix(src2, vec4(0.0), t); - vec4 s3 = mix(src3, vec4(0.0), t); - float sum = sum(s0) + sum(s1) + sum(s2) + sum(s3); - s0 /= sum; - s1 /= sum; - s2 /= sum; - s3 /= sum; - COLOR = s0; -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader b/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader deleted file mode 100644 index 1291dbd..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader +++ /dev/null @@ -1,63 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_splat = vec4(1.0, 0.0, 0.0, 0.0); -uniform sampler2D u_heightmap; -uniform float u_normal_min_y = 0.0; -uniform float u_normal_max_y = 1.0; -//uniform float u_normal_falloff = 0.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -vec3 get_normal(sampler2D heightmap, vec2 pos) { - vec2 ps = vec2(1.0) / vec2(textureSize(heightmap, 0)); - float hnx = get_height(heightmap, pos + vec2(-ps.x, 0.0)); - float hpx = get_height(heightmap, pos + vec2(ps.x, 0.0)); - float hny = get_height(heightmap, pos + vec2(0.0, -ps.y)); - float hpy = get_height(heightmap, pos + vec2(0.0, ps.y)); - return normalize(vec3(hnx - hpx, 2.0, hpy - hny)); -} - -// Limits painting based on the slope, with a bit of falloff -float apply_slope_limit(float brush_value, vec3 normal, float normal_min_y, float normal_max_y) { - float normal_falloff = 0.2; - - // If an edge is at min/max, make sure it won't be affected by falloff - normal_min_y = normal_min_y <= 0.0 ? -2.0 : normal_min_y; - normal_max_y = normal_max_y >= 1.0 ? 2.0 : normal_max_y; - - brush_value *= 1.0 - smoothstep( - normal_max_y - normal_falloff, - normal_max_y + normal_falloff, normal.y); - - brush_value *= smoothstep( - normal_min_y - normal_falloff, - normal_min_y + normal_falloff, normal.y); - - return brush_value; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec3 normal = get_normal(u_heightmap, src_uv); - brush_value = apply_slope_limit(brush_value, normal, u_normal_min_y, u_normal_max_y); - - vec4 src_splat = texture(u_src_texture, src_uv); - vec4 s = mix(src_splat, u_splat, brush_value); - s = s / (s.r + s.g + s.b + s.a); - COLOR = s; -} diff --git a/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader b/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader deleted file mode 100644 index 9828068..0000000 --- a/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader +++ /dev/null @@ -1,89 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform int u_texture_index; -uniform int u_mode; // 0: output index, 1: output weight -uniform sampler2D u_index_map; -uniform sampler2D u_weight_map; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec4 iv = texture(u_index_map, src_uv); - vec4 wv = texture(u_weight_map, src_uv); - - float i[3] = {iv.r, iv.g, iv.b}; - float w[3] = {wv.r, wv.g, wv.b}; - - if (brush_value > 0.0) { - float texture_index_f = float(u_texture_index) / 255.0; - int ci = u_texture_index % 3; - - float cm[3] = {-1.0, -1.0, -1.0}; - cm[ci] = 1.0; - - // Decompress third weight to make computations easier - w[2] = 1.0 - w[0] - w[1]; - - if (abs(i[ci] - texture_index_f) > 0.001) { - // Pixel does not have our texture index, - // transfer its weight to other components first - if (w[ci] > brush_value) { - w[0] -= cm[0] * brush_value; - w[1] -= cm[1] * brush_value; - w[2] -= cm[2] * brush_value; - - } else if (w[ci] >= 0.f) { - w[ci] = 0.f; - i[ci] = texture_index_f; - } - - } else { - // Pixel has our texture index, increase its weight - if (w[ci] + brush_value < 1.f) { - w[0] += cm[0] * brush_value; - w[1] += cm[1] * brush_value; - w[2] += cm[2] * brush_value; - - } else { - // Pixel weight is full, we can set all components to the same index. - // Need to nullify other weights because they would otherwise never reach - // zero due to normalization - w[0] = 0.0; - w[1] = 0.0; - w[2] = 0.0; - - w[ci] = 1.0; - - i[0] = texture_index_f; - i[1] = texture_index_f; - i[2] = texture_index_f; - } - } - - w[0] = clamp(w[0], 0.0, 1.0); - w[1] = clamp(w[1], 0.0, 1.0); - w[2] = clamp(w[2], 0.0, 1.0); - - // Renormalize - float sum = w[0] + w[1] + w[2]; - w[0] /= sum; - w[1] /= sum; - w[2] /= sum; - } - - if (u_mode == 0) { - COLOR = vec4(i[0], i[1], i[2], 1.0); - } else { - COLOR = vec4(w[0], w[1], w[2], 1.0); - } -} diff --git a/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr b/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr deleted file mode 100644 index 14b66d6..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr.import b/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr.import deleted file mode 100644 index c547891..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cua2gxgj2pum5" -path="res://.godot/imported/acrylic1.exr-8a4b622f104c607118d296791ee118f3.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr" -dest_files=["res://.godot/imported/acrylic1.exr-8a4b622f104c607118d296791ee118f3.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/round0.exr b/addons/zylann.hterrain/tools/brush/shapes/round0.exr deleted file mode 100644 index e91d97e..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/round0.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/round0.exr.import b/addons/zylann.hterrain/tools/brush/shapes/round0.exr.import deleted file mode 100644 index 6308ee6..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/round0.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dekau2j7fx14d" -path="res://.godot/imported/round0.exr-fc6d691e8892911b1b4496769ee75dbb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round0.exr" -dest_files=["res://.godot/imported/round0.exr-fc6d691e8892911b1b4496769ee75dbb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/round1.exr b/addons/zylann.hterrain/tools/brush/shapes/round1.exr deleted file mode 100644 index f6931ba..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/round1.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/round1.exr.import b/addons/zylann.hterrain/tools/brush/shapes/round1.exr.import deleted file mode 100644 index e64db1a..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/round1.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bbo5hotdg6mg7" -path="res://.godot/imported/round1.exr-8050cfbed31968e6ce8bd055fbaa6897.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round1.exr" -dest_files=["res://.godot/imported/round1.exr-8050cfbed31968e6ce8bd055fbaa6897.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/round2.exr b/addons/zylann.hterrain/tools/brush/shapes/round2.exr deleted file mode 100644 index 477ab7e..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/round2.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/round2.exr.import b/addons/zylann.hterrain/tools/brush/shapes/round2.exr.import deleted file mode 100644 index 6038a8e..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/round2.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://tn1ww3c47pwy" -path="res://.godot/imported/round2.exr-2a843db3bf131f2b2f5964ce65600f42.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round2.exr" -dest_files=["res://.godot/imported/round2.exr-2a843db3bf131f2b2f5964ce65600f42.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/round3.exr b/addons/zylann.hterrain/tools/brush/shapes/round3.exr deleted file mode 100644 index b466f92..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/round3.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/round3.exr.import b/addons/zylann.hterrain/tools/brush/shapes/round3.exr.import deleted file mode 100644 index e8f2107..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/round3.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://baim7e27k13r4" -path="res://.godot/imported/round3.exr-77a9cdd9a592eb6010dc1db702d42c3a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round3.exr" -dest_files=["res://.godot/imported/round3.exr-77a9cdd9a592eb6010dc1db702d42c3a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/smoke.exr b/addons/zylann.hterrain/tools/brush/shapes/smoke.exr deleted file mode 100644 index 021947b..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/smoke.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/smoke.exr.import b/addons/zylann.hterrain/tools/brush/shapes/smoke.exr.import deleted file mode 100644 index 85151ff..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/smoke.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cl6pxk6wr4hem" -path="res://.godot/imported/smoke.exr-0061a0a2acdf1ca295ec547e4b8c920d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/smoke.exr" -dest_files=["res://.godot/imported/smoke.exr-0061a0a2acdf1ca295ec547e4b8c920d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/texture1.exr b/addons/zylann.hterrain/tools/brush/shapes/texture1.exr deleted file mode 100644 index f456b77..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/texture1.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/texture1.exr.import b/addons/zylann.hterrain/tools/brush/shapes/texture1.exr.import deleted file mode 100644 index 9226d03..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/texture1.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dqdkxiq52oo0j" -path="res://.godot/imported/texture1.exr-0fac1840855f814972ea5666743101fc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/texture1.exr" -dest_files=["res://.godot/imported/texture1.exr-0fac1840855f814972ea5666743101fc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/thing.exr b/addons/zylann.hterrain/tools/brush/shapes/thing.exr deleted file mode 100644 index 49d341e..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/thing.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/thing.exr.import b/addons/zylann.hterrain/tools/brush/shapes/thing.exr.import deleted file mode 100644 index 90ba164..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/thing.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://blljfgdlwdae5" -path="res://.godot/imported/thing.exr-8e88d861fe83e5e870fa01faee694c73.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/thing.exr" -dest_files=["res://.godot/imported/thing.exr-8e88d861fe83e5e870fa01faee694c73.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr b/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr deleted file mode 100644 index d65bc6e..0000000 Binary files a/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr and /dev/null differ diff --git a/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr.import b/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr.import deleted file mode 100644 index 2a1c46a..0000000 --- a/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ca5nk2h4ukm0g" -path="res://.godot/imported/vegetation1.exr-0573f4c73944e2dd8f3202b8930ac625.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr" -dest_files=["res://.godot/imported/vegetation1.exr-0573f4c73944e2dd8f3202b8930ac625.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/brush/terrain_painter.gd b/addons/zylann.hterrain/tools/brush/terrain_painter.gd deleted file mode 100644 index 81891b6..0000000 --- a/addons/zylann.hterrain/tools/brush/terrain_painter.gd +++ /dev/null @@ -1,573 +0,0 @@ -@tool -extends Node - -const HT_Painter = preload("./painter.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_Brush = preload("./brush.gd") - -const HT_RaiseShader = preload("./shaders/raise.gdshader") -const HT_SmoothShader = preload("./shaders/smooth.gdshader") -const HT_LevelShader = preload("./shaders/level.gdshader") -const HT_FlattenShader = preload("./shaders/flatten.gdshader") -const HT_ErodeShader = preload("./shaders/erode.gdshader") -const HT_Splat4Shader = preload("./shaders/splat4.gdshader") -const HT_Splat16Shader = preload("./shaders/splat16.gdshader") -const HT_SplatIndexedShader = preload("./shaders/splat_indexed.gdshader") -const HT_ColorShader = preload("./shaders/color.gdshader") -const HT_AlphaShader = preload("./shaders/alpha.gdshader") - -const MODE_RAISE = 0 -const MODE_LOWER = 1 -const MODE_SMOOTH = 2 -const MODE_FLATTEN = 3 -const MODE_SPLAT = 4 -const MODE_COLOR = 5 -const MODE_MASK = 6 -const MODE_DETAIL = 7 -const MODE_LEVEL = 8 -const MODE_ERODE = 9 -const MODE_COUNT = 10 - -class HT_ModifiedMap: - var map_type := 0 - var map_index := 0 - var painter_index := 0 - -signal flatten_height_changed - -var _painters : Array[HT_Painter] = [] - -var _brush := HT_Brush.new() - -var _color := Color(1, 0, 0, 1) -var _mask_flag := false -var _mode := MODE_RAISE -var _flatten_height := 0.0 -var _detail_index := 0 -var _detail_density := 1.0 -var _texture_index := 0 -var _slope_limit_low_angle := 0.0 -var _slope_limit_high_angle := PI / 2.0 - -var _modified_maps := [] -var _terrain : HTerrain -var _logger = HT_Logger.get_for(self) - - -func _init(): - for i in 4: - var p := HT_Painter.new() - # The name is just for debugging - p.set_name(str("Painter", i)) - #p.set_brush_size(_brush_size) - p.texture_region_changed.connect(_on_painter_texture_region_changed.bind(i)) - add_child(p) - _painters.append(p) - - -func get_brush() -> HT_Brush: - return _brush - - -func get_brush_size() -> int: - return _brush.get_size() - - -func set_brush_size(s: int): - _brush.set_size(s) -# for p in _painters: -# p.set_brush_size(_brush_size) - - -func set_brush_texture(texture: Texture2D): - _brush.set_shapes([texture]) -# for p in _painters: -# p.set_brush_texture(texture) - - -func get_opacity() -> float: - return _brush.get_opacity() - - -func set_opacity(opacity: float): - _brush.set_opacity(opacity) - - -func set_flatten_height(h: float): - if h == _flatten_height: - return - _flatten_height = h - flatten_height_changed.emit() - - -func get_flatten_height() -> float: - return _flatten_height - - -func set_color(c: Color): - _color = c - - -func get_color() -> Color: - return _color - - -func set_mask_flag(m: bool): - _mask_flag = m - - -func get_mask_flag() -> bool: - return _mask_flag - - -func set_detail_density(d: float): - _detail_density = clampf(d, 0.0, 1.0) - - -func get_detail_density() -> float: - return _detail_density - - -func set_detail_index(di: int): - _detail_index = di - - -func set_texture_index(i: int): - _texture_index = i - - -func get_texture_index() -> int: - return _texture_index - - -func get_slope_limit_low_angle() -> float: - return _slope_limit_low_angle - - -func get_slope_limit_high_angle() -> float: - return _slope_limit_high_angle - - -func set_slope_limit_angles(low: float, high: float): - _slope_limit_low_angle = low - _slope_limit_high_angle = high - - -func is_operation_pending() -> bool: - for p in _painters: - if p.is_operation_pending(): - return true - return false - - -func has_modified_chunks() -> bool: - for p in _painters: - if p.has_modified_chunks(): - return true - return false - - -func get_undo_chunk_size() -> int: - return HT_Painter.UNDO_CHUNK_SIZE - - -func commit() -> Dictionary: - assert(_terrain.get_data() != null) - var terrain_data = _terrain.get_data() - assert(not terrain_data.is_locked()) - - var changes := [] - var chunk_positions : Array - - assert(len(_modified_maps) > 0) - - for mm in _modified_maps: - #print("Flushing painter ", mm.painter_index) - var painter : HT_Painter = _painters[mm.painter_index] - var info := painter.commit() - - # Note, positions are always the same for each map - chunk_positions = info.chunk_positions - - changes.append({ - "map_type": mm.map_type, - "map_index": mm.map_index, - "chunk_initial_datas": info.chunk_initial_datas, - "chunk_final_datas": info.chunk_final_datas - }) - - var cs := get_undo_chunk_size() - for pos in info.chunk_positions: - var rect = Rect2(pos * cs, Vector2(cs, cs)) - # This will update vertical bounds and notify normal map baker, - # since the latter updates out of order for preview - terrain_data.notify_region_change(rect, mm.map_type, mm.map_index, false, true) - -# for i in len(_painters): -# var p = _painters[i] -# if p.has_modified_chunks(): -# print("Painter ", i, " has modified chunks") - - # `commit()` is supposed to consume these chunks, there should be none left - assert(not has_modified_chunks()) - - return { - "chunk_positions": chunk_positions, - "maps": changes - } - - -func set_mode(mode: int): - assert(mode >= 0 and mode < MODE_COUNT) - _mode = mode - - -func get_mode() -> int: - return _mode - - -func set_terrain(terrain: HTerrain): - if terrain == _terrain: - return - _terrain = terrain - # It's important to release resources here, - # otherwise Godot keeps modified terrain maps in memory and "reloads" them like that - # next time we reopen the scene, even if we didn't save it - for p in _painters: - p.set_image(null, null) - p.clear_brush_shader_params() - - -# This may be called from an `_input` callback. -# Returns `true` if any change was performed. -func paint_input(position: Vector2, pressure: float) -> bool: - assert(_terrain.get_data() != null) - var data := _terrain.get_data() - assert(not data.is_locked()) - - if not _brush.configure_paint_input(_painters, position, pressure): - # Sometimes painting may not happen due to frequency options - return false - - _modified_maps.clear() - - match _mode: - MODE_RAISE: - _paint_height(data, position, 1.0) - - MODE_LOWER: - _paint_height(data, position, -1.0) - - MODE_SMOOTH: - _paint_smooth(data, position) - - MODE_FLATTEN: - _paint_flatten(data, position) - - MODE_LEVEL: - _paint_level(data, position) - - MODE_ERODE: - _paint_erode(data, position) - - MODE_SPLAT: - # TODO Properly support what happens when painting outside of supported index - # var supported_slots_count := terrain.get_cached_ground_texture_slot_count() - # if _texture_index >= supported_slots_count: - # _logger.debug("Painting out of range of supported texture slots: {0}/{1}" \ - # .format([_texture_index, supported_slots_count])) - # return - if _terrain.is_using_indexed_splatmap(): - _paint_splat_indexed(data, position) - else: - var splatmap_count := _terrain.get_used_splatmaps_count() - match splatmap_count: - 1: - _paint_splat4(data, position) - 4: - _paint_splat16(data, position) - - MODE_COLOR: - _paint_color(data, position) - - MODE_MASK: - _paint_mask(data, position) - - MODE_DETAIL: - _paint_detail(data, position) - - _: - _logger.error("Unknown mode {0}".format([_mode])) - - assert(len(_modified_maps) > 0) - return true - - -func _on_painter_texture_region_changed(rect: Rect2, painter_index: int): - var data := _terrain.get_data() - if data == null: - return - for mm in _modified_maps: - if mm.painter_index == painter_index: - # This will tell auto-baked maps to update (like normals). - data.notify_region_change(rect, mm.map_type, mm.map_index, false, false) - break - - -func _paint_height(data: HTerrainData, position: Vector2, factor: float): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - # When using sculpting tools, make it dependent on brush size - var raise_strength := 10.0 + float(_brush.get_size()) - var delta := factor * (2.0 / 60.0) * raise_strength - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_RaiseShader) - p.set_brush_shader_param("u_factor", delta) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_smooth(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_SmoothShader) - p.set_brush_shader_param("u_factor", 1.0) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_flatten(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_FlattenShader) - p.set_brush_shader_param("u_flatten_value", _flatten_height) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_level(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_LevelShader) - p.set_brush_shader_param("u_factor", (10.0 / 60.0)) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_erode(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_ErodeShader) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_splat4(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_SPLAT) - var texture := data.get_texture(HTerrainData.CHANNEL_SPLAT, 0, true) - var heightmap_texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_SPLAT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - var splat := Color(0.0, 0.0, 0.0, 0.0) - splat[_texture_index] = 1.0; - p.set_brush_shader(HT_Splat4Shader) - p.set_brush_shader_param("u_splat", splat) - _set_slope_limit_shader_params(p, heightmap_texture) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_splat_indexed(data: HTerrainData, position: Vector2): - var map_types := [ - HTerrainData.CHANNEL_SPLAT_INDEX, - HTerrainData.CHANNEL_SPLAT_WEIGHT - ] - _modified_maps = [] - - var textures := [] - for mode in 2: - textures.append(data.get_texture(map_types[mode], 0, true)) - - for mode in 2: - var image := data.get_image(map_types[mode]) - - var mm := HT_ModifiedMap.new() - mm.map_type = map_types[mode] - mm.map_index = 0 - mm.painter_index = mode - _modified_maps.append(mm) - - var p : HT_Painter = _painters[mode] - - p.set_brush_shader(HT_SplatIndexedShader) - p.set_brush_shader_param("u_mode", mode) - p.set_brush_shader_param("u_index_map", textures[0]) - p.set_brush_shader_param("u_weight_map", textures[1]) - p.set_brush_shader_param("u_texture_index", _texture_index) - p.set_image(image, textures[mode]) - p.paint_input(position) - - -func _paint_splat16(data: HTerrainData, position: Vector2): - # Make sure required maps are present - while data.get_map_count(HTerrainData.CHANNEL_SPLAT) < 4: - data._edit_add_map(HTerrainData.CHANNEL_SPLAT) - - var splats := [] - for i in 4: - splats.append(Color(0.0, 0.0, 0.0, 0.0)) - splats[_texture_index / 4][_texture_index % 4] = 1.0 - - var textures := [] - for i in 4: - textures.append(data.get_texture(HTerrainData.CHANNEL_SPLAT, i, true)) - - var heightmap_texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0) - - for i in 4: - var image : Image = data.get_image(HTerrainData.CHANNEL_SPLAT, i) - var texture : Texture = textures[i] - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_SPLAT - mm.map_index = i - mm.painter_index = i - _modified_maps.append(mm) - - var p : HT_Painter = _painters[i] - - var other_splatmaps := [] - for tex in textures: - if tex != texture: - other_splatmaps.append(tex) - - p.set_brush_shader(HT_Splat16Shader) - p.set_brush_shader_param("u_splat", splats[i]) - p.set_brush_shader_param("u_other_splatmap_1", other_splatmaps[0]) - p.set_brush_shader_param("u_other_splatmap_2", other_splatmaps[1]) - p.set_brush_shader_param("u_other_splatmap_3", other_splatmaps[2]) - _set_slope_limit_shader_params(p, heightmap_texture) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_color(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_COLOR) - var texture := data.get_texture(HTerrainData.CHANNEL_COLOR, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_COLOR - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - # There was a problem with painting colors because of sRGB - # https://github.com/Zylann/godot_heightmap_plugin/issues/17#issuecomment-734001879 - - p.set_brush_shader(HT_ColorShader) - p.set_brush_shader_param("u_color", _color) - p.set_brush_shader_param("u_normal_min_y", 0.0) - p.set_brush_shader_param("u_normal_max_y", 1.0) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_mask(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_COLOR) - var texture := data.get_texture(HTerrainData.CHANNEL_COLOR, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_COLOR - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_AlphaShader) - p.set_brush_shader_param("u_value", 1.0 if _mask_flag else 0.0) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_detail(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_DETAIL, _detail_index) - var texture := data.get_texture(HTerrainData.CHANNEL_DETAIL, _detail_index, true) - var heightmap_texture = data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_DETAIL - mm.map_index = _detail_index - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - var c := Color(_detail_density, _detail_density, _detail_density, 1.0) - - # TODO Don't use this shader (why?) - p.set_brush_shader(HT_ColorShader) - p.set_brush_shader_param("u_color", c) - _set_slope_limit_shader_params(p, heightmap_texture) - p.set_image(image, texture) - p.paint_input(position) - - -func _set_slope_limit_shader_params(p: HT_Painter, heightmap_texture: Texture): - p.set_brush_shader_param("u_normal_min_y", cos(_slope_limit_high_angle)) - p.set_brush_shader_param("u_normal_max_y", cos(_slope_limit_low_angle) + 0.001) - p.set_brush_shader_param("u_heightmap", heightmap_texture) diff --git a/addons/zylann.hterrain/tools/bump2normal_tex.gdshader b/addons/zylann.hterrain/tools/bump2normal_tex.gdshader deleted file mode 100644 index b0c97da..0000000 --- a/addons/zylann.hterrain/tools/bump2normal_tex.gdshader +++ /dev/null @@ -1,25 +0,0 @@ -shader_type canvas_item; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -vec4 pack_normal(vec3 n) { - return vec4((0.5 * (n + 1.0)).xzy, 1.0); -} - -float get_height(sampler2D tex, vec2 uv) { - return sample_heightmap(tex, uv); -} - -void fragment() { - vec2 uv = UV; - vec2 ps = TEXTURE_PIXEL_SIZE; - float left = get_height(TEXTURE, uv + vec2(-ps.x, 0)); - float right = get_height(TEXTURE, uv + vec2(ps.x, 0)); - float back = get_height(TEXTURE, uv + vec2(0, -ps.y)); - float fore = get_height(TEXTURE, uv + vec2(0, ps.y)); - vec3 n = normalize(vec3(left - right, 2.0, fore - back)); - COLOR = pack_normal(n); - // DEBUG - //COLOR.r = fract(TIME * 100.0); -} - diff --git a/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd b/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd deleted file mode 100644 index cb3288e..0000000 --- a/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd +++ /dev/null @@ -1,200 +0,0 @@ -@tool -extends Control - -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HTerrainDetailLayer = preload("../../hterrain_detail_layer.gd") -const HT_ImageFileCache = preload("../../util/image_file_cache.gd") -const HT_EditorUtil = preload("../util/editor_util.gd") -const HT_Logger = preload("../../util/logger.gd") - -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const PLACEHOLDER_ICON_TEXTURE = "res://addons/zylann.hterrain/tools/icons/icon_grass.svg" -const DETAIL_LAYER_ICON_TEXTURE = \ - "res://addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg" - -signal detail_selected(index) -# Emitted when the tool added or removed a detail map -signal detail_list_changed - -@onready var _item_list : ItemList = $ItemList -@onready var _confirmation_dialog : ConfirmationDialog = $ConfirmationDialog - -var _terrain : HTerrain = null -var _dialog_target := -1 -var _undo_redo_manager : EditorUndoRedoManager -var _image_cache : HT_ImageFileCache -var _logger = HT_Logger.get_for(self) - - -func set_terrain(terrain): - if _terrain == terrain: - return - _terrain = terrain - _update_list() - - -func set_undo_redo(ur: EditorUndoRedoManager): - assert(ur != null) - _undo_redo_manager = ur - - -func set_image_cache(image_cache: HT_ImageFileCache): - _image_cache = image_cache - - -func set_layer_index(i: int): - _item_list.select(i, true) - - -func _update_list(): - _item_list.clear() - - if _terrain == null: - return - - var layer_nodes = _terrain.get_detail_layers() - var layer_nodes_by_index := {} - for layer in layer_nodes: - if not layer_nodes_by_index.has(layer.layer_index): - layer_nodes_by_index[layer.layer_index] = [] - layer_nodes_by_index[layer.layer_index].append(layer.name) - - var data = _terrain.get_data() - if data != null: - # Display layers from what terrain data actually contains, - # because layer nodes are just what makes them rendered and aren't much restricted. - var layer_count = data.get_map_count(HTerrainData.CHANNEL_DETAIL) - var placeholder_icon = HT_EditorUtil.load_texture(PLACEHOLDER_ICON_TEXTURE, _logger) - - for i in layer_count: - # TODO Show a preview icon - _item_list.add_item(str("Map ", i), placeholder_icon) - - if layer_nodes_by_index.has(i): - # TODO How to keep names updated with node names? - var names := ", ".join(PackedStringArray(layer_nodes_by_index[i])) - if len(names) == 1: - _item_list.set_item_tooltip(i, "Used by " + names) - else: - _item_list.set_item_tooltip(i, "Used by " + names) - # Remove custom color - # TODO Use fg version when available in Godot 3.1, I want to only highlight text - _item_list.set_item_custom_bg_color(i, Color(0, 0, 0, 0)) - else: - # TODO Use fg version when available in Godot 3.1, I want to only highlight text - _item_list.set_item_custom_bg_color(i, Color(1.0, 0.2, 0.2, 0.3)) - _item_list.set_item_tooltip(i, "This map isn't used by any layer. " \ - + "Add a HTerrainDetailLayer node as child of the terrain.") - - -func _on_Add_pressed(): - _add_layer() - - -func _on_Remove_pressed(): - var selected = _item_list.get_selected_items() - if len(selected) == 0: - return - _dialog_target = _item_list.get_selected_items()[0] - _confirmation_dialog.title = "Removing detail map {0}".format([_dialog_target]) - _confirmation_dialog.popup_centered() - - -func _on_ConfirmationDialog_confirmed(): - _remove_layer(_dialog_target) - - -func _add_layer(): - assert(_terrain != null) - assert(_terrain.get_data() != null) - assert(_undo_redo_manager != null) - var terrain_data : HTerrainData = _terrain.get_data() - - # First, create node and map image - var node := HTerrainDetailLayer.new() - # TODO Workarounds for https://github.com/godotengine/godot/issues/21410 - var detail_layer_icon := HT_EditorUtil.load_texture(DETAIL_LAYER_ICON_TEXTURE, _logger) - node.set_meta("_editor_icon", detail_layer_icon) - node.name = "HTerrainDetailLayer" - var map_index := terrain_data._edit_add_map(HTerrainData.CHANNEL_DETAIL) - var map_image := terrain_data.get_image(HTerrainData.CHANNEL_DETAIL) - var map_image_cache_id := _image_cache.save_image(map_image) - node.layer_index = map_index - - var undo_redo := _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_terrain)) - - # Then, create an action - undo_redo.create_action("Add Detail Layer {0}".format([map_index])) - - undo_redo.add_do_method(terrain_data._edit_insert_map_from_image_cache.bind( - HTerrainData.CHANNEL_DETAIL, map_index, _image_cache, map_image_cache_id)) - undo_redo.add_do_method(_terrain.add_child.bind(node)) - undo_redo.add_do_property(node, "owner", get_tree().edited_scene_root) - undo_redo.add_do_method(self._update_list) - undo_redo.add_do_reference(node) - - undo_redo.add_undo_method(_terrain.remove_child.bind(node)) - undo_redo.add_undo_method( - terrain_data._edit_remove_map.bind(HTerrainData.CHANNEL_DETAIL, map_index)) - undo_redo.add_undo_method(self._update_list) - - # Yet another instance of this hack, to prevent UndoRedo from running some of the functions, - # which we had to run already - terrain_data._edit_set_disable_apply_undo(true) - undo_redo.commit_action() - terrain_data._edit_set_disable_apply_undo(false) - - #_update_list() - detail_list_changed.emit() - - var index := node.layer_index - _item_list.select(index) - # select() doesn't trigger the signal - detail_selected.emit(index) - - -func _remove_layer(map_index: int): - var terrain_data : HTerrainData = _terrain.get_data() - - # First, cache image data - var image := terrain_data.get_image(HTerrainData.CHANNEL_DETAIL, map_index) - var image_id := _image_cache.save_image(image) - var nodes = _terrain.get_detail_layers() - var using_nodes := [] - # Nodes using this map will be removed from the tree - for node in nodes: - if node.layer_index == map_index: - using_nodes.append(node) - - var undo_redo := _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_terrain)) - - undo_redo.create_action("Remove Detail Layer {0}".format([map_index])) - - undo_redo.add_do_method( - terrain_data._edit_remove_map.bind(HTerrainData.CHANNEL_DETAIL, map_index)) - for node in using_nodes: - undo_redo.add_do_method(_terrain.remove_child.bind(node)) - undo_redo.add_do_method(self._update_list) - - undo_redo.add_undo_method(terrain_data._edit_insert_map_from_image_cache.bind( - HTerrainData.CHANNEL_DETAIL, map_index, _image_cache, image_id)) - for node in using_nodes: - undo_redo.add_undo_method(_terrain.add_child.bind(node)) - undo_redo.add_undo_property(node, "owner", get_tree().edited_scene_root) - undo_redo.add_undo_reference(node) - undo_redo.add_undo_method(self._update_list) - - undo_redo.commit_action() - - #_update_list() - detail_list_changed.emit() - - -func _on_ItemList_item_selected(index): - detail_selected.emit(index) - - - diff --git a/addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn b/addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn deleted file mode 100644 index cc5b995..0000000 --- a/addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn +++ /dev/null @@ -1,48 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://do3c3jse5p7hx"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/detail_editor/detail_editor.gd" id="1"] - -[node name="DetailEditor" type="Control"] -custom_minimum_size = Vector2(200, 0) -layout_mode = 3 -anchors_preset = 0 -offset_right = 189.0 -offset_bottom = 109.0 -script = ExtResource("1") - -[node name="ItemList" type="ItemList" parent="."] -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_bottom = -26.0 -max_columns = 0 -same_column_width = true -icon_mode = 0 -fixed_icon_size = Vector2i(32, 32) - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 0 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -24.0 - -[node name="Add" type="Button" parent="HBoxContainer"] -layout_mode = 2 -text = "Add" - -[node name="Remove" type="Button" parent="HBoxContainer"] -layout_mode = 2 -text = "Remove" - -[node name="Label" type="Label" parent="HBoxContainer"] -layout_mode = 2 -text = "Details" - -[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] -dialog_text = "Are you sure you want to remove this detail map?" - -[connection signal="item_selected" from="ItemList" to="." method="_on_ItemList_item_selected"] -[connection signal="pressed" from="HBoxContainer/Add" to="." method="_on_Add_pressed"] -[connection signal="pressed" from="HBoxContainer/Remove" to="." method="_on_Remove_pressed"] -[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_ConfirmationDialog_confirmed"] diff --git a/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd b/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd deleted file mode 100644 index b989099..0000000 --- a/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd +++ /dev/null @@ -1,221 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Errors = preload("../../util/errors.gd") -const HT_Util = preload("../../util/util.gd") -const HT_Logger = preload("../../util/logger.gd") - -const FORMAT_RH = 0 -const FORMAT_RF = 1 -const FORMAT_R16 = 2 -const FORMAT_PNG8 = 3 -const FORMAT_EXRH = 4 -const FORMAT_EXRF = 5 -const FORMAT_COUNT = 6 - -@onready var _output_path_line_edit := $VB/Grid/OutputPath/HeightmapPathLineEdit as LineEdit -@onready var _format_selector := $VB/Grid/FormatSelector as OptionButton -@onready var _height_range_min_spinbox := $VB/Grid/HeightRange/HeightRangeMin as SpinBox -@onready var _height_range_max_spinbox := $VB/Grid/HeightRange/HeightRangeMax as SpinBox -@onready var _export_button := $VB/Buttons/ExportButton as Button -@onready var _show_in_explorer_checkbox := $VB/ShowInExplorerCheckbox as CheckBox - -var _terrain : HTerrain = null -var _file_dialog : EditorFileDialog = null -var _format_names := [] -var _format_extensions := [] -var _logger = HT_Logger.get_for(self) - - -func _init(): - # Godot 4 decided to not have a plain WindowDialog class... - # there is Window but it's way too unfriendly... - get_ok_button().hide() - - -func _ready(): - _format_names.resize(FORMAT_COUNT) - _format_extensions.resize(FORMAT_COUNT) - - _format_names[FORMAT_RH] = "16-bit RAW float" - _format_names[FORMAT_RF] = "32-bit RAW float" - _format_names[FORMAT_R16] = "16-bit RAW unsigned" - _format_names[FORMAT_PNG8] = "8-bit PNG greyscale" - _format_names[FORMAT_EXRH] = "16-bit float greyscale EXR" - _format_names[FORMAT_EXRF] = "32-bit float greyscale EXR" - - _format_extensions[FORMAT_RH] = "raw" - _format_extensions[FORMAT_RF] = "raw" - _format_extensions[FORMAT_R16] = "raw" - _format_extensions[FORMAT_PNG8] = "png" - _format_extensions[FORMAT_EXRH] = "exr" - _format_extensions[FORMAT_EXRF] = "exr" - - if not HT_Util.is_in_edited_scene(self): - for i in len(_format_names): - _format_selector.get_popup().add_item(_format_names[i], i) - - -func setup_dialogs(base_control: Control): - assert(_file_dialog == null) - var fd := EditorFileDialog.new() - fd.file_mode = EditorFileDialog.FILE_MODE_SAVE_FILE - fd.unresizable = false - fd.access = EditorFileDialog.ACCESS_FILESYSTEM - fd.file_selected.connect(_on_FileDialog_file_selected) - add_child(fd) - _file_dialog = fd - - _update_file_extension() - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -func _exit_tree(): - if _file_dialog != null: - _file_dialog.queue_free() - _file_dialog = null - - -func _on_FileDialog_file_selected(fpath: String): - _output_path_line_edit.text = fpath - - -func _auto_adjust_height_range(): - assert(_terrain != null) - assert(_terrain.get_data() != null) - var aabb := _terrain.get_data().get_aabb() - _height_range_min_spinbox.value = aabb.position.y - _height_range_max_spinbox.value = aabb.position.y + aabb.size.y - - -func _export() -> bool: - assert(_terrain != null) - assert(_terrain.get_data() != null) - var src_heightmap: Image = _terrain.get_data().get_image(HTerrainData.CHANNEL_HEIGHT) - var fpath := _output_path_line_edit.text.strip_edges() - - # TODO Is `selected` an ID or an index? I need an ID, it works by chance for now. - var format := _format_selector.selected - - var height_min := _height_range_min_spinbox.value - var height_max := _height_range_max_spinbox.value - - if height_min == height_max: - _logger.error("Cannot export, height range is zero") - return false - - if height_min > height_max: - _logger.error("Cannot export, height min is greater than max") - return false - - var save_error := OK - - var float_heightmap := HTerrainData.convert_heightmap_to_float(src_heightmap, _logger) - - if format == FORMAT_PNG8: - var hscale := 1.0 / (height_max - height_min) - var im := Image.create( - src_heightmap.get_width(), src_heightmap.get_height(), false, Image.FORMAT_R8) - - for y in src_heightmap.get_height(): - for x in src_heightmap.get_width(): - var h := clampf((float_heightmap.get_pixel(x, y).r - height_min) * hscale, 0.0, 1.0) - im.set_pixel(x, y, Color(h, h, h)) - - save_error = im.save_png(fpath) - - elif format == FORMAT_EXRH: - float_heightmap.convert(Image.FORMAT_RH) - save_error = float_heightmap.save_exr(fpath, true) - - elif format == FORMAT_EXRF: - save_error = float_heightmap.save_exr(fpath, true) - - else: # RAW - var f := FileAccess.open(fpath, FileAccess.WRITE) - if f == null: - var err := FileAccess.get_open_error() - _print_file_error(fpath, err) - return false - - if format == FORMAT_RH: - float_heightmap.convert(Image.FORMAT_RH) - f.store_buffer(float_heightmap.get_data()) - - elif format == FORMAT_RF: - f.store_buffer(float_heightmap.get_data()) - - elif format == FORMAT_R16: - var hscale := 65535.0 / (height_max - height_min) - for y in float_heightmap.get_height(): - for x in float_heightmap.get_width(): - var h := int((float_heightmap.get_pixel(x, y).r - height_min) * hscale) - if h < 0: - h = 0 - elif h > 65535: - h = 65535 - if x % 50 == 0: - _logger.debug(str(h)) - f.store_16(h) - - if save_error == OK: - _logger.debug("Exported heightmap as \"{0}\"".format([fpath])) - return true - else: - _print_file_error(fpath, save_error) - return false - - -func _update_file_extension(): - if _format_selector.selected == -1: - _format_selector.selected = 0 - # This recursively calls the current function - return - - # TODO Is `selected` an ID or an index? I need an ID, it works by chance for now. - var format = _format_selector.selected - - var ext : String = _format_extensions[format] - _file_dialog.clear_filters() - _file_dialog.add_filter(str("*.", ext, " ; ", ext.to_upper(), " files")) - - var fpath := _output_path_line_edit.text.strip_edges() - if fpath != "": - _output_path_line_edit.text = str(fpath.get_basename(), ".", ext) - - -func _print_file_error(fpath: String, err: int): - _logger.error("Could not save path {0}, error: {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - - -func _on_CancelButton_pressed(): - hide() - - -func _on_ExportButton_pressed(): - if _export(): - hide() - if _show_in_explorer_checkbox.button_pressed: - OS.shell_open(_output_path_line_edit.text.strip_edges().get_base_dir()) - - -func _on_HeightmapPathLineEdit_text_changed(new_text: String): - _export_button.disabled = (new_text.strip_edges() == "") - - -func _on_HeightmapPathBrowseButton_pressed(): - _file_dialog.popup_centered_ratio() - - -func _on_FormatSelector_item_selected(id): - _update_file_extension() - - -func _on_HeightRangeAutoButton_pressed(): - _auto_adjust_height_range() diff --git a/addons/zylann.hterrain/tools/exporter/export_image_dialog.tscn b/addons/zylann.hterrain/tools/exporter/export_image_dialog.tscn deleted file mode 100644 index a702181..0000000 --- a/addons/zylann.hterrain/tools/exporter/export_image_dialog.tscn +++ /dev/null @@ -1,125 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bcocysgmum5ag"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/exporter/export_image_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="2"] - -[node name="ExportImageDialog" type="AcceptDialog"] -size = Vector2i(500, 340) -min_size = Vector2i(500, 250) -script = ExtResource("1") - -[node name="VB" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="Grid" type="GridContainer" parent="VB"] -layout_mode = 2 -columns = 2 - -[node name="OutputPathLabel" type="Label" parent="VB/Grid"] -layout_mode = 2 -text = "Output path:" - -[node name="OutputPath" type="HBoxContainer" parent="VB/Grid"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="HeightmapPathLineEdit" type="LineEdit" parent="VB/Grid/OutputPath"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="HeightmapPathBrowseButton" type="Button" parent="VB/Grid/OutputPath"] -layout_mode = 2 -text = "..." - -[node name="FormatLabel" type="Label" parent="VB/Grid"] -layout_mode = 2 -text = "Format:" - -[node name="FormatSelector" type="OptionButton" parent="VB/Grid"] -layout_mode = 2 - -[node name="HeightRangeLabel" type="Label" parent="VB/Grid"] -layout_mode = 2 -text = "Height range:" - -[node name="HeightRange" type="HBoxContainer" parent="VB/Grid"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/Grid/HeightRange"] -layout_mode = 2 -text = "Min" - -[node name="HeightRangeMin" type="SpinBox" parent="VB/Grid/HeightRange"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -min_value = -10000.0 -max_value = 10000.0 -step = 0.0 -value = -2000.0 - -[node name="Label2" type="Label" parent="VB/Grid/HeightRange"] -layout_mode = 2 -text = "Max" - -[node name="HeightRangeMax" type="SpinBox" parent="VB/Grid/HeightRange"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -min_value = -10000.0 -max_value = 10000.0 -step = 0.0 -value = 2000.0 - -[node name="HeightRangeAutoButton" type="Button" parent="VB/Grid/HeightRange"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Auto" - -[node name="ShowInExplorerCheckbox" type="CheckBox" parent="VB"] -layout_mode = 2 -text = "Show in explorer after export" - -[node name="Spacer" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 16) -layout_mode = 2 - -[node name="Label" type="Label" parent="VB"] -layout_mode = 2 -text = "Note: height range is needed for integer image formats, as they can't directly represent the real height. 8-bit formats may cause precision loss." -autowrap_mode = 2 - -[node name="Spacer2" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 16) -layout_mode = 2 - -[node name="Buttons" type="HBoxContainer" parent="VB"] -layout_mode = 2 -alignment = 1 - -[node name="ExportButton" type="Button" parent="VB/Buttons"] -layout_mode = 2 -text = "Export" - -[node name="CancelButton" type="Button" parent="VB/Buttons"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("2")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 492.0 -offset_bottom = 322.0 - -[connection signal="text_changed" from="VB/Grid/OutputPath/HeightmapPathLineEdit" to="." method="_on_HeightmapPathLineEdit_text_changed"] -[connection signal="pressed" from="VB/Grid/OutputPath/HeightmapPathBrowseButton" to="." method="_on_HeightmapPathBrowseButton_pressed"] -[connection signal="item_selected" from="VB/Grid/FormatSelector" to="." method="_on_FormatSelector_item_selected"] -[connection signal="pressed" from="VB/Grid/HeightRange/HeightRangeAutoButton" to="." method="_on_HeightRangeAutoButton_pressed"] -[connection signal="pressed" from="VB/Buttons/ExportButton" to="." method="_on_ExportButton_pressed"] -[connection signal="pressed" from="VB/Buttons/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/addons/zylann.hterrain/tools/generate_mesh_dialog.gd b/addons/zylann.hterrain/tools/generate_mesh_dialog.gd deleted file mode 100644 index f567e02..0000000 --- a/addons/zylann.hterrain/tools/generate_mesh_dialog.gd +++ /dev/null @@ -1,54 +0,0 @@ -@tool -extends AcceptDialog - -signal generate_selected(lod) - -const HTerrain = preload("../hterrain.gd") -const HTerrainMesher = preload("../hterrain_mesher.gd") -const HT_Util = preload("../util/util.gd") - -@onready var _preview_label : Label = $VBoxContainer/PreviewLabel -@onready var _lod_spinbox : SpinBox = $VBoxContainer/HBoxContainer/LODSpinBox - -var _terrain : HTerrain = null - - -func _init(): - get_ok_button().hide() - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - if visible and _terrain != null: - _update_preview() - - -func _on_LODSpinBox_value_changed(value): - _update_preview() - - -func _update_preview(): - assert(_terrain != null) - assert(_terrain.get_data() != null) - var resolution := _terrain.get_data().get_resolution() - var stride := int(_lod_spinbox.value) - resolution /= stride - var s := HTerrainMesher.get_mesh_size(resolution, resolution) - _preview_label.text = str( \ - HT_Util.format_integer(s.vertices), " vertices, ", \ - HT_Util.format_integer(s.triangles), " triangles") - - -func _on_Generate_pressed(): - var stride := int(_lod_spinbox.value) - generate_selected.emit(stride) - hide() - - -func _on_Cancel_pressed(): - hide() - diff --git a/addons/zylann.hterrain/tools/generate_mesh_dialog.tscn b/addons/zylann.hterrain/tools/generate_mesh_dialog.tscn deleted file mode 100644 index 12f3d4a..0000000 --- a/addons/zylann.hterrain/tools/generate_mesh_dialog.tscn +++ /dev/null @@ -1,69 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://ci0da54goyo5o"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/generate_mesh_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="2"] - -[node name="GenerateMeshDialog" type="AcceptDialog"] -title = "Generate full mesh" -size = Vector2i(448, 234) -min_size = Vector2i(448, 186) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "LOD" - -[node name="LODSpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = 1.0 -max_value = 16.0 -value = 1.0 - -[node name="PreviewLabel" type="Label" parent="VBoxContainer"] -layout_mode = 2 -text = "9999 vertices, 9999 triangles" - -[node name="Spacer" type="Control" parent="VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VBoxContainer"] -layout_mode = 2 -text = "Note: generating a full mesh from the terrain may result in a huge amount of vertices for a single object. It is preferred to do this for small terrains, or as a temporary workaround to generate a navmesh." -autowrap_mode = 2 - -[node name="Buttons" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="Generate" type="Button" parent="VBoxContainer/Buttons"] -layout_mode = 2 -text = "Generate" - -[node name="Cancel" type="Button" parent="VBoxContainer/Buttons"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("2")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 440.0 -offset_bottom = 216.0 - -[connection signal="value_changed" from="VBoxContainer/HBoxContainer/LODSpinBox" to="." method="_on_LODSpinBox_value_changed"] -[connection signal="pressed" from="VBoxContainer/Buttons/Generate" to="." method="_on_Generate_pressed"] -[connection signal="pressed" from="VBoxContainer/Buttons/Cancel" to="." method="_on_Cancel_pressed"] diff --git a/addons/zylann.hterrain/tools/generator/generator_dialog.gd b/addons/zylann.hterrain/tools/generator/generator_dialog.gd deleted file mode 100644 index bbb7069..0000000 --- a/addons/zylann.hterrain/tools/generator/generator_dialog.gd +++ /dev/null @@ -1,562 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HTerrainMesher = preload("../../hterrain_mesher.gd") -const HT_Util = preload("../../util/util.gd") -const HT_TextureGenerator = preload("./texture_generator.gd") -const HT_TextureGeneratorPass = preload("./texture_generator_pass.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_ImageFileCache = preload("../../util/image_file_cache.gd") -const HT_Inspector = preload("../inspector/inspector.gd") -const HT_TerrainPreview = preload("../terrain_preview.gd") -const HT_ProgressWindow = preload("../progress_window.gd") - -const HT_ProgressWindowScene = preload("../progress_window.tscn") - -# TODO Power of two is assumed here. -# I wonder why it doesn't have the off by one terrain textures usually have -const MAX_VIEWPORT_RESOLUTION = 512 - -#signal progress_notified(info) # { "progress": real, "message": string, "finished": bool } - -@onready var _inspector_container : Control = $VBoxContainer/Editor/Settings -@onready var _inspector : HT_Inspector = $VBoxContainer/Editor/Settings/Inspector -@onready var _preview : HT_TerrainPreview = $VBoxContainer/Editor/Preview/TerrainPreview -@onready var _progress_bar : ProgressBar = $VBoxContainer/Editor/Preview/ProgressBar - -var _dummy_texture = load("res://addons/zylann.hterrain/tools/icons/empty.png") -var _terrain : HTerrain = null -var _applying := false -var _generator : HT_TextureGenerator -var _generated_textures := [null, null] -var _dialog_visible := false -var _undo_map_ids := {} -var _image_cache : HT_ImageFileCache = null -var _undo_redo_manager : EditorUndoRedoManager -var _logger := HT_Logger.get_for(self) -var _viewport_resolution := MAX_VIEWPORT_RESOLUTION -var _progress_window : HT_ProgressWindow - - -static func get_shader(shader_name: String) -> Shader: - var path := "res://addons/zylann.hterrain/tools/generator/shaders"\ - .path_join(str(shader_name, ".gdshader")) - return load(path) as Shader - - -func _init(): - # Godot 4 does not have a plain WindowDialog class... there is Window but it's too unfriendly... - get_ok_button().hide() - - _progress_window = HT_ProgressWindowScene.instantiate() - add_child(_progress_window) - - -func _ready(): - _inspector.set_prototype({ - "seed": { - "type": TYPE_INT, - "randomizable": true, - "range": { "min": -100, "max": 100 }, - "slidable": false - }, - "offset": { - "type": TYPE_VECTOR2 - }, - "base_height": { - "type": TYPE_FLOAT, - "range": {"min": -500.0, "max": 500.0, "step": 0.1 }, - "default_value": -50.0 - }, - "height_range": { - "type": TYPE_FLOAT, - "range": {"min": 0.0, "max": 2000.0, "step": 0.1 }, - "default_value": 150.0 - }, - "scale": { - "type": TYPE_FLOAT, - "range": {"min": 1.0, "max": 1000.0, "step": 1.0}, - "default_value": 100.0 - }, - "roughness": { - "type": TYPE_FLOAT, - "range": {"min": 0.0, "max": 1.0, "step": 0.01}, - "default_value": 0.4 - }, - "curve": { - "type": TYPE_FLOAT, - "range": {"min": 1.0, "max": 10.0, "step": 0.1}, - "default_value": 1.0 - }, - "octaves": { - "type": TYPE_INT, - "range": {"min": 1, "max": 10, "step": 1}, - "default_value": 6 - }, - "erosion_steps": { - "type": TYPE_INT, - "range": {"min": 0, "max": 100, "step": 1}, - "default_value": 0 - }, - "erosion_weight": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0 }, - "default_value": 0.5 - }, - "erosion_slope_factor": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0 }, - "default_value": 0.0 - }, - "erosion_slope_direction": { - "type": TYPE_VECTOR2, - "default_value": Vector2(0, 0) - }, - "erosion_slope_invert": { - "type": TYPE_BOOL, - "default_value": false - }, - "dilation": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0 }, - "default_value": 0.0 - }, - "island_weight": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0, "step": 0.01 }, - "default_value": 0.0 - }, - "island_sharpness": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0, "step": 0.01 }, - "default_value": 0.0 - }, - "island_height_ratio": { - "type": TYPE_FLOAT, - "range": { "min": -1.0, "max": 1.0, "step": 0.01 }, - "default_value": -1.0 - }, - "island_shape": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0, "step": 0.01 }, - "default_value": 0.0 - }, - "additive_heightmap": { - "type": TYPE_BOOL, - "default_value": false - }, - "show_sea": { - "type": TYPE_BOOL, - "default_value": true - }, - "shadows": { - "type": TYPE_BOOL, - "default_value": true - } - }) - - _generator = HT_TextureGenerator.new() - _generator.set_resolution(Vector2i(_viewport_resolution, _viewport_resolution)) - # Setup the extra pixels we want on max edges for terrain - # TODO I wonder if it's not better to let the generator shaders work in pixels - # instead of NDC, rather than putting a padding system there - _generator.set_output_padding([0, 1, 0, 1]) - _generator.output_generated.connect(_on_TextureGenerator_output_generated) - _generator.completed.connect(_on_TextureGenerator_completed) - _generator.progress_reported.connect(_on_TextureGenerator_progress_reported) - add_child(_generator) - - # TEST - if not Engine.is_editor_hint(): - call_deferred("popup_centered") - - -func apply_dpi_scale(dpi_scale: float): - min_size *= dpi_scale - _inspector_container.custom_minimum_size *= dpi_scale - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - _adjust_viewport_resolution() - - -func _adjust_viewport_resolution(): - if _terrain == null: - return - var data = _terrain.get_data() - if data == null: - return - var terrain_resolution := data.get_resolution() - - # By default we want to work with a large enough viewport to generate tiles, - # but we should pick a smaller size if the terrain is smaller than that... - var vp_res := MAX_VIEWPORT_RESOLUTION - while vp_res > terrain_resolution: - vp_res /= 2 - - _generator.set_resolution(Vector2(vp_res, vp_res)) - _viewport_resolution = vp_res - - -func set_image_cache(image_cache: HT_ImageFileCache): - _image_cache = image_cache - - -func set_undo_redo(ur: EditorUndoRedoManager): - _undo_redo_manager = ur - - -func _notification(what: int): - match what: - NOTIFICATION_VISIBILITY_CHANGED: - # We don't want any of this to run in an edited scene - if HT_Util.is_in_edited_scene(self): - return - # Since Godot 4 visibility can be changed even between _enter_tree and _ready - if _preview == null: - return - - if visible: - # TODO https://github.com/godotengine/godot/issues/18160 - if _dialog_visible: - return - _dialog_visible = true - - _adjust_viewport_resolution() - - _preview.set_sea_visible(_inspector.get_value("show_sea")) - _preview.set_shadows_enabled(_inspector.get_value("shadows")) - - _update_generator(true) - - else: -# if not _applying: -# _destroy_viewport() - _preview.cleanup() - for i in len(_generated_textures): - _generated_textures[i] = null - _dialog_visible = false - - -func _update_generator(preview: bool): - var scale : float = _inspector.get_value("scale") - # Scale is inverted in the shader - if absf(scale) < 0.01: - scale = 0.0 - else: - scale = 1.0 / scale - scale *= _viewport_resolution - - var preview_scale := 4.0 # As if 2049x2049 - var sectors := [] - var terrain_size := 513 - - var additive_heightmap : Texture2D = null - - # For testing - if not Engine.is_editor_hint() and _terrain == null: - sectors.append(Vector2(0, 0)) - - # Get preview scale and sectors to generate. - # Allowing null terrain to make it testable. - if _terrain != null and _terrain.get_data() != null: - var terrain_data := _terrain.get_data() - terrain_size = terrain_data.get_resolution() - - if _inspector.get_value("additive_heightmap"): - additive_heightmap = terrain_data.get_texture(HTerrainData.CHANNEL_HEIGHT) - - if preview: - # When previewing the resolution does not span the entire terrain, - # so we apply a scale to some of the passes to make it cover it all. - preview_scale = float(terrain_size) / float(_viewport_resolution) - sectors.append(Vector2(0, 0)) - - else: - if additive_heightmap != null: - # We have to duplicate the heightmap because we are going to write - # into it during the generation process. - # It would be fine when we don't read outside of a generated tile, - # but we actually do that for erosion: neighboring pixels are read - # again, and if they were modified by a previous tile it will - # disrupt generation, so we need to use a copy of the original. - additive_heightmap = additive_heightmap.duplicate() - - # When we get to generate it fully, sectors are used, - # so the size or shape of the terrain doesn't matter - preview_scale = 1.0 - - var cw := terrain_size / _viewport_resolution - var ch := terrain_size / _viewport_resolution - - for y in ch: - for x in cw: - sectors.append(Vector2(x, y)) - - var erosion_iterations := int(_inspector.get_value("erosion_steps")) - erosion_iterations /= int(preview_scale) - - _generator.clear_passes() - - # Terrain textures need to have an off-by-one on their max edge, - # which is shared with the other sectors. - var base_offset_ndc = _inspector.get_value("offset") - #var sector_size_offby1_ndc = float(VIEWPORT_RESOLUTION - 1) / padded_viewport_resolution - - for i in len(sectors): - var sector = sectors[i] - #var offset = sector * sector_size_offby1_ndc - Vector2(pad_offset_ndc, pad_offset_ndc) - -# var offset_px = sector * (VIEWPORT_RESOLUTION - 1) - Vector2(pad_offset_px, pad_offset_px) -# var offset_ndc = offset_px / padded_viewport_resolution - var progress := float(i) / len(sectors) - var p := HT_TextureGeneratorPass.new() - p.clear = true - p.shader = get_shader("perlin_noise") - # This pass generates the shapes of the terrain so will have to account for offset - p.tile_pos = sector - p.params = { - "u_octaves": _inspector.get_value("octaves"), - "u_seed": _inspector.get_value("seed"), - "u_scale": scale, - "u_offset": base_offset_ndc, - "u_base_height": _inspector.get_value("base_height") / preview_scale, - "u_height_range": _inspector.get_value("height_range") / preview_scale, - "u_roughness": _inspector.get_value("roughness"), - "u_curve": _inspector.get_value("curve"), - "u_island_weight": _inspector.get_value("island_weight"), - "u_island_sharpness": _inspector.get_value("island_sharpness"), - "u_island_height_ratio": _inspector.get_value("island_height_ratio"), - "u_island_shape": _inspector.get_value("island_shape"), - "u_additive_heightmap": additive_heightmap, - "u_additive_heightmap_factor": \ - (1.0 if additive_heightmap != null else 0.0) / preview_scale, - "u_terrain_size": terrain_size / preview_scale, - "u_tile_size": _viewport_resolution - } - _generator.add_pass(p) - - if erosion_iterations > 0: - p = HT_TextureGeneratorPass.new() - p.shader = get_shader("erode") - # TODO More erosion config - p.params = { - "u_slope_factor": _inspector.get_value("erosion_slope_factor"), - "u_slope_invert": _inspector.get_value("erosion_slope_invert"), - "u_slope_up": _inspector.get_value("erosion_slope_direction"), - "u_weight": _inspector.get_value("erosion_weight"), - "u_dilation": _inspector.get_value("dilation") - } - p.iterations = erosion_iterations - p.padding = p.iterations - _generator.add_pass(p) - - _generator.add_output({ - "maptype": HTerrainData.CHANNEL_HEIGHT, - "sector": sector, - "progress": progress - }) - - p = HT_TextureGeneratorPass.new() - p.shader = get_shader("bump2normal") - p.padding = 1 - _generator.add_pass(p) - - _generator.add_output({ - "maptype": HTerrainData.CHANNEL_NORMAL, - "sector": sector, - "progress": progress - }) - - # TODO AO generation - # TODO Splat generation - _generator.run() - - -func _on_CancelButton_pressed(): - hide() - - -func _on_ApplyButton_pressed(): - # We used to hide the dialog when the Apply button is clicked, and then texture generation took - # place in an offscreen viewport in multiple tiled stages, with a progress window being shown. - # But in Godot 4, it turns out SubViewports never update if they are child of a hidden Window, - # even if they are set to UPDATE_ALWAYS... - #hide() - - _apply() - - -func _on_Inspector_property_changed(key, value): - match key: - "show_sea": - _preview.set_sea_visible(value) - "shadows": - _preview.set_shadows_enabled(value) - _: - _update_generator(true) - - -func _on_TerrainPreview_dragged(relative: Vector2, button_mask: int): - if button_mask & MOUSE_BUTTON_MASK_LEFT: - var offset : Vector2 = _inspector.get_value("offset") - offset += relative - _inspector.set_value("offset", offset) - - -func _apply(): - if _terrain == null: - _logger.error("cannot apply, terrain is null") - return - - var data := _terrain.get_data() - if data == null: - _logger.error("cannot apply, terrain data is null") - return - - var dst_heights := data.get_image(HTerrainData.CHANNEL_HEIGHT) - if dst_heights == null: - _logger.error("terrain heightmap image isn't loaded") - return - - var dst_normals := data.get_image(HTerrainData.CHANNEL_NORMAL) - if dst_normals == null: - _logger.error("terrain normal image isn't loaded") - return - - _applying = true - - _undo_map_ids[HTerrainData.CHANNEL_HEIGHT] = _image_cache.save_image(dst_heights) - _undo_map_ids[HTerrainData.CHANNEL_NORMAL] = _image_cache.save_image(dst_normals) - - _update_generator(false) - - -func _on_TextureGenerator_progress_reported(info: Dictionary): - if _applying: - return - var p := 0.0 - if info.pass_index == 1: - p = float(info.iteration) / float(info.iteration_count) - _progress_bar.show() - _progress_bar.ratio = p - - -func _on_TextureGenerator_output_generated(image: Image, info: Dictionary): - # TODO We should check the terrain's image format, - # but that would prevent from testing in isolation... - if info.maptype == HTerrainData.CHANNEL_HEIGHT: - # Hack to workaround Godot 4.0 not supporting RF viewports. Heights are packed as floats - # into RGBA8 components. - assert(image.get_format() == Image.FORMAT_RGBA8) - image = Image.create_from_data(image.get_width(), image.get_height(), false, - Image.FORMAT_RF, image.get_data()) - - if not _applying: - # Update preview - # TODO Improve TextureGenerator so we can get a ViewportTexture per output? - var tex = _generated_textures[info.maptype] - if tex == null: - tex = ImageTexture.create_from_image(image) - _generated_textures[info.maptype] = tex - else: - tex.update(image) - - var num_set := 0 - for v in _generated_textures: - if v != null: - num_set += 1 - if num_set == len(_generated_textures): - _preview.setup( \ - _generated_textures[HTerrainData.CHANNEL_HEIGHT], - _generated_textures[HTerrainData.CHANNEL_NORMAL]) - else: - assert(_terrain != null) - var data := _terrain.get_data() - assert(data != null) - var dst := data.get_image(info.maptype) - assert(dst != null) -# print("Tile ", info.sector) -# image.save_png(str("debug_generator_tile_", -# info.sector.x, "_", info.sector.y, "_map", info.maptype, ".png")) - - # Converting in case Viewport texture isn't the format we expect for this map. - # Note, in Godot 4 it seems the chosen renderer also influences what you get. - # Forward+ non-transparent viewport gives RGB8, but Compatibility gives RGBA8. - # I don't know if it's expected or is a bug... - # Also, since RF heightmaps we use RGBA8 so we can pack floats in pixels, because - # Godot 4.0 does not support RF viewports. But that also means the same viewport may be - # re-used for other maps that don't need to be RGBA8. - if image.get_format() != dst.get_format(): - image.convert(dst.get_format()) - - dst.blit_rect(image, \ - Rect2i(0, 0, image.get_width(), image.get_height()), \ - info.sector * _viewport_resolution) - - _notify_progress({ - "progress": info.progress, - "message": "Calculating sector (" - + str(info.sector.x) + ", " + str(info.sector.y) + ")" - }) - -# if info.maptype == HTerrainData.CHANNEL_NORMAL: -# image.save_png(str("normal_sector_", info.sector.x, "_", info.sector.y, ".png")) - - -func _on_TextureGenerator_completed(): - _progress_bar.hide() - - if not _applying: - return - _applying = false - - assert(_terrain != null) - var data : HTerrainData = _terrain.get_data() - var resolution := data.get_resolution() - data.notify_region_change(Rect2(0, 0, resolution, resolution), HTerrainData.CHANNEL_HEIGHT) - - var redo_map_ids := {} - for map_type in _undo_map_ids: - redo_map_ids[map_type] = _image_cache.save_image(data.get_image(map_type)) - - var undo_redo := _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(data)) - - data._edit_set_disable_apply_undo(true) - undo_redo.create_action("Generate terrain") - undo_redo.add_do_method(data._edit_apply_maps_from_file_cache.bind(_image_cache, redo_map_ids)) - undo_redo.add_undo_method( - data._edit_apply_maps_from_file_cache.bind(_image_cache, _undo_map_ids)) - undo_redo.commit_action() - data._edit_set_disable_apply_undo(false) - - _notify_progress({ "finished": true }) - _logger.debug("Done") - - hide() - - -func _notify_progress(info: Dictionary): - _progress_window.handle_progress(info) - - -func _process(delta): - if _applying: - # HACK to workaround a peculiar behavior of Viewports in Godot 4. - # Apparently Godot 4 will not update Viewports set to UPDATE_ALWAYS when the editor decides - # it doesn't need to redraw ("low processor mode", what makes the editor redraw only with - # changes). That wasn't the case in Godot 3, but I guess it is now. - # That means when we click Apply, the viewport will not update in particular when doing - # erosion passes, because the action of clicking Apply doesn't lead to as many redraws as - # changing preview parameters in the UI (those cause redraws for different reasons). - # So let's poke the renderer by redrawing something... - # - # This also piles on top of the workaround in which we keep the window visible when - # applying! So the window has one more reason to stay visible... - # - _preview.queue_redraw() - diff --git a/addons/zylann.hterrain/tools/generator/generator_dialog.tscn b/addons/zylann.hterrain/tools/generator/generator_dialog.tscn deleted file mode 100644 index 5d911e3..0000000 --- a/addons/zylann.hterrain/tools/generator/generator_dialog.tscn +++ /dev/null @@ -1,84 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://cgfo1ocbdi1ug"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/generator/generator_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/inspector/inspector.tscn" id="2"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/terrain_preview.tscn" id="3"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="4"] - -[node name="GeneratorDialog" type="AcceptDialog"] -title = "Generate terrain" -size = Vector2i(1100, 780) -min_size = Vector2i(1100, 620) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="Editor" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Settings" type="VBoxContainer" parent="VBoxContainer/Editor"] -custom_minimum_size = Vector2(420, 0) -layout_mode = 2 - -[node name="Inspector" parent="VBoxContainer/Editor/Settings" instance=ExtResource("2")] -layout_mode = 2 - -[node name="Preview" type="Control" parent="VBoxContainer/Editor"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="TerrainPreview" parent="VBoxContainer/Editor/Preview" instance=ExtResource("3")] -layout_mode = 1 -anchors_preset = 15 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="Label" type="Label" parent="VBoxContainer/Editor/Preview"] -layout_mode = 0 -offset_left = 5.0 -offset_top = 4.0 -offset_right = 207.0 -offset_bottom = 18.0 -text = "LMB: offset, MMB: rotate" - -[node name="ProgressBar" type="ProgressBar" parent="VBoxContainer/Editor/Preview"] -layout_mode = 1 -anchors_preset = -1 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -35.0 -step = 1.0 - -[node name="Choices" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="ApplyButton" type="Button" parent="VBoxContainer/Choices"] -layout_mode = 2 -text = "Apply" - -[node name="CancelButton" type="Button" parent="VBoxContainer/Choices"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("4")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 1092.0 -offset_bottom = 762.0 - -[connection signal="property_changed" from="VBoxContainer/Editor/Settings/Inspector" to="." method="_on_Inspector_property_changed"] -[connection signal="dragged" from="VBoxContainer/Editor/Preview/TerrainPreview" to="." method="_on_TerrainPreview_dragged"] -[connection signal="pressed" from="VBoxContainer/Choices/ApplyButton" to="." method="_on_ApplyButton_pressed"] -[connection signal="pressed" from="VBoxContainer/Choices/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader b/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader deleted file mode 100644 index 7dd9714..0000000 --- a/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader +++ /dev/null @@ -1,27 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -//uniform sampler2D u_screen_texture : hint_screen_texture; -uniform sampler2D u_previous_pass; - -vec4 pack_normal(vec3 n) { - return vec4((0.5 * (n + 1.0)).xzy, 1.0); -} - -float get_height(sampler2D tex, vec2 uv) { - return sample_height_from_viewport(tex, uv); -} - -void fragment() { - vec2 uv = SCREEN_UV; - vec2 ps = SCREEN_PIXEL_SIZE; - float left = get_height(u_previous_pass, uv + vec2(-ps.x, 0)); - float right = get_height(u_previous_pass, uv + vec2(ps.x, 0)); - float back = get_height(u_previous_pass, uv + vec2(0, -ps.y)); - float fore = get_height(u_previous_pass, uv + vec2(0, ps.y)); - vec3 n = normalize(vec3(left - right, 2.0, fore - back)); - COLOR = pack_normal(n); -} - diff --git a/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader b/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader deleted file mode 100644 index 6f45e1c..0000000 --- a/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader +++ /dev/null @@ -1,76 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform vec2 u_slope_up = vec2(0, 0); -uniform float u_slope_factor = 1.0; -uniform bool u_slope_invert = false; -uniform float u_weight = 0.5; -uniform float u_dilation = 0.0; -//uniform sampler2D u_screen_texture : hint_screen_texture; -uniform sampler2D u_previous_pass; - -float get_height(sampler2D tex, vec2 uv) { - return sample_height_from_viewport(tex, uv); -} - -void fragment() { - float r = 3.0; - - // Divide so the shader stays neighbor dependent 1 pixel across. - // For this to work, filtering must be enabled. - vec2 eps = SCREEN_PIXEL_SIZE / (0.99 * r); - - vec2 uv = SCREEN_UV; - float h = get_height(u_previous_pass, uv); - float eh = h; - float dh = h; - - // Morphology with circular structuring element - for (float y = -r; y <= r; ++y) { - for (float x = -r; x <= r; ++x) { - - vec2 p = vec2(float(x), float(y)); - float nh = get_height(u_previous_pass, uv + p * eps); - - float s = max(length(p) - r, 0); - eh = min(eh, nh + s); - - s = min(r - length(p), 0); - dh = max(dh, nh + s); - } - } - - eh = mix(h, eh, u_weight); - dh = mix(h, dh, u_weight); - - float ph = mix(eh, dh, u_dilation); - - if (u_slope_factor > 0.0) { - vec2 ps = SCREEN_PIXEL_SIZE; - - float left = get_height(u_previous_pass, uv + vec2(-ps.x, 0.0)); - float right = get_height(u_previous_pass, uv + vec2(ps.x, 0.0)); - float top = get_height(u_previous_pass, uv + vec2(0.0, ps.y)); - float bottom = get_height(u_previous_pass, uv + vec2(0.0, -ps.y)); - - vec3 normal = normalize(vec3(left - right, ps.x + ps.y, bottom - top)); - vec3 up = normalize(vec3(u_slope_up.x, 1.0, u_slope_up.y)); - - float f = max(dot(normal, up), 0); - if (u_slope_invert) { - f = 1.0 - f; - } - - ph = mix(h, ph, mix(1.0, f, u_slope_factor)); - //COLOR = vec4(f, f, f, 1.0); - } - - //COLOR = vec4(0.5 * normal + 0.5, 1.0); - - //eh = 0.5 * (eh + texture(SCREEN_TEXTURE, uv + mp * ps * k).r); - //eh = mix(h, eh, (1.0 - h) / r); - - COLOR = encode_height_to_viewport(ph); -} diff --git a/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader b/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader deleted file mode 100644 index 7609f7c..0000000 --- a/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader +++ /dev/null @@ -1,211 +0,0 @@ -shader_type canvas_item; -// Required only because we use all 4 channels to encode floats into RGBA8 -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform vec2 u_offset; -uniform float u_scale = 0.02; -uniform float u_base_height = 0.0; -uniform float u_height_range = 100.0; -uniform int u_seed; -uniform int u_octaves = 5; -uniform float u_roughness = 0.5; -uniform float u_curve = 1.0; -uniform float u_terrain_size = 513.0; -uniform float u_tile_size = 513.0; -uniform sampler2D u_additive_heightmap; -uniform float u_additive_heightmap_factor = 0.0; -uniform vec2 u_uv_offset; -uniform vec2 u_uv_scale = vec2(1.0, 1.0); - -uniform float u_island_weight = 0.0; -// 0: smooth transition, 1: sharp transition -uniform float u_island_sharpness = 0.0; -// 0: edge is min height (island), 1: edge is max height (canyon) -uniform float u_island_height_ratio = 0.0; -// 0: round, 1: square -uniform float u_island_shape = 0.0; - -//////////////////////////////////////////////////////////////////////////////// -// Perlin noise source: -// https://github.com/curly-brace/Godot-3.0-Noise-Shaders -// -// GLSL textureless classic 2D noise \"cnoise\", -// with an RSL-style periodic variant \"pnoise\". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-08-22 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/stegu/webgl-noise -// - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) { - return mod289(((x * 34.0) + 1.0) * x); -} - -vec4 taylorInvSqrt(vec4 r) { - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec2 fade(vec2 t) { - return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); -} - -// Classic Perlin noise -float cnoise(vec2 P) { - vec4 Pi = floor(vec4(P, P)) + vec4(0.0, 0.0, 1.0, 1.0); - vec4 Pf = fract(vec4(P, P)) - vec4(0.0, 0.0, 1.0, 1.0); - Pi = mod289(Pi); // To avoid truncation effects in permutation - vec4 ix = Pi.xzxz; - vec4 iy = Pi.yyww; - vec4 fx = Pf.xzxz; - vec4 fy = Pf.yyww; - - vec4 i = permute(permute(ix) + iy); - - vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ; - vec4 gy = abs(gx) - 0.5 ; - vec4 tx = floor(gx + 0.5); - gx = gx - tx; - - vec2 g00 = vec2(gx.x,gy.x); - vec2 g10 = vec2(gx.y,gy.y); - vec2 g01 = vec2(gx.z,gy.z); - vec2 g11 = vec2(gx.w,gy.w); - - vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - - float n00 = dot(g00, vec2(fx.x, fy.x)); - float n10 = dot(g10, vec2(fx.y, fy.y)); - float n01 = dot(g01, vec2(fx.z, fy.z)); - float n11 = dot(g11, vec2(fx.w, fy.w)); - - vec2 fade_xy = fade(Pf.xy); - vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x); - float n_xy = mix(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; -} -//////////////////////////////////////////////////////////////////////////////// - -float get_fractal_noise(vec2 uv) { - float scale = 1.0; - float sum = 0.0; - float amp = 0.0; - int octaves = u_octaves; - float p = 1.0; - uv.x += float(u_seed) * 61.0; - - for (int i = 0; i < octaves; ++i) { - sum += p * cnoise(uv * scale); - amp += p; - scale *= 2.0; - p *= u_roughness; - } - - float gs = sum / amp; - return gs; -} - -// x is a ratio in 0..1 -float get_island_curve(float x) { - return smoothstep(min(0.999, u_island_sharpness), 1.0, x); -// float exponent = 1.0 + 10.0 * u_island_sharpness; -// return pow(abs(x), exponent); -} - -float smooth_union(float a, float b, float k) { - float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0); - return mix(b, a, h) - k * h * (1.0 - h); -} - -float squareish_distance(vec2 a, vec2 b, float r, float s) { - vec2 v = b - a; - // TODO This is brute force but this is the first attempt that gave me a "rounded square" distance, - // where the "roundings" remained constant over distance (not the case with standard box SDF) - float da = -smooth_union(v.x+s, v.y+s, r)+s; - float db = -smooth_union(s-v.x, s-v.y, r)+s; - float dc = -smooth_union(s-v.x, v.y+s, r)+s; - float dd = -smooth_union(v.x+s, s-v.y, r)+s; - return max(max(da, db), max(dc, dd)); -} - -// This is too sharp -//float squareish_distance(vec2 a, vec2 b) { -// vec2 v = b - a; -// // Manhattan distance would produce a "diamond-shaped distance". -// // This gives "square-shaped" distance. -// return max(abs(v.x), abs(v.y)); -//} - -float get_island_distance(vec2 pos, vec2 center, float terrain_size) { - float rd = distance(pos, center); - float sd = squareish_distance(pos, center, terrain_size * 0.1, terrain_size); - return mix(rd, sd, u_island_shape); -} - -// pos is in terrain space -float get_height(vec2 pos) { - float h = 0.0; - - { - // Noise (0..1) - // Offset and scale for the noise itself - vec2 uv_noise = (pos / u_terrain_size + u_offset) * u_scale; - h = 0.5 + 0.5 * get_fractal_noise(uv_noise); - } - - // Curve - { - h = pow(h, u_curve); - } - - // Island - { - float terrain_size = u_terrain_size; - vec2 island_center = vec2(0.5 * terrain_size); - float island_height_ratio = 0.5 + 0.5 * u_island_height_ratio; - float island_distance = get_island_distance(pos, island_center, terrain_size); - float distance_ratio = clamp(island_distance / (0.5 * terrain_size), 0.0, 1.0); - float island_ratio = u_island_weight * get_island_curve(distance_ratio); - h = mix(h, island_height_ratio, island_ratio); - } - - // Height remapping - { - h = u_base_height + h * u_height_range; - } - - // Additive heightmap - { - vec2 uv = pos / u_terrain_size; - float ah = sample_heightmap(u_additive_heightmap, uv); - h += u_additive_heightmap_factor * ah; - } - - return h; -} - -void fragment() { - // Handle screen padding: transform UV back into generation space. - // This is in tile space actually...? it spans 1 unit across the viewport, - // and starts from 0 when tile (0,0) is generated. - // Maybe we could change this into world units instead? - vec2 uv_tile = (SCREEN_UV + u_uv_offset) * u_uv_scale; - - float h = get_height(uv_tile * u_tile_size); - - COLOR = encode_height_to_viewport(h); -} diff --git a/addons/zylann.hterrain/tools/generator/texture_generator.gd b/addons/zylann.hterrain/tools/generator/texture_generator.gd deleted file mode 100644 index 0caaf7c..0000000 --- a/addons/zylann.hterrain/tools/generator/texture_generator.gd +++ /dev/null @@ -1,331 +0,0 @@ -# Holds a viewport on which several passes may run to generate a final image. -# Passes can have different shaders and re-use what was drawn by a previous pass. -# TODO I'd like to make such a system working as a graph of passes for more possibilities. - -@tool -extends Node - -const HT_Util = preload("res://addons/zylann.hterrain/util/util.gd") -const HT_TextureGeneratorPass = preload("./texture_generator_pass.gd") -const HT_Logger = preload("../../util/logger.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const DUMMY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal progress_reported(info) -# Emitted when an output is generated. -signal output_generated(image, metadata) -# Emitted when all passes are complete -signal completed - -class HT_TextureGeneratorViewport: - var viewport : SubViewport - var ci : TextureRect - -var _passes := [] -var _resolution := Vector2i(512, 512) -var _output_padding := [0, 0, 0, 0] - -# Since Godot 4.0, we use ping-pong viewports because `hint_screen_texture` always returns `1.0` -# for transparent pixels, which is wrong, but sadly appears to be intented... -# https://github.com/godotengine/godot/issues/78207 -var _viewports : Array[HT_TextureGeneratorViewport] = [null, null] -var _viewport_index := 0 - -var _dummy_texture : Texture2D -var _running := false -var _rerun := false -#var _tiles = PoolVector2Array([Vector2()]) - -var _running_passes := [] -var _running_pass_index := 0 -var _running_iteration := 0 -var _shader_material : ShaderMaterial = null -#var _uv_offset = 0 # Offset de to padding - -var _logger = HT_Logger.get_for(self) - - -func _ready(): - _dummy_texture = load(DUMMY_TEXTURE_PATH) - if _dummy_texture == null: - _logger.error(str("Failed to load dummy texture ", DUMMY_TEXTURE_PATH)) - - for viewport_index in len(_viewports): - var viewport = SubViewport.new() - # We render with 2D shaders, but we don't want the parent world to interfere - viewport.own_world_3d = true - viewport.world_3d = World3D.new() - viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - # Require RGBA8 so we can pack heightmap floats into pixels - viewport.transparent_bg = true - add_child(viewport) - - var ci := TextureRect.new() - ci.stretch_mode = TextureRect.STRETCH_SCALE - ci.texture = _dummy_texture - viewport.add_child(ci) - - var vp := HT_TextureGeneratorViewport.new() - vp.viewport = viewport - vp.ci = ci - _viewports[viewport_index] = vp - - _shader_material = ShaderMaterial.new() - - set_process(false) - - -func is_running() -> bool: - return _running - - -func clear_passes(): - _passes.clear() - - -func add_pass(p: HT_TextureGeneratorPass): - assert(_passes.find(p) == -1) - assert(p.iterations > 0) - _passes.append(p) - - -func add_output(meta): - assert(len(_passes) > 0) - var p = _passes[-1] - p.output = true - p.metadata = meta - - -# Sets at which base resolution the generator will work on. -# In tiled rendering, this is the resolution of one tile. -# The internal viewport may be larger if some passes need more room, -# and the resulting images might include some of these pixels if output padding is used. -func set_resolution(res: Vector2i): - assert(not _running) - _resolution = res - - -# Tell image outputs to include extra pixels on the edges. -# This extends the resolution of images compared to the base resolution. -# The initial use case for this is to generate terrain tiles where edge pixels are -# shared with the neighor tiles. -func set_output_padding(p: Array): - assert(typeof(p) == TYPE_ARRAY) - assert(len(p) == 4) - for v in p: - assert(typeof(v) == TYPE_INT) - _output_padding = p - - -func run(): - assert(len(_passes) > 0) - - if _running: - _rerun = true - return - - for vp in _viewports: - assert(vp.viewport != null) - assert(vp.ci != null) - - # Copy passes - var passes := [] - passes.resize(len(_passes)) - for i in len(_passes): - passes[i] = _passes[i].duplicate() - _running_passes = passes - - # Pad pixels according to largest padding - var largest_padding := 0 - for p in passes: - if p.padding > largest_padding: - largest_padding = p.padding - for v in _output_padding: - if v > largest_padding: - largest_padding = v - var padded_size := _resolution + 2 * Vector2i(largest_padding, largest_padding) - -# _uv_offset = Vector2( \ -# float(largest_padding) / padded_size.x, -# float(largest_padding) / padded_size.y) - - for vp in _viewports: - vp.ci.size = padded_size - vp.viewport.size = padded_size - - # First viewport index doesn't matter. - # Maybe one issue of resetting it to zero would be that the previous run - # could have ended with the same viewport that will be sent as a texture as - # one of the uniforms of the shader material, which causes an error in the - # renderer because it's not allowed to use a viewport texture while - # rendering on the same viewport -# _viewport_index = 0 - - var first_vp := _viewports[_viewport_index] - first_vp.viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - # I don't trust `UPDATE_ONCE`, it also doesn't reset so we never know if it actually works... - # https://github.com/godotengine/godot/issues/33351 - first_vp.viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS - - for vp in _viewports: - if vp != first_vp: - vp.viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - - _running_pass_index = 0 - _running_iteration = 0 - _running = true - set_process(true) - - -func _process(delta: float): - # TODO because of https://github.com/godotengine/godot/issues/7894 - if not is_processing(): - return - - var prev_vpi := 0 if _viewport_index == 1 else 1 - var prev_vp := _viewports[prev_vpi] - - if _running_pass_index > 0: - var prev_pass : HT_TextureGeneratorPass = _running_passes[_running_pass_index - 1] - if prev_pass.output: - _create_output_image(prev_pass.metadata, prev_vp) - - if _running_pass_index >= len(_running_passes): - _running = false - - completed.emit() - - if _rerun: - # run() was requested again before we complete... - # this will happen very frequently because we are forced to wait multiple frames - # before getting a result - _rerun = false - run() - else: - # Done - for vp in _viewports: - vp.viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - set_process(false) - return - - var p : HT_TextureGeneratorPass = _running_passes[_running_pass_index] - - var vp := _viewports[_viewport_index] - vp.viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS - prev_vp.viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - - if _running_iteration == 0: - _setup_pass(p, vp) - - _setup_iteration(vp, prev_vp) - - _report_progress(_running_passes, _running_pass_index, _running_iteration) - # Wait one frame for render, and this for EVERY iteration and every pass, - # because Godot doesn't provide any way to run multiple feedback render passes in one go. - _running_iteration += 1 - - if _running_iteration == p.iterations: - _running_iteration = 0 - _running_pass_index += 1 - - # Swap viewport for next pass - _viewport_index = (_viewport_index + 1) % 2 - - # The viewport should render after the tree was processed - - -# Called at the beginning of each pass -func _setup_pass(p: HT_TextureGeneratorPass, vp: HT_TextureGeneratorViewport): - if p.texture != null: - vp.ci.texture = p.texture - else: - vp.ci.texture = _dummy_texture - - if p.shader != null: - if _shader_material == null: - _shader_material = ShaderMaterial.new() - _shader_material.shader = p.shader - - vp.ci.material = _shader_material - - if p.params != null: - for param_name in p.params: - _shader_material.set_shader_parameter(param_name, p.params[param_name]) - - var vp_size_f := Vector2(vp.viewport.size) - var res_f := Vector2(_resolution) - var scale_ndc := vp_size_f / res_f - var pad_offset_ndc := ((vp_size_f - res_f) / 2.0) / vp_size_f - var offset_ndc := -pad_offset_ndc + p.tile_pos / scale_ndc - - # Because padding may be used around the generated area, - # the shader can use these predefined parameters, - # and apply the following to SCREEN_UV to adjust its calculations: - # vec2 uv = (SCREEN_UV + u_uv_offset) * u_uv_scale; - - if p.params == null or not p.params.has("u_uv_scale"): - _shader_material.set_shader_parameter("u_uv_scale", scale_ndc) - - if p.params == null or not p.params.has("u_uv_offset"): - _shader_material.set_shader_parameter("u_uv_offset", offset_ndc) - - else: - vp.ci.material = null - - if p.clear: - vp.viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - - -# Called for every iteration of every pass -func _setup_iteration(vp: HT_TextureGeneratorViewport, prev_vp: HT_TextureGeneratorViewport): - assert(vp != prev_vp) - if _shader_material != null: - _shader_material.set_shader_parameter("u_previous_pass", prev_vp.viewport.get_texture()) - - -func _create_output_image(metadata, vp: HT_TextureGeneratorViewport): - var tex := vp.viewport.get_texture() - var src := tex.get_image() -# src.save_png(str("ddd_tgen_output", metadata.maptype, ".png")) - - # Pick the center of the image - var subrect := Rect2i( \ - (src.get_width() - _resolution.x) / 2, \ - (src.get_height() - _resolution.y) / 2, \ - _resolution.x, _resolution.y) - - # Make sure we are pixel-perfect. If not, padding is odd -# assert(int(subrect.position.x) == subrect.position.x) -# assert(int(subrect.position.y) == subrect.position.y) - - subrect.position.x -= _output_padding[0] - subrect.position.y -= _output_padding[2] - subrect.size.x += _output_padding[0] + _output_padding[1] - subrect.size.y += _output_padding[2] + _output_padding[3] - - var dst : Image - if subrect == Rect2i(0, 0, src.get_width(), src.get_height()): - dst = src - else: - # Note: size MUST match at this point. - # If it doesn't, the viewport has not been configured properly, - # or padding has been modified while the generator was running - dst = Image.create( \ - _resolution.x + _output_padding[0] + _output_padding[1], \ - _resolution.y + _output_padding[2] + _output_padding[3], \ - false, src.get_format()) - dst.blit_rect(src, subrect, Vector2i()) - - output_generated.emit(dst, metadata) - - -func _report_progress(passes: Array, pass_index: int, iteration: int): - var p = passes[pass_index] - progress_reported.emit({ - "name": p.debug_name, - "pass_index": pass_index, - "pass_count": len(passes), - "iteration": iteration, - "iteration_count": p.iterations - }) - diff --git a/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd b/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd deleted file mode 100644 index 76745f1..0000000 --- a/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd +++ /dev/null @@ -1,43 +0,0 @@ - -# Name of the pass, for debug purposes -var debug_name := "" -# The viewport will be cleared at this pass -var clear := false -# Which main texture should be drawn. -# If not set, a default texture will be drawn. -# Note that it won't matter if the shader disregards it, -# and will only serve to provide UVs, due to https://github.com/godotengine/godot/issues/7298. -var texture : Texture = null -# Which shader to use -var shader : Shader = null -# Parameters for the shader -# TODO Use explicit Dictionary, dont allow null -var params = null -# How many pixels to pad the viewport on all edges, in case neighboring matters. -# Outputs won't have that padding, but can pick part of it in case output padding is used. -var padding := 0 -# How many times this pass must be run -var iterations := 1 -# If not empty, the viewport will be downloaded as an image before the next pass -var output := false -# Sent along the output -var metadata = null -# Used for tiled rendering, where each tile has the base resolution, -# in case the viewport cannot be made big enough to cover the final image, -# of if you are generating a pseudo-infinite terrain. -# TODO Have an API for this? -var tile_pos := Vector2() - -func duplicate(): - var p = get_script().new() - p.debug_name = debug_name - p.clear = clear - p.texture = texture - p.shader = shader - p.params = params - p.padding = padding - p.iterations = iterations - p.output = output - p.metadata = metadata - p.tile_pos = tile_pos - return p diff --git a/addons/zylann.hterrain/tools/globalmap_baker.gd b/addons/zylann.hterrain/tools/globalmap_baker.gd deleted file mode 100644 index 6faa0eb..0000000 --- a/addons/zylann.hterrain/tools/globalmap_baker.gd +++ /dev/null @@ -1,168 +0,0 @@ - -# Bakes a global albedo map using the same shader the terrain uses, -# but renders top-down in orthographic mode. - -@tool -extends Node - -const HTerrain = preload("../hterrain.gd") -const HTerrainData = preload("../hterrain_data.gd") -const HTerrainMesher = preload("../hterrain_mesher.gd") - -# Must be power of two -const DEFAULT_VIEWPORT_SIZE = 512 - -signal progress_notified(info) -signal permanent_change_performed(message) - -var _terrain : HTerrain = null -var _viewport : SubViewport = null -var _viewport_size := DEFAULT_VIEWPORT_SIZE -var _plane : MeshInstance3D = null -var _camera : Camera3D = null -var _sectors := [] -var _sector_index := 0 - - -func _ready(): - set_process(false) - - -func bake(terrain: HTerrain): - assert(terrain != null) - var data := terrain.get_data() - assert(data != null) - _terrain = terrain - - var splatmap := data.get_texture(HTerrainData.CHANNEL_SPLAT) - var colormap := data.get_texture(HTerrainData.CHANNEL_COLOR) - - var terrain_size := data.get_resolution() - - if _viewport == null: - _setup_scene(terrain_size) - - var cw := terrain_size / _viewport_size - var ch := terrain_size / _viewport_size - for y in ch: - for x in cw: - _sectors.append(Vector2(x, y)) - - var mat := _plane.material_override - _terrain.setup_globalmap_material(mat) - - _sector_index = 0 - set_process(true) - - -func _setup_scene(terrain_size: int): - assert(_viewport == null) - - _viewport_size = DEFAULT_VIEWPORT_SIZE - while _viewport_size > terrain_size: - _viewport_size /= 2 - - _viewport = SubViewport.new() - _viewport.size = Vector2(_viewport_size + 1, _viewport_size + 1) - _viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ALWAYS - # _viewport.render_target_v_flip = true - _viewport.world_3d = World3D.new() - _viewport.own_world_3d = true - _viewport.debug_draw = Viewport.DEBUG_DRAW_UNSHADED - - var mat := ShaderMaterial.new() - - _plane = MeshInstance3D.new() - # Make a very small mesh, vertex precision isn't required - var plane_res := 4 - _plane.mesh = \ - HTerrainMesher.make_flat_chunk(plane_res, plane_res, _viewport_size / plane_res, 0) - _plane.material_override = mat - _viewport.add_child(_plane) - - _camera = Camera3D.new() - _camera.projection = Camera3D.PROJECTION_ORTHOGONAL - _camera.size = _viewport.size.x - _camera.near = 0.1 - _camera.far = 10.0 - _camera.current = true - _camera.rotation = Vector3(deg_to_rad(-90), 0, 0) - _viewport.add_child(_camera) - - add_child(_viewport) - - -func _cleanup_scene(): - _viewport.queue_free() - _viewport = null - _plane = null - _camera = null - - -func _process(delta): - if not is_processing(): - return - - if _sector_index > 0: - _grab_image(_sectors[_sector_index - 1]) - - if _sector_index >= len(_sectors): - set_process(false) - _finish() - progress_notified.emit({ "finished": true }) - else: - _setup_pass(_sectors[_sector_index]) - _report_progress() - _sector_index += 1 - - -func _report_progress(): - var sector = _sectors[_sector_index] - progress_notified.emit({ - "progress": float(_sector_index) / len(_sectors), - "message": "Calculating sector (" + str(sector.x) + ", " + str(sector.y) + ")" - }) - - -func _setup_pass(sector: Vector2): - # Note: we implicitely take off-by-one pixels into account - var origin := sector * _viewport_size - var center := origin + 0.5 * Vector2(_viewport.size) - - # The heightmap is left empty, so will default to white, which is a height of 1. - # The camera must be placed above the terrain to see it. - _camera.position = Vector3(center.x, 2.0, center.y) - _plane.position = Vector3(origin.x, 0.0, origin.y) - - -func _grab_image(sector: Vector2): - var tex := _viewport.get_texture() - var src := tex.get_image() - - assert(_terrain != null) - var data := _terrain.get_data() - assert(data != null) - - if data.get_map_count(HTerrainData.CHANNEL_GLOBAL_ALBEDO) == 0: - data._edit_add_map(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - - var dst := data.get_image(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - - src.convert(dst.get_format()) - var origin = sector * _viewport_size - dst.blit_rect(src, Rect2i(0, 0, src.get_width(), src.get_height()), origin) - - -func _finish(): - assert(_terrain != null) - var data := _terrain.get_data() as HTerrainData - assert(data != null) - var dst := data.get_image(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - - data.notify_region_change(Rect2(0, 0, dst.get_width(), dst.get_height()), - HTerrainData.CHANNEL_GLOBAL_ALBEDO) - permanent_change_performed.emit("Bake globalmap") - - _cleanup_scene() - _terrain = null diff --git a/addons/zylann.hterrain/tools/icons/empty.png b/addons/zylann.hterrain/tools/icons/empty.png deleted file mode 100644 index 0a59813..0000000 Binary files a/addons/zylann.hterrain/tools/icons/empty.png and /dev/null differ diff --git a/addons/zylann.hterrain/tools/icons/empty.png.import b/addons/zylann.hterrain/tools/icons/empty.png.import deleted file mode 100644 index 267b65d..0000000 --- a/addons/zylann.hterrain/tools/icons/empty.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vo2brkj3udel" -path="res://.godot/imported/empty.png-31363f083c9c4e2e8e54cf64f3716737.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/empty.png" -dest_files=["res://.godot/imported/empty.png-31363f083c9c4e2e8e54cf64f3716737.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg deleted file mode 100644 index f490172..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg.import deleted file mode 100644 index a5e8479..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://l16qrsohg7jj" -path="res://.godot/imported/icon_anchor_bottom.svg-963f115d31a41c38349ab03453cf2ef5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg" -dest_files=["res://.godot/imported/icon_anchor_bottom.svg-963f115d31a41c38349ab03453cf2ef5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg deleted file mode 100644 index 05f255a..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg.import deleted file mode 100644 index 861cc99..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://30wsjmeemngg" -path="res://.godot/imported/icon_anchor_bottom_left.svg-c59f20ff71f725e47b5fc556b5ef93c4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg" -dest_files=["res://.godot/imported/icon_anchor_bottom_left.svg-c59f20ff71f725e47b5fc556b5ef93c4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg deleted file mode 100644 index 33e97ef..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg.import deleted file mode 100644 index b24ab20..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cwb02kd3gr5v1" -path="res://.godot/imported/icon_anchor_bottom_right.svg-23dd5f1d1c7021fe105f8bde603dcc4d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg" -dest_files=["res://.godot/imported/icon_anchor_bottom_right.svg-23dd5f1d1c7021fe105f8bde603dcc4d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg deleted file mode 100644 index 8ab613a..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg.import deleted file mode 100644 index a0d694c..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bkphpwgf3vlqy" -path="res://.godot/imported/icon_anchor_center.svg-d48605c4035ec4a02ae8159aea6db85f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_center.svg" -dest_files=["res://.godot/imported/icon_anchor_center.svg-d48605c4035ec4a02ae8159aea6db85f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg deleted file mode 100644 index 7fd1a68..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg.import deleted file mode 100644 index 9d5b149..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmydngdawudhq" -path="res://.godot/imported/icon_anchor_left.svg-77f3e03e6fbadfd7e4dc1ab3661e6e7c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_left.svg" -dest_files=["res://.godot/imported/icon_anchor_left.svg-77f3e03e6fbadfd7e4dc1ab3661e6e7c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg deleted file mode 100644 index 8ad32f1..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg.import deleted file mode 100644 index 42b5b1c..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cut3xadorcxqt" -path="res://.godot/imported/icon_anchor_right.svg-90e3a37e8d38587bac01703849f8b9f7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_right.svg" -dest_files=["res://.godot/imported/icon_anchor_right.svg-90e3a37e8d38587bac01703849f8b9f7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg deleted file mode 100644 index e15ed1a..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg.import deleted file mode 100644 index 50e96dc..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cprd188dc3fc7" -path="res://.godot/imported/icon_anchor_top.svg-f1dcf93e569fe43b280b5dc072ee78e5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_top.svg" -dest_files=["res://.godot/imported/icon_anchor_top.svg-f1dcf93e569fe43b280b5dc072ee78e5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg deleted file mode 100644 index cd82a6f..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg.import deleted file mode 100644 index 832b11e..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bugm51ryp0urq" -path="res://.godot/imported/icon_anchor_top_left.svg-aea4438056394f9967bf74b13799fedc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg" -dest_files=["res://.godot/imported/icon_anchor_top_left.svg-aea4438056394f9967bf74b13799fedc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg b/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg deleted file mode 100644 index 4619493..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg.import b/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg.import deleted file mode 100644 index 146b057..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bebc1xsqguspq" -path="res://.godot/imported/icon_anchor_top_right.svg-e9f520f41c9c20cc5e64aca56427ca01.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg" -dest_files=["res://.godot/imported/icon_anchor_top_right.svg-e9f520f41c9c20cc5e64aca56427ca01.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg b/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg deleted file mode 100644 index f5d8156..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg.import b/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg.import deleted file mode 100644 index 941c747..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://6jmdwj3vn6m0" -path="res://.godot/imported/icon_detail_layer_node.svg-70daba484432569847b1d2fe22768af3.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg" -dest_files=["res://.godot/imported/icon_detail_layer_node.svg-70daba484432569847b1d2fe22768af3.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_grass.svg b/addons/zylann.hterrain/tools/icons/icon_grass.svg deleted file mode 100644 index 7866628..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_grass.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_grass.svg.import b/addons/zylann.hterrain/tools/icons/icon_grass.svg.import deleted file mode 100644 index ad48667..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_grass.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://coicfqoi4spg0" -path="res://.godot/imported/icon_grass.svg-6a20eb11bc23d46b8a4c0f365f95554b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_grass.svg" -dest_files=["res://.godot/imported/icon_grass.svg-6a20eb11bc23d46b8a4c0f365f95554b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg deleted file mode 100644 index 2b20f6a..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg.import deleted file mode 100644 index a72fade..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://t1m58v6iitwb" -path="res://.godot/imported/icon_heightmap_color.svg-2b3375697cab4a6c7b8d933fc7f2b982.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg" -dest_files=["res://.godot/imported/icon_heightmap_color.svg-2b3375697cab4a6c7b8d933fc7f2b982.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg deleted file mode 100644 index 03c0caf..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg.import deleted file mode 100644 index 9db362d..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cd13q0qxqt8cd" -path="res://.godot/imported/icon_heightmap_data.svg-00236b6035ce13dd687a19d98237bdbd.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg" -dest_files=["res://.godot/imported/icon_heightmap_data.svg-00236b6035ce13dd687a19d98237bdbd.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg deleted file mode 100644 index 22824a2..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg.import deleted file mode 100644 index c1424e6..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ci3jif8wx2tig" -path="res://.godot/imported/icon_heightmap_erode.svg-fad285f0810d69bec16027ac0257c223.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg" -dest_files=["res://.godot/imported/icon_heightmap_erode.svg-fad285f0810d69bec16027ac0257c223.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg deleted file mode 100644 index c4d3268..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg.import deleted file mode 100644 index 9c1c4bf..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://6bnt8lvvabf1" -path="res://.godot/imported/icon_heightmap_flatten.svg-3d183c33fce9f34c419c53418ef26264.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg" -dest_files=["res://.godot/imported/icon_heightmap_flatten.svg-3d183c33fce9f34c419c53418ef26264.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg deleted file mode 100644 index d7c27e9..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg.import deleted file mode 100644 index 29294ec..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c6trw4wyo86x4" -path="res://.godot/imported/icon_heightmap_level.svg-0abbb78afcf28f4da15188c85861a768.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg" -dest_files=["res://.godot/imported/icon_heightmap_level.svg-0abbb78afcf28f4da15188c85861a768.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg deleted file mode 100644 index 87101c3..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg.import deleted file mode 100644 index 97163b3..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://da02ckrgusaoe" -path="res://.godot/imported/icon_heightmap_lower.svg-5bb5cae46ea03f9d65d6c497a65882db.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg" -dest_files=["res://.godot/imported/icon_heightmap_lower.svg-5bb5cae46ea03f9d65d6c497a65882db.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg deleted file mode 100644 index 751b683..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg.import deleted file mode 100644 index 7305e92..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://btb4kkafvn67j" -path="res://.godot/imported/icon_heightmap_mask.svg-3fad663c59a229c1c6c17c4e8d5bad09.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg" -dest_files=["res://.godot/imported/icon_heightmap_mask.svg-3fad663c59a229c1c6c17c4e8d5bad09.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg deleted file mode 100644 index 00fb889..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg.import deleted file mode 100644 index aa38f33..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ofs3osrmxfi" -path="res://.godot/imported/icon_heightmap_node.svg-0b776ad0015c7d9d9553b161b36e70fe.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg" -dest_files=["res://.godot/imported/icon_heightmap_node.svg-0b776ad0015c7d9d9553b161b36e70fe.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg deleted file mode 100644 index 00fb889..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg.import deleted file mode 100644 index 3478c92..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://sdaddk8wxjin" -path="res://.godot/imported/icon_heightmap_node_large.svg-4b8ff9077cb0d8dc06efcf638cce1edb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg" -dest_files=["res://.godot/imported/icon_heightmap_node_large.svg-4b8ff9077cb0d8dc06efcf638cce1edb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=8.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg deleted file mode 100644 index 72503fa..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg.import deleted file mode 100644 index 8d325c1..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cgw6r4eg1msvn" -path="res://.godot/imported/icon_heightmap_paint.svg-ad4c1d13ab344959f8e60b793d52d80d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg" -dest_files=["res://.godot/imported/icon_heightmap_paint.svg-ad4c1d13ab344959f8e60b793d52d80d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg deleted file mode 100644 index 0e3033f..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg.import deleted file mode 100644 index b856d27..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://0polw88tpkl4" -path="res://.godot/imported/icon_heightmap_raise.svg-16ae516b9460ce83d04d965ed6b9989a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg" -dest_files=["res://.godot/imported/icon_heightmap_raise.svg-16ae516b9460ce83d04d965ed6b9989a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg deleted file mode 100644 index c9d586a..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg.import deleted file mode 100644 index a7bff5d..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b6hlgjb4fa31c" -path="res://.godot/imported/icon_heightmap_smooth.svg-1216ccdd3a408b8769b0a0964b7bd3f9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg" -dest_files=["res://.godot/imported/icon_heightmap_smooth.svg-1216ccdd3a408b8769b0a0964b7bd3f9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg b/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg deleted file mode 100644 index 24f39a4..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg.import b/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg.import deleted file mode 100644 index 48dc9ea..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b4ya0po3a4nqa" -path="res://.godot/imported/icon_heightmap_unmask.svg-f88c0addb6f444beecc364dd218d67e9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg" -dest_files=["res://.godot/imported/icon_heightmap_unmask.svg-f88c0addb6f444beecc364dd218d67e9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg b/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg deleted file mode 100644 index 0cc022a..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg.import b/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg.import deleted file mode 100644 index 70f4a55..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b6l5dys0awbwd" -path="res://.godot/imported/icon_long_arrow_down.svg-baa34c94eaf2f9f3533b079350dd260b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg" -dest_files=["res://.godot/imported/icon_long_arrow_down.svg-baa34c94eaf2f9f3533b079350dd260b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg b/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg deleted file mode 100644 index d4e8c2b..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg.import b/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg.import deleted file mode 100644 index 4d77e3d..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d3vie0tj3ry6k" -path="res://.godot/imported/icon_long_arrow_right.svg-2e9c5428ca49af0df04372d4de12fdd2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg" -dest_files=["res://.godot/imported/icon_long_arrow_right.svg-2e9c5428ca49af0df04372d4de12fdd2.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg b/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg deleted file mode 100644 index 34e2ab7..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg.import b/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg.import deleted file mode 100644 index 0e73229..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cc47smy24m368" -path="res://.godot/imported/icon_minimap_out_of_range_position.svg-be0d8e592b6594137b0f40434b64f771.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg" -dest_files=["res://.godot/imported/icon_minimap_out_of_range_position.svg-be0d8e592b6594137b0f40434b64f771.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg b/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg deleted file mode 100644 index 468c52d..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg.import b/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg.import deleted file mode 100644 index 5b864e3..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c1el0dmyvaaij" -path="res://.godot/imported/icon_minimap_position.svg-09c3263e8852c7010dcfa0a85245403d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_minimap_position.svg" -dest_files=["res://.godot/imported/icon_minimap_position.svg-09c3263e8852c7010dcfa0a85245403d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/icon_small_circle.svg b/addons/zylann.hterrain/tools/icons/icon_small_circle.svg deleted file mode 100644 index b5a004d..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_small_circle.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/addons/zylann.hterrain/tools/icons/icon_small_circle.svg.import b/addons/zylann.hterrain/tools/icons/icon_small_circle.svg.import deleted file mode 100644 index 92cf893..0000000 --- a/addons/zylann.hterrain/tools/icons/icon_small_circle.svg.import +++ /dev/null @@ -1,37 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bdkcgtv1r5j31" -path="res://.godot/imported/icon_small_circle.svg-758362406034e77f78350899f9b2cf34.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_small_circle.svg" -dest_files=["res://.godot/imported/icon_small_circle.svg-758362406034e77f78350899f9b2cf34.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/addons/zylann.hterrain/tools/icons/white.png b/addons/zylann.hterrain/tools/icons/white.png deleted file mode 100644 index dee54f4..0000000 Binary files a/addons/zylann.hterrain/tools/icons/white.png and /dev/null differ diff --git a/addons/zylann.hterrain/tools/icons/white.png.import b/addons/zylann.hterrain/tools/icons/white.png.import deleted file mode 100644 index a0d73bf..0000000 --- a/addons/zylann.hterrain/tools/icons/white.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dnee27oabcvy2" -path.s3tc="res://.godot/imported/white.png-06b7d7f95e74cd7f8357ec25a73870fb.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/white.png" -dest_files=["res://.godot/imported/white.png-06b7d7f95e74cd7f8357ec25a73870fb.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/zylann.hterrain/tools/importer/importer_dialog.gd b/addons/zylann.hterrain/tools/importer/importer_dialog.gd deleted file mode 100644 index 5f57bb1..0000000 --- a/addons/zylann.hterrain/tools/importer/importer_dialog.gd +++ /dev/null @@ -1,312 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../util/util.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Errors = preload("../../util/errors.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_XYZFormat = preload("../../util/xyz_format.gd") -const HT_Inspector = preload("../inspector/inspector.gd") - -signal permanent_change_performed(message) - -@onready var _inspector : HT_Inspector = $VBoxContainer/Inspector -@onready var _errors_label : Label = $VBoxContainer/ColorRect/ScrollContainer/VBoxContainer/Errors -@onready var _warnings_label : Label = \ - $VBoxContainer/ColorRect/ScrollContainer/VBoxContainer/Warnings - -const RAW_LITTLE_ENDIAN = 0 -const RAW_BIG_ENDIAN = 1 - -var _terrain : HTerrain = null -var _logger = HT_Logger.get_for(self) - - -func _init(): - get_ok_button().hide() - - -func _ready(): - _inspector.set_prototype({ - "heightmap": { - "type": TYPE_STRING, - "usage": "file", - "exts": ["raw", "png", "exr", "xyz"] - }, - "raw_endianess": { - "type": TYPE_INT, - "usage": "enum", - "enum_items": ["Little Endian", "Big Endian"], - "enabled": false - }, - "min_height": { - "type": TYPE_FLOAT, - "range": {"min": -2000.0, "max": 2000.0, "step": 0.01}, - "default_value": 0.0 - }, - "max_height": { - "type": TYPE_FLOAT, - "range": {"min": -2000.0, "max": 2000.0, "step": 0.01}, - "default_value": 400.0 - }, - "splatmap": { - "type": TYPE_STRING, - "usage": "file", - "exts": ["png"] - }, - "colormap": { - "type": TYPE_STRING, - "usage": "file", - "exts": ["png"] - } - }) - - # Testing -# _errors_label.text = "- Hello World!" -# _warnings_label.text = "- Yolo Jesus!" - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - # Checking a node set in _ready, - # because visibility can also change between _enter_tree and _ready... - if visible and _inspector != null: - _clear_feedback() - - -static func _format_feedbacks(feed): - var a := [] - for s in feed: - a.append("- " + s) - return "\n".join(PackedStringArray(a)) - - -func _clear_feedback(): - _errors_label.text = "" - _warnings_label.text = "" - - -class HT_ErrorCheckReport: - var errors := [] - var warnings := [] - - -func _show_feedback(res: HT_ErrorCheckReport): - for e in res.errors: - _logger.error(e) - - for w in res.warnings: - _logger.warn(w) - - _clear_feedback() - - if len(res.errors) > 0: - _errors_label.text = _format_feedbacks(res.errors) - - if len(res.warnings) > 0: - _warnings_label.text = _format_feedbacks(res.warnings) - - -func _on_CheckButton_pressed(): - var res := _validate_form() - _show_feedback(res) - - -func _on_ImportButton_pressed(): - assert(_terrain != null and _terrain.get_data() != null) - - # Verify input to inform the user of potential issues - var res := _validate_form() - _show_feedback(res) - - if len(res.errors) != 0: - _logger.debug("Cannot import due to errors, aborting") - return - - var params := {} - - var heightmap_path = _inspector.get_value("heightmap") - if heightmap_path != "": - var endianess = _inspector.get_value("raw_endianess") - params[HTerrainData.CHANNEL_HEIGHT] = { - "path": heightmap_path, - "min_height": _inspector.get_value("min_height"), - "max_height": _inspector.get_value("max_height"), - "big_endian": endianess == RAW_BIG_ENDIAN - } - - var colormap_path = _inspector.get_value("colormap") - if colormap_path != "": - params[HTerrainData.CHANNEL_COLOR] = { - "path": colormap_path - } - - var splatmap_path = _inspector.get_value("splatmap") - if splatmap_path != "": - params[HTerrainData.CHANNEL_SPLAT] = { - "path": splatmap_path - } - - var data = _terrain.get_data() - data._edit_import_maps(params) - emit_signal("permanent_change_performed", "Import maps") - - _logger.debug("Terrain import finished") - hide() - - -func _on_CancelButton_pressed(): - hide() - - -func _on_Inspector_property_changed(key: String, value): - if key == "heightmap": - var is_raw = value.get_extension().to_lower() == "raw" - _inspector.set_property_enabled("raw_endianess", is_raw) - - -func _validate_form() -> HT_ErrorCheckReport: - var res := HT_ErrorCheckReport.new() - - var heightmap_path : String = _inspector.get_value("heightmap") - var splatmap_path : String = _inspector.get_value("splatmap") - var colormap_path : String = _inspector.get_value("colormap") - - if colormap_path == "" and heightmap_path == "" and splatmap_path == "": - res.errors.append("No maps specified.") - return res - - # If a heightmap is specified, it will override the size of the existing terrain. - # If not specified, maps will have to match the resolution of the existing terrain. - var heightmap_size := _terrain.get_data().get_resolution() - - if heightmap_path != "": - var min_height = _inspector.get_value("min_height") - var max_height = _inspector.get_value("max_height") - - if min_height >= max_height: - res.errors.append("Minimum height must be lower than maximum height") - # Returning early because min and max can be slided, - # so we avoid loading other maps every time to do further checks. - return res - - var image_size_result = _load_image_size(heightmap_path, _logger) - if image_size_result.error_code != OK: - res.errors.append(str("Cannot open heightmap file: ", image_size_result.to_string())) - return res - - var adjusted_size = HTerrainData.get_adjusted_map_size( - image_size_result.width, image_size_result.height) - - if adjusted_size != image_size_result.width: - res.warnings.append( - "The square resolution deduced from heightmap file size is not power of two + 1.\n" + \ - "The heightmap will be cropped.") - - heightmap_size = adjusted_size - - if splatmap_path != "": - _check_map_size(splatmap_path, "splatmap", heightmap_size, res, _logger) - - if colormap_path != "": - _check_map_size(colormap_path, "colormap", heightmap_size, res, _logger) - - return res - - -static func _check_map_size(path: String, map_name: String, heightmap_size: int, - res: HT_ErrorCheckReport, logger): - - var size_result := _load_image_size(path, logger) - if size_result.error_code != OK: - res.errors.append(str("Cannot open splatmap file: ", size_result.to_string())) - return - var adjusted_size := HTerrainData.get_adjusted_map_size(size_result.width, size_result.height) - if adjusted_size != heightmap_size: - res.errors.append(str( - "The ", map_name, - " must have the same resolution as the heightmap (", heightmap_size, ")")) - else: - if adjusted_size != size_result.width: - res.warnings.append(str( - "The square resolution deduced from ", map_name, - " file size is not power of two + 1.\nThe ", - map_name, " will be cropped.")) - - -class HT_ImageSizeResult: - var width := 0 - var height := 0 - var error_code := OK - var error_message := "" - - func to_string() -> String: - if error_message != "": - return error_message - return HT_Errors.get_message(error_code) - - -static func _load_image_size(path: String, logger) -> HT_ImageSizeResult: - var ext := path.get_extension().to_lower() - var result := HT_ImageSizeResult.new() - - if ext == "png" or ext == "exr": - # Godot can load these formats natively - var im := Image.new() - var err := im.load(path) - if err != OK: - logger.error("An error occurred loading image '{0}', code {1}".format([path, err])) - result.error_code = err - return result - - result.width = im.get_width() - result.height = im.get_height() - return result - - elif ext == "raw": - var f := FileAccess.open(path, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - logger.error("Error opening file {0}".format([path])) - result.error_code = err - return result - - # Assume the raw data is square in 16-bit format, - # so its size is function of file length - var flen := f.get_length() - f = null - var size_px = HT_Util.integer_square_root(flen / 2) - if size_px == -1: - result.error_code = ERR_INVALID_DATA - result.error_message = "RAW image is not square" - return result - - logger.debug("Deduced RAW heightmap resolution: {0}*{1}, for a length of {2}" \ - .format([size_px, size_px, flen])) - - result.width = size_px - result.height = size_px - return result - - elif ext == "xyz": - var f := FileAccess.open(path, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - logger.error("Error opening file {0}".format([path])) - result.error_code = err - return result - - var bounds := HT_XYZFormat.load_bounds(f) - - result.width = bounds.image_width - result.height = bounds.image_height - return result - - else: - result.error_code = ERR_FILE_UNRECOGNIZED - return result diff --git a/addons/zylann.hterrain/tools/importer/importer_dialog.tscn b/addons/zylann.hterrain/tools/importer/importer_dialog.tscn deleted file mode 100644 index 0c2d267..0000000 --- a/addons/zylann.hterrain/tools/importer/importer_dialog.tscn +++ /dev/null @@ -1,87 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://on7x7xkovsc8"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/importer/importer_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/inspector/inspector.tscn" id="2"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="3"] - -[node name="WindowDialog" type="AcceptDialog"] -title = "Import maps" -size = Vector2i(500, 433) -min_size = Vector2i(500, 380) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="Label" type="Label" parent="VBoxContainer"] -layout_mode = 2 -text = "Select maps to import. Leave empty if you don't need some." - -[node name="Spacer" type="Control" parent="VBoxContainer"] -custom_minimum_size = Vector2(0, 16) -layout_mode = 2 - -[node name="Inspector" parent="VBoxContainer" instance=ExtResource("2")] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="ColorRect" type="ColorRect" parent="VBoxContainer"] -custom_minimum_size = Vector2(0, 100) -layout_mode = 2 -color = Color(0, 0, 0, 0.417529) - -[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer/ColorRect"] -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 - -[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/ColorRect/ScrollContainer"] -layout_mode = 2 - -[node name="Errors" type="Label" parent="VBoxContainer/ColorRect/ScrollContainer/VBoxContainer"] -self_modulate = Color(1, 0.203125, 0.203125, 1) -layout_mode = 2 - -[node name="Warnings" type="Label" parent="VBoxContainer/ColorRect/ScrollContainer/VBoxContainer"] -self_modulate = Color(1, 0.901428, 0.257813, 1) -layout_mode = 2 - -[node name="Spacer2" type="Control" parent="VBoxContainer"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="ButtonsArea" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -mouse_filter = 0 -alignment = 1 - -[node name="CheckButton" type="Button" parent="VBoxContainer/ButtonsArea"] -layout_mode = 2 -text = "Check" - -[node name="ImportButton" type="Button" parent="VBoxContainer/ButtonsArea"] -layout_mode = 2 -text = "Import" - -[node name="CancelButton" type="Button" parent="VBoxContainer/ButtonsArea"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("3")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 492.0 -offset_bottom = 415.0 - -[connection signal="property_changed" from="VBoxContainer/Inspector" to="." method="_on_Inspector_property_changed"] -[connection signal="pressed" from="VBoxContainer/ButtonsArea/CheckButton" to="." method="_on_CheckButton_pressed"] -[connection signal="pressed" from="VBoxContainer/ButtonsArea/ImportButton" to="." method="_on_ImportButton_pressed"] -[connection signal="pressed" from="VBoxContainer/ButtonsArea/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/addons/zylann.hterrain/tools/inspector/inspector.gd b/addons/zylann.hterrain/tools/inspector/inspector.gd deleted file mode 100644 index 6039cee..0000000 --- a/addons/zylann.hterrain/tools/inspector/inspector.gd +++ /dev/null @@ -1,479 +0,0 @@ - -# GDScript implementation of an inspector. -# It generates controls for a provided list of properties, -# which is easier to maintain than placing them by hand and connecting things in the editor. - -@tool -extends Control - -const USAGE_FILE = "file" -const USAGE_ENUM = "enum" - -signal property_changed(key, value) - -# Used for most simple types -class HT_InspectorEditor: - var control = null - var getter := Callable() - var setter := Callable() - var key_label : Label - - -# Used when the control cannot hold the actual value -class HT_InspectorResourceEditor extends HT_InspectorEditor: - var value = null - var label = null - - func get_value(): - return value - - func set_value(v): - value = v - label.text = "null" if v == null else v.resource_path - - -class HT_InspectorVectorEditor extends HT_InspectorEditor: - signal value_changed(v) - - var value := Vector2() - var xed = null - var yed = null - - func get_value(): - return value - - func set_value(v): - xed.value = v.x - yed.value = v.y - value = v - - func _component_changed(v, i): - value[i] = v - value_changed.emit(value) - - -# TODO Rename _schema -var _prototype = null -var _edit_signal := true -# name => editor -var _editors := {} - -# Had to separate the container because otherwise I can't open dialogs properly... -@onready var _grid_container = get_node("GridContainer") -@onready var _file_dialog = get_node("OpenFileDialog") - - -func _ready(): - _file_dialog.visibility_changed.connect( - call_deferred.bind("_on_file_dialog_visibility_changed")) -# Test -# set_prototype({ -# "seed": { -# "type": TYPE_INT, -# "randomizable": true -# }, -# "base_height": { -# "type": TYPE_REAL, -# "range": {"min": -1000.0, "max": 1000.0, "step": 0.1} -# }, -# "height_range": { -# "type": TYPE_REAL, -# "range": {"min": -1000.0, "max": 1000.0, "step": 0.1 }, -# "default_value": 500.0 -# }, -# "streamed": { -# "type": TYPE_BOOL -# }, -# "texture": { -# "type": TYPE_OBJECT, -# "object_type": Resource -# } -# }) - - -# TODO Rename clear_schema -func clear_prototype(): - _editors.clear() - var i = _grid_container.get_child_count() - 1 - while i >= 0: - var child = _grid_container.get_child(i) - _grid_container.remove_child(child) - child.call_deferred("free") - i -= 1 - _prototype = null - - -func get_value(key: String): - var editor = _editors[key] - return editor.getter.call() - - -func get_values(): - var values = {} - for key in _editors: - var editor = _editors[key] - values[key] = editor.getter.call() - return values - - -func set_value(key: String, value): - var editor = _editors[key] - editor.setter.call(value) - - -func set_values(values: Dictionary): - for key in values: - if _editors.has(key): - var editor = _editors[key] - var v = values[key] - editor.setter.call(v) - - -# TODO Rename set_schema -func set_prototype(proto: Dictionary): - clear_prototype() - - for key in proto: - var prop = proto[key] - - var label := Label.new() - label.text = str(key).capitalize() - _grid_container.add_child(label) - - var editor := _make_editor(key, prop) - editor.key_label = label - - if prop.has("default_value"): - editor.setter.call(prop.default_value) - - _editors[key] = editor - - if prop.has("enabled"): - set_property_enabled(key, prop.enabled) - - _grid_container.add_child(editor.control) - - _prototype = proto - - -func trigger_all_modified(): - for key in _prototype: - var value = _editors[key].getter.call_func() - property_changed.emit(key, value) - - -func set_property_enabled(prop_name: String, enabled: bool): - var ed = _editors[prop_name] - - if ed.control is BaseButton: - ed.control.disabled = not enabled - - elif ed.control is SpinBox: - ed.control.editable = enabled - - elif ed.control is LineEdit: - ed.control.editable = enabled - - # TODO Support more editors - - var col = ed.key_label.modulate - if enabled: - col.a = 1.0 - else: - col.a = 0.5 - ed.key_label.modulate = col - - -func _make_editor(key: String, prop: Dictionary) -> HT_InspectorEditor: - var ed : HT_InspectorEditor = null - - var editor : Control = null - var getter : Callable - var setter : Callable - var extra = null - - match prop.type: - TYPE_INT, \ - TYPE_FLOAT: - var pre = null - if prop.has("randomizable") and prop.randomizable: - editor = HBoxContainer.new() - pre = Button.new() - pre.pressed.connect(_randomize_property_pressed.bind(key)) - pre.text = "Randomize" - editor.add_child(pre) - - if prop.type == TYPE_INT and prop.has("usage") and prop.usage == USAGE_ENUM: - # Enumerated value - assert(prop.has("enum_items")) - var option_button := OptionButton.new() - - for i in len(prop.enum_items): - var item = prop.enum_items[i] - option_button.add_item(item) - - # TODO We assume index, actually - getter = option_button.get_selected_id - setter = option_button.select - option_button.item_selected.connect(_property_edited.bind(key)) - - editor = option_button - - else: - # Numeric value - var spinbox := SpinBox.new() - # Spinboxes have shit UX when not expanded... - spinbox.custom_minimum_size = Vector2(120, 16) - _setup_range_control(spinbox, prop) - spinbox.value_changed.connect(_property_edited.bind(key)) - - # TODO In case the type is INT, the getter should return an integer! - getter = spinbox.get_value - setter = spinbox.set_value - - var show_slider = prop.has("range") \ - and not (prop.has("slidable") \ - and prop.slidable == false) - - if show_slider: - if editor == null: - editor = HBoxContainer.new() - var slider := HSlider.new() - # Need to give some size because otherwise the slider is hard to click... - slider.custom_minimum_size = Vector2(32, 16) - _setup_range_control(slider, prop) - slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL - spinbox.share(slider) - editor.add_child(slider) - editor.add_child(spinbox) - else: - spinbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL - if editor == null: - editor = spinbox - else: - editor.add_child(spinbox) - - TYPE_STRING: - if prop.has("usage") and prop.usage == USAGE_FILE: - editor = HBoxContainer.new() - - var line_edit := LineEdit.new() - line_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL - editor.add_child(line_edit) - - var exts = [] - if prop.has("exts"): - exts = prop.exts - - var load_button := Button.new() - load_button.text = "..." - load_button.pressed.connect(_on_ask_load_file.bind(key, exts)) - editor.add_child(load_button) - - line_edit.text_submitted.connect(_property_edited.bind(key)) - getter = line_edit.get_text - setter = line_edit.set_text - - else: - editor = LineEdit.new() - editor.text_submitted.connect(_property_edited.bind(key)) - getter = editor.get_text - setter = editor.set_text - - TYPE_COLOR: - editor = ColorPickerButton.new() - editor.color_changed.connect(_property_edited.bind(key)) - getter = editor.get_pick_color - setter = editor.set_pick_color - - TYPE_BOOL: - editor = CheckBox.new() - editor.toggled.connect(_property_edited.bind(key)) - getter = editor.is_pressed - setter = editor.set_pressed - - TYPE_OBJECT: - # TODO How do I even check inheritance if I work on the class themselves, not instances? - if prop.object_type == Resource: - editor = HBoxContainer.new() - - var label := Label.new() - label.text = "null" - label.size_flags_horizontal = Control.SIZE_EXPAND_FILL - label.clip_text = true - label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - editor.add_child(label) - - var load_button := Button.new() - load_button.text = "Load..." - load_button.pressed.connect(_on_ask_load_texture.bind(key)) - editor.add_child(load_button) - - var clear_button := Button.new() - clear_button.text = "Clear" - clear_button.pressed.connect(_on_ask_clear_texture.bind(key)) - editor.add_child(clear_button) - - ed = HT_InspectorResourceEditor.new() - ed.label = label - getter = ed.get_value - setter = ed.set_value - - TYPE_VECTOR2: - editor = HBoxContainer.new() - - ed = HT_InspectorVectorEditor.new() - - var xlabel := Label.new() - xlabel.text = "x" - editor.add_child(xlabel) - var xed := SpinBox.new() - xed.size_flags_horizontal = Control.SIZE_EXPAND_FILL - xed.step = 0.01 - xed.min_value = -10000 - xed.max_value = 10000 - # TODO This will fire twice (for each coordinate), hmmm... - xed.value_changed.connect(ed._component_changed.bind(0)) - editor.add_child(xed) - - var ylabel := Label.new() - ylabel.text = "y" - editor.add_child(ylabel) - var yed = SpinBox.new() - yed.size_flags_horizontal = Control.SIZE_EXPAND_FILL - yed.step = 0.01 - yed.min_value = -10000 - yed.max_value = 10000 - yed.value_changed.connect(ed._component_changed.bind(1)) - editor.add_child(yed) - - ed.xed = xed - ed.yed = yed - ed.value_changed.connect(_property_edited.bind(key)) - getter = ed.get_value - setter = ed.set_value - - _: - editor = Label.new() - editor.text = "" - getter = _dummy_getter - setter = _dummy_setter - - if not(editor is CheckButton): - editor.size_flags_horizontal = Control.SIZE_EXPAND_FILL - - if ed == null: - # Default - ed = HT_InspectorEditor.new() - ed.control = editor - ed.getter = getter - ed.setter = setter - - return ed - - -static func _setup_range_control(range_control: Range, prop): - if prop.type == TYPE_INT: - range_control.step = 1 - range_control.rounded = true - else: - range_control.step = 0.1 - if prop.has("range"): - range_control.min_value = prop.range.min - range_control.max_value = prop.range.max - if prop.range.has("step"): - range_control.step = prop.range.step - else: - # Where is INT_MAX?? - range_control.min_value = -0x7fffffff - range_control.max_value = 0x7fffffff - - -func _property_edited(value, key): - if _edit_signal: - property_changed.emit(key, value) - - -func _randomize_property_pressed(key): - var prop = _prototype[key] - var v = 0 - - # TODO Support range step - match prop.type: - TYPE_INT: - if prop.has("range"): - v = randi() % (prop.range.max - prop.range.min) + prop.range.min - else: - v = randi() - 0x7fffffff - TYPE_FLOAT: - if prop.has("range"): - v = randf_range(prop.range.min, prop.range.max) - else: - v = randf() - - _editors[key].setter.call(v) - - -func _dummy_getter(): - pass - - -func _dummy_setter(v): - # TODO Could use extra data to store the value anyways? - pass - - -func _on_ask_load_texture(key): - _open_file_dialog(["*.png ; PNG files"], _on_texture_selected.bind(key), - FileDialog.ACCESS_RESOURCES) - - -func _open_file_dialog(filters: Array, callback: Callable, access: int): - _file_dialog.access = access - _file_dialog.clear_filters() - for filter in filters: - _file_dialog.add_filter(filter) - - # Can't just use one-shot signals because the dialog could be closed without choosing a file... -# if not _file_dialog.file_selected.is_connected(callback): -# _file_dialog.file_selected.connect(callback, Object.CONNECT_ONE_SHOT) - _file_dialog.file_selected.connect(callback) - - _file_dialog.popup_centered_ratio(0.7) - - -func _on_file_dialog_visibility_changed(): - if _file_dialog.visible == false: - # Disconnect listeners automatically, - # so we can re-use the same dialog with different listeners - var cons = _file_dialog.get_signal_connection_list("file_selected") - for con in cons: - _file_dialog.file_selected.disconnect(con.callable) - - -func _on_texture_selected(path: String, key): - var tex = load(path) - if tex == null: - return - var ed = _editors[key] - ed.setter.call(tex) - _property_edited(tex, key) - - -func _on_ask_clear_texture(key): - var ed = _editors[key] - ed.setter.call(null) - _property_edited(null, key) - - -func _on_ask_load_file(key, exts): - var filters := [] - for ext in exts: - filters.append(str("*.", ext, " ; ", ext.to_upper(), " files")) - _open_file_dialog(filters, _on_file_selected.bind(key), FileDialog.ACCESS_FILESYSTEM) - - -func _on_file_selected(path, key): - var ed = _editors[key] - ed.setter.call(path) - _property_edited(path, key) diff --git a/addons/zylann.hterrain/tools/inspector/inspector.tscn b/addons/zylann.hterrain/tools/inspector/inspector.tscn deleted file mode 100644 index 4bd1395..0000000 --- a/addons/zylann.hterrain/tools/inspector/inspector.tscn +++ /dev/null @@ -1,15 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dfjip6c4olemn"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/inspector/inspector.gd" id="1"] - -[node name="Inspector" type="VBoxContainer"] -script = ExtResource("1") - -[node name="GridContainer" type="GridContainer" parent="."] -layout_mode = 2 -columns = 2 - -[node name="OpenFileDialog" type="FileDialog" parent="."] -title = "Open a File" -ok_button_text = "Open" -file_mode = 0 diff --git a/addons/zylann.hterrain/tools/load_texture_dialog.gd b/addons/zylann.hterrain/tools/load_texture_dialog.gd deleted file mode 100644 index 6d1e874..0000000 --- a/addons/zylann.hterrain/tools/load_texture_dialog.gd +++ /dev/null @@ -1,22 +0,0 @@ -@tool -extends EditorFileDialog - - -func _init(): - #access = EditorFileDialog.ACCESS_RESOURCES - file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - # TODO I actually want a dialog to load a texture, not specifically a PNG... - add_filter("*.png ; PNG files") - add_filter("*.jpg ; JPG files") - unresizable = false - access = EditorFileDialog.ACCESS_RESOURCES - close_requested.connect(call_deferred.bind("_on_close")) - - -func _on_close(): - # Disconnect listeners automatically, - # so we can re-use the same dialog with different listeners - var cons = get_signal_connection_list("file_selected") - for con in cons: - file_selected.disconnect(con.callable) - diff --git a/addons/zylann.hterrain/tools/minimap/minimap.gd b/addons/zylann.hterrain/tools/minimap/minimap.gd deleted file mode 100644 index f71295a..0000000 --- a/addons/zylann.hterrain/tools/minimap/minimap.gd +++ /dev/null @@ -1,140 +0,0 @@ -@tool -extends Control - -const HT_Util = preload("../../util/util.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_MinimapOverlay = preload("./minimap_overlay.gd") - -const HT_MinimapShader = preload("./minimap_normal.gdshader") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_WhiteTexture = preload("../icons/white.png") -const WHITE_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/white.png" - -const MODE_QUADTREE = 0 -const MODE_NORMAL = 1 - -@onready var _popup_menu : PopupMenu = $PopupMenu -@onready var _color_rect : ColorRect = $ColorRect -@onready var _overlay : HT_MinimapOverlay = $Overlay - -var _terrain : HTerrain = null -var _mode := MODE_NORMAL -var _camera_transform := Transform3D() - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - _set_mode(_mode) - - _popup_menu.add_item("Quadtree mode", MODE_QUADTREE) - _popup_menu.add_item("Normal mode", MODE_NORMAL) - - -func set_terrain(node: HTerrain): - if _terrain != node: - _terrain = node - set_process(_terrain != null) - - -func set_camera_transform(ct: Transform3D): - if _camera_transform == ct: - return - if _terrain == null: - return - var data = _terrain.get_data() - if data == null: - return - var to_local := _terrain.get_internal_transform().affine_inverse() - var pos := _get_xz(to_local * _camera_transform.origin) - var size := Vector2(data.get_resolution(), data.get_resolution()) - pos /= size - var dir := _get_xz(to_local.basis * (-_camera_transform.basis.z)).normalized() - _overlay.set_cursor_position_normalized(pos, dir) - _camera_transform = ct - - -static func _get_xz(v: Vector3) -> Vector2: - return Vector2(v.x, v.z) - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - match event.button_index: - MOUSE_BUTTON_RIGHT: - _popup_menu.position = get_screen_position() + event.position - _popup_menu.popup() - MOUSE_BUTTON_LEFT: - # Teleport there? - pass - - -func _process(delta): - if _terrain != null: - if _mode == MODE_QUADTREE: - queue_redraw() - else: - _update_normal_material() - - -func _set_mode(mode: int): - if mode == MODE_QUADTREE: - _color_rect.hide() - else: - var mat := ShaderMaterial.new() - mat.shader = HT_MinimapShader - _color_rect.material = mat - _color_rect.show() - _update_normal_material() - _mode = mode - queue_redraw() - - -func _update_normal_material(): - if _terrain == null: - return - var data : HTerrainData = _terrain.get_data() - if data == null: - return - - var normalmap = data.get_texture(HTerrainData.CHANNEL_NORMAL) - _set_if_changed(_color_rect.material, "u_normalmap", normalmap) - - var globalmap : Texture - if data.has_texture(HTerrainData.CHANNEL_GLOBAL_ALBEDO, 0): - globalmap = data.get_texture(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - if globalmap == null: - globalmap = load(WHITE_TEXTURE_PATH) - _set_if_changed(_color_rect.material, "u_globalmap", globalmap) - - -# Need to check if it has changed, otherwise Godot's update spinner -# indicates that the editor keeps redrawing every frame, -# which is not intended and consumes more power. -static func _set_if_changed(sm: ShaderMaterial, param: String, v): - if sm.get_shader_parameter(param) != v: - sm.set_shader_parameter(param, v) - - -func _draw(): - if _terrain == null: - return - - if _mode == MODE_QUADTREE: - var lod_count := _terrain.get_lod_count() - - if lod_count > 0: - # Fit drawing to rect - - var qsize = 1 << (lod_count - 1) - var vsize := size - draw_set_transform(Vector2(0, 0), 0, Vector2(vsize.x / qsize, vsize.y / qsize)) - - _terrain._edit_debug_draw(self) - - -func _on_PopupMenu_id_pressed(id: int): - _set_mode(id) diff --git a/addons/zylann.hterrain/tools/minimap/minimap.tscn b/addons/zylann.hterrain/tools/minimap/minimap.tscn deleted file mode 100644 index b2a7ef5..0000000 --- a/addons/zylann.hterrain/tools/minimap/minimap.tscn +++ /dev/null @@ -1,56 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://cba6k3hrwhrke"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/minimap/minimap.gd" id="1"] -[ext_resource type="Shader" path="res://addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader" id="2"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/minimap/minimap_overlay.gd" id="3"] -[ext_resource type="Texture2D" uid="uid://c1el0dmyvaaij" path="res://addons/zylann.hterrain/tools/icons/icon_minimap_position.svg" id="4"] -[ext_resource type="Texture2D" uid="uid://cc47smy24m368" path="res://addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg" id="5"] - -[sub_resource type="ShaderMaterial" id="1"] -shader = ExtResource("2") -shader_parameter/u_light_direction = Vector3(0.5, -0.7, 0.2) - -[node name="Minimap" type="Control"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 3 -anchors_preset = 0 -offset_right = 100.0 -offset_bottom = 100.0 -script = ExtResource("1") - -[node name="PopupMenu" type="PopupMenu" parent="."] - -[node name="ColorRect" type="ColorRect" parent="."] -material = SubResource("1") -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 2 - -[node name="X" type="ColorRect" parent="."] -layout_mode = 0 -mouse_filter = 2 -color = Color(0.929412, 0.290196, 0.290196, 0.627451) - -[node name="Z" type="ColorRect" parent="."] -layout_mode = 0 -mouse_filter = 2 -color = Color(0.0784314, 0.501961, 1, 0.627451) - -[node name="Y" type="ColorRect" parent="."] -layout_mode = 0 -mouse_filter = 2 -color = Color(0.207843, 0.835294, 0.152941, 0.627451) - -[node name="Overlay" type="Control" parent="."] -anchors_preset = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 2 -script = ExtResource("3") -cursor_texture = ExtResource("4") -out_of_range_texture = ExtResource("5") - -[node name="Cursor" type="Sprite2D" parent="Overlay"] - -[connection signal="id_pressed" from="PopupMenu" to="." method="_on_PopupMenu_id_pressed"] diff --git a/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader b/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader deleted file mode 100644 index 0ea3120..0000000 --- a/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader +++ /dev/null @@ -1,24 +0,0 @@ -shader_type canvas_item; - -uniform sampler2D u_normalmap; -uniform sampler2D u_globalmap; -uniform vec3 u_light_direction = vec3(0.5, -0.7, 0.2); - -vec3 unpack_normal(vec4 rgba) { - return rgba.xzy * 2.0 - vec3(1.0); -} - -void fragment() { - vec3 albedo = texture(u_globalmap, UV).rgb; - // Undo sRGB - // TODO I don't know what is correct tbh, this didn't work well - //albedo *= pow(albedo, vec3(0.4545)); - //albedo *= pow(albedo, vec3(1.0 / 0.4545)); - albedo = sqrt(albedo); - - vec3 normal = unpack_normal(texture(u_normalmap, UV)); - float g = max(-dot(u_light_direction, normal), 0.0); - - COLOR = vec4(albedo * g, 1.0); -} - diff --git a/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd b/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd deleted file mode 100644 index 93c6695..0000000 --- a/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd +++ /dev/null @@ -1,24 +0,0 @@ -@tool -extends Control - - -@export var cursor_texture : Texture -@export var out_of_range_texture : Texture - -@onready var _sprite : Sprite2D = $Cursor - -var _pos := Vector2() -var _rot := 0.0 - - -func set_cursor_position_normalized(pos_norm: Vector2, dir: Vector2): - if Rect2(0, 0, 1, 1).has_point(pos_norm): - _sprite.texture = cursor_texture - else: - pos_norm.x = clampf(pos_norm.x, 0.0, 1.0) - pos_norm.y = clampf(pos_norm.y, 0.0, 1.0) - _sprite.texture = out_of_range_texture - - _sprite.position = pos_norm * size - _sprite.rotation = dir.angle() - diff --git a/addons/zylann.hterrain/tools/minimap/ratio_container.gd b/addons/zylann.hterrain/tools/minimap/ratio_container.gd deleted file mode 100644 index 1bd6aca..0000000 --- a/addons/zylann.hterrain/tools/minimap/ratio_container.gd +++ /dev/null @@ -1,32 +0,0 @@ -# Simple container keeping its children under the same aspect ratio - -@tool -extends Container - - -@export var ratio := 1.0 - - -func _notification(what: int): - if what == NOTIFICATION_SORT_CHILDREN: - _sort_children2() - - -# TODO Function with ugly name to workaround a Godot 3.1 issue -# See https://github.com/godotengine/godot/pull/38396 -func _sort_children2(): - for i in get_child_count(): - var child = get_child(i) - if not (child is Control): - continue - var w := size.x - var h := size.x / ratio - - if h > size.y: - h = size.y - w = h * ratio - - var rect := Rect2(0, 0, w, h) - - fit_child_in_rect(child, rect) - diff --git a/addons/zylann.hterrain/tools/normalmap_baker.gd b/addons/zylann.hterrain/tools/normalmap_baker.gd deleted file mode 100644 index e5af37d..0000000 --- a/addons/zylann.hterrain/tools/normalmap_baker.gd +++ /dev/null @@ -1,148 +0,0 @@ - -# Bakes normals asynchronously in the editor as the heightmap gets modified. -# It uses the heightmap texture to change the normalmap image, which is then uploaded like an edit. -# This is probably not a nice method GPU-wise, but it's way faster than GDScript. - -@tool -extends Node - -const HTerrainData = preload("../hterrain_data.gd") - -const VIEWPORT_SIZE = 64 - -const STATE_PENDING = 0 -const STATE_PROCESSING = 1 - -var _viewport : SubViewport = null -var _ci : Sprite2D = null -var _pending_tiles_grid := {} -var _pending_tiles_queue := [] -var _processing_tile = null -var _terrain_data : HTerrainData = null - - -func _init(): - assert(VIEWPORT_SIZE <= HTerrainData.MIN_RESOLUTION) - _viewport = SubViewport.new() - _viewport.size = Vector2(VIEWPORT_SIZE + 2, VIEWPORT_SIZE + 2) - _viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ALWAYS - # We only render 2D, but we don't want the parent world to interfere - _viewport.world_3d = World3D.new() - _viewport.own_world_3d = true - add_child(_viewport) - - var mat = ShaderMaterial.new() - mat.shader = load("res://addons/zylann.hterrain/tools/bump2normal_tex.gdshader") - - _ci = Sprite2D.new() - _ci.centered = false - _ci.material = mat - _viewport.add_child(_ci) - - set_process(false) - - -func set_terrain_data(data: HTerrainData): - if data == _terrain_data: - return - - _pending_tiles_grid.clear() - _pending_tiles_queue.clear() - _processing_tile = null - _ci.texture = null - set_process(false) - - if data == null: - _terrain_data.map_changed.disconnect(_on_terrain_data_map_changed) - _terrain_data.resolution_changed.disconnect(_on_terrain_data_resolution_changed) - - _terrain_data = data - - if _terrain_data != null: - _terrain_data.map_changed.connect(_on_terrain_data_map_changed) - _terrain_data.resolution_changed.connect(_on_terrain_data_resolution_changed) - _ci.texture = data.get_texture(HTerrainData.CHANNEL_HEIGHT) - - -func _on_terrain_data_map_changed(maptype: int, index: int): - if maptype == HTerrainData.CHANNEL_HEIGHT: - _ci.texture = _terrain_data.get_texture(HTerrainData.CHANNEL_HEIGHT) - - -func _on_terrain_data_resolution_changed(): - # TODO Workaround issue https://github.com/godotengine/godot/issues/24463 - _ci.queue_redraw() - - -# TODO Use Vector2i -func request_tiles_in_region(min_pos: Vector2, size: Vector2): - assert(is_inside_tree()) - assert(_terrain_data != null) - var res = _terrain_data.get_resolution() - - min_pos -= Vector2(1, 1) - var max_pos = min_pos + size + Vector2(1, 1) - var tmin = (min_pos / VIEWPORT_SIZE).floor() - var tmax = (max_pos / VIEWPORT_SIZE).ceil() - var ntx = res / VIEWPORT_SIZE - var nty = res / VIEWPORT_SIZE - tmin.x = clamp(tmin.x, 0, ntx) - tmin.y = clamp(tmin.y, 0, nty) - tmax.x = clamp(tmax.x, 0, ntx) - tmax.y = clamp(tmax.y, 0, nty) - - for y in range(tmin.y, tmax.y): - for x in range(tmin.x, tmax.x): - request_tile(Vector2(x, y)) - - -# TODO Use Vector2i -func request_tile(tpos: Vector2): - assert(tpos == tpos.round()) - if _pending_tiles_grid.has(tpos): - var state = _pending_tiles_grid[tpos] - if state == STATE_PENDING: - return - _pending_tiles_grid[tpos] = STATE_PENDING - _pending_tiles_queue.push_front(tpos) - set_process(true) - - -func _process(delta): - if not is_processing(): - return - - if _processing_tile != null and _terrain_data != null: - var src = _viewport.get_texture().get_image() - var dst = _terrain_data.get_image(HTerrainData.CHANNEL_NORMAL) - - src.convert(dst.get_format()) - #src.save_png(str("test_", _processing_tile.x, "_", _processing_tile.y, ".png")) - var pos = _processing_tile * VIEWPORT_SIZE - var w = src.get_width() - 1 - var h = src.get_height() - 1 - dst.blit_rect(src, Rect2i(1, 1, w, h), pos) - _terrain_data.notify_region_change(Rect2(pos.x, pos.y, w, h), HTerrainData.CHANNEL_NORMAL) - - if _pending_tiles_grid[_processing_tile] == STATE_PROCESSING: - _pending_tiles_grid.erase(_processing_tile) - _processing_tile = null - - if _has_pending_tiles(): - var tpos = _pending_tiles_queue[-1] - _pending_tiles_queue.pop_back() - # The sprite will be much larger than the viewport due to the size of the heightmap. - # We move it around so the part inside the viewport will correspond to the tile. - _ci.position = -VIEWPORT_SIZE * tpos + Vector2(1, 1) - _viewport.render_target_update_mode = SubViewport.UPDATE_ONCE - _processing_tile = tpos - _pending_tiles_grid[tpos] = STATE_PROCESSING - else: - set_process(false) - - -func _has_pending_tiles(): - return len(_pending_tiles_queue) > 0 - - diff --git a/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd b/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd deleted file mode 100644 index 4032212..0000000 --- a/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd +++ /dev/null @@ -1,86 +0,0 @@ -@tool - -const HT_Logger = preload("../../util/logger.gd") -const HT_Errors = preload("../../util/errors.gd") -const HT_Result = preload("../util/result.gd") - -const _transform_params = [ - "normalmap_flip_y" -] - - -# sources: { -# "a": "path_to_image_where_red_channel_will_be_stored_in_alpha.png", -# "rgb": "path_to_image_where_rgb_channels_will_be_stored.png" -# "rgba": "path_to_image.png", -# "rgb": "#hexcolor" -# } -static func generate_image(sources: Dictionary, resolution: int, logger) -> HT_Result: - var image := Image.create(resolution, resolution, true, Image.FORMAT_RGBA8) - - var flip_normalmap_y := false - - # TODO Accelerate with GDNative - for key in sources: - if key in _transform_params: - continue - - var src_path : String = sources[key] - - logger.debug(str("Processing source \"", src_path, "\"")) - - var src_image : Image - if src_path.begins_with("#"): - # Plain color - var col = Color(src_path) - src_image = Image.create(resolution, resolution, false, Image.FORMAT_RGBA8) - src_image.fill(col) - - else: - # File - src_image = Image.new() - var err := src_image.load(src_path) - if err != OK: - return HT_Result.new(false, "Could not open file \"{0}\": {1}" \ - .format([src_path, HT_Errors.get_message(err)])) \ - .with_value(err) - src_image.decompress() - - src_image.resize(image.get_width(), image.get_height()) - - # TODO Support more channel configurations - if key == "rgb": - for y in image.get_height(): - for x in image.get_width(): - var dst_col := image.get_pixel(x, y) - var a := dst_col.a - dst_col = src_image.get_pixel(x, y) - dst_col.a = a - image.set_pixel(x, y, dst_col) - - elif key == "a": - for y in image.get_height(): - for x in image.get_width(): - var dst_col := image.get_pixel(x, y) - dst_col.a = src_image.get_pixel(x, y).r - image.set_pixel(x, y, dst_col) - - elif key == "rgba": - # Meh - image.blit_rect(src_image, - Rect2i(0, 0, image.get_width(), image.get_height()), Vector2i()) - - if sources.has("normalmap_flip_y") and sources.normalmap_flip_y: - _flip_normalmap_y(image) - - return HT_Result.new(true).with_value(image) - - -static func _flip_normalmap_y(image: Image): - for y in image.get_height(): - for x in image.get_width(): - var col := image.get_pixel(x, y) - col.g = 1.0 - col.g - image.set_pixel(x, y, col) - - diff --git a/addons/zylann.hterrain/tools/panel.gd b/addons/zylann.hterrain/tools/panel.gd deleted file mode 100644 index 307e008..0000000 --- a/addons/zylann.hterrain/tools/panel.gd +++ /dev/null @@ -1,75 +0,0 @@ -@tool -extends Control - -const HT_DetailEditor = preload("./detail_editor/detail_editor.gd") - - -# Emitted when a texture item is selected -signal texture_selected(index) -signal edit_texture_pressed(index) -signal import_textures_pressed - -# Emitted when a detail item is selected (grass painting) -signal detail_selected(index) -signal detail_list_changed - - -@onready var _minimap = $HSplitContainer/HSplitContainer/MinimapContainer/Minimap -@onready var _brush_editor = $HSplitContainer/BrushEditor -@onready var _texture_editor = $HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor -@onready var _detail_editor : HT_DetailEditor = \ - $HSplitContainer/HSplitContainer/HSplitContainer/DetailEditor - - -func setup_dialogs(base_control: Control): - _brush_editor.setup_dialogs(base_control) - - -func set_terrain(terrain): - _minimap.set_terrain(terrain) - _texture_editor.set_terrain(terrain) - _detail_editor.set_terrain(terrain) - - -func set_undo_redo(undo_manager: EditorUndoRedoManager): - _detail_editor.set_undo_redo(undo_manager) - - -func set_image_cache(image_cache): - _detail_editor.set_image_cache(image_cache) - - -func set_camera_transform(cam_transform: Transform3D): - _minimap.set_camera_transform(cam_transform) - - -func set_terrain_painter(terrain_painter): - _brush_editor.set_terrain_painter(terrain_painter) - - -func _on_TextureEditor_texture_selected(index): - texture_selected.emit(index) - - -func _on_DetailEditor_detail_selected(index): - detail_selected.emit(index) - - -func set_brush_editor_display_mode(mode): - _brush_editor.set_display_mode(mode) - - -func set_detail_layer_index(index): - _detail_editor.set_layer_index(index) - - -func _on_DetailEditor_detail_list_changed(): - detail_list_changed.emit() - - -func _on_TextureEditor_import_pressed(): - import_textures_pressed.emit() - - -func _on_TextureEditor_edit_pressed(index: int): - edit_texture_pressed.emit(index) diff --git a/addons/zylann.hterrain/tools/panel.tscn b/addons/zylann.hterrain/tools/panel.tscn deleted file mode 100644 index 33e856f..0000000 --- a/addons/zylann.hterrain/tools/panel.tscn +++ /dev/null @@ -1,58 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://dtdgawtpwfaft"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/panel.gd" id="1"] -[ext_resource type="PackedScene" uid="uid://bd42ig216p216" path="res://addons/zylann.hterrain/tools/brush/brush_editor.tscn" id="2"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn" id="3"] -[ext_resource type="PackedScene" uid="uid://do3c3jse5p7hx" path="res://addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn" id="4"] -[ext_resource type="PackedScene" uid="uid://cba6k3hrwhrke" path="res://addons/zylann.hterrain/tools/minimap/minimap.tscn" id="5"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/minimap/ratio_container.gd" id="6"] - -[node name="Panel" type="Control"] -custom_minimum_size = Vector2(400, 120) -layout_mode = 3 -anchors_preset = 0 -offset_right = 1012.0 -offset_bottom = 120.0 -script = ExtResource("1") - -[node name="HSplitContainer" type="HSplitContainer" parent="."] -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 4.0 -offset_top = 4.0 -offset_right = -6.0 -offset_bottom = -4.0 -split_offset = 60 - -[node name="BrushEditor" parent="HSplitContainer" instance=ExtResource("2")] -layout_mode = 2 - -[node name="HSplitContainer" type="HSplitContainer" parent="HSplitContainer"] -layout_mode = 2 - -[node name="HSplitContainer" type="HSplitContainer" parent="HSplitContainer/HSplitContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -split_offset = 300 - -[node name="TextureEditor" parent="HSplitContainer/HSplitContainer/HSplitContainer" instance=ExtResource("3")] -layout_mode = 2 -size_flags_horizontal = 1 - -[node name="DetailEditor" parent="HSplitContainer/HSplitContainer/HSplitContainer" instance=ExtResource("4")] -layout_mode = 2 - -[node name="MinimapContainer" type="Container" parent="HSplitContainer/HSplitContainer"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -script = ExtResource("6") - -[node name="Minimap" parent="HSplitContainer/HSplitContainer/MinimapContainer" instance=ExtResource("5")] -layout_mode = 2 - -[connection signal="edit_pressed" from="HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor" to="." method="_on_TextureEditor_edit_pressed"] -[connection signal="import_pressed" from="HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor" to="." method="_on_TextureEditor_import_pressed"] -[connection signal="texture_selected" from="HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor" to="." method="_on_TextureEditor_texture_selected"] -[connection signal="detail_list_changed" from="HSplitContainer/HSplitContainer/HSplitContainer/DetailEditor" to="." method="_on_DetailEditor_detail_list_changed"] -[connection signal="detail_selected" from="HSplitContainer/HSplitContainer/HSplitContainer/DetailEditor" to="." method="_on_DetailEditor_detail_selected"] diff --git a/addons/zylann.hterrain/tools/plugin.gd b/addons/zylann.hterrain/tools/plugin.gd deleted file mode 100644 index 741ce8d..0000000 --- a/addons/zylann.hterrain/tools/plugin.gd +++ /dev/null @@ -1,884 +0,0 @@ -@tool # https://www.youtube.com/watch?v=Y7JG63IuaWs - -extends EditorPlugin - -const HTerrain = preload("../hterrain.gd") -const HTerrainDetailLayer = preload("../hterrain_detail_layer.gd") -const HTerrainData = preload("../hterrain_data.gd") -const HTerrainMesher = preload("../hterrain_mesher.gd") -const HTerrainTextureSet = preload("../hterrain_texture_set.gd") -const HT_PreviewGenerator = preload("./preview_generator.gd") -const HT_TerrainPainter = preload("./brush/terrain_painter.gd") -const HT_BrushDecal = preload("./brush/decal.gd") -const HT_Util = preload("../util/util.gd") -const HT_EditorUtil = preload("./util/editor_util.gd") -const HT_LoadTextureDialog = preload("./load_texture_dialog.gd") -const HT_GlobalMapBaker = preload("./globalmap_baker.gd") -const HT_ImageFileCache = preload("../util/image_file_cache.gd") -const HT_Logger = preload("../util/logger.gd") -const HT_EditPanel = preload("./panel.gd") -const HT_GeneratorDialog = preload("./generator/generator_dialog.gd") -const HT_TextureSetEditor = preload("./texture_editor/set_editor/texture_set_editor.gd") -const HT_TextureSetImportEditor = \ - preload("./texture_editor/set_editor/texture_set_import_editor.gd") -const HT_ProgressWindow = preload("./progress_window.gd") - -const HT_EditPanelScene = preload("./panel.tscn") -const HT_ProgressWindowScene = preload("./progress_window.tscn") -const HT_GeneratorDialogScene = preload("./generator/generator_dialog.tscn") -const HT_ImportDialogScene = preload("./importer/importer_dialog.tscn") -const HT_GenerateMeshDialogScene = preload("./generate_mesh_dialog.tscn") -const HT_ResizeDialogScene = preload("./resize_dialog/resize_dialog.tscn") -const HT_ExportImageDialogScene = preload("./exporter/export_image_dialog.tscn") -const HT_TextureSetEditorScene = preload("./texture_editor/set_editor/texture_set_editor.tscn") -const HT_TextureSetImportEditorScene = \ - preload("./texture_editor/set_editor/texture_set_import_editor.tscn") -const HT_AboutDialogScene = preload("./about/about_dialog.tscn") - -const DOCUMENTATION_URL = "https://hterrain-plugin.readthedocs.io/en/latest" - -const MENU_IMPORT_MAPS = 0 -const MENU_GENERATE = 1 -const MENU_BAKE_GLOBALMAP = 2 -const MENU_RESIZE = 3 -const MENU_UPDATE_EDITOR_COLLIDER = 4 -const MENU_GENERATE_MESH = 5 -const MENU_EXPORT_HEIGHTMAP = 6 -const MENU_LOOKDEV = 7 -const MENU_DOCUMENTATION = 8 -const MENU_ABOUT = 9 - - -# TODO Rename _terrain -var _node : HTerrain = null - -# GUI -var _panel : HT_EditPanel = null -var _toolbar : Container = null -var _toolbar_brush_buttons := {} -var _generator_dialog : HT_GeneratorDialog = null -# TODO Rename _import_terrain_dialog -var _import_dialog = null -var _export_image_dialog = null - -# This window is only used for operations not triggered by an existing dialog. -# In Godot it has been solved by automatically reparenting the dialog: -# https://github.com/godotengine/godot/pull/71209 -# But `get_exclusive_child()` is not exposed. So dialogs triggering a progress -# dialog may need their own child instance... -var _progress_window : HT_ProgressWindow = null - -var _generate_mesh_dialog = null -var _preview_generator : HT_PreviewGenerator = null -var _resize_dialog = null -var _about_dialog = null -var _menu_button : MenuButton -var _lookdev_menu : PopupMenu -var _texture_set_editor : HT_TextureSetEditor = null -var _texture_set_import_editor : HT_TextureSetImportEditor = null - -var _globalmap_baker : HT_GlobalMapBaker = null -var _terrain_had_data_previous_frame := false -var _image_cache : HT_ImageFileCache -var _terrain_painter : HT_TerrainPainter = null -var _brush_decal : HT_BrushDecal = null -var _mouse_pressed := false -#var _pending_paint_action = null -var _pending_paint_commit := false - -var _logger := HT_Logger.get_for(self) - - -func get_icon(icon_name: String) -> Texture2D: - return HT_EditorUtil.load_texture( - "res://addons/zylann.hterrain/tools/icons/icon_" + icon_name + ".svg", _logger) - - -func _enter_tree(): - _logger.debug("HTerrain plugin Enter tree") - - var dpi_scale = get_editor_interface().get_editor_scale() - _logger.debug(str("DPI scale: ", dpi_scale)) - - add_custom_type("HTerrain", "Node3D", HTerrain, get_icon("heightmap_node")) - add_custom_type("HTerrainDetailLayer", "Node3D", HTerrainDetailLayer, - get_icon("detail_layer_node")) - add_custom_type("HTerrainData", "Resource", HTerrainData, get_icon("heightmap_data")) - # TODO Proper texture - add_custom_type("HTerrainTextureSet", "Resource", HTerrainTextureSet, null) - - _preview_generator = HT_PreviewGenerator.new() - get_editor_interface().get_resource_previewer().add_preview_generator(_preview_generator) - - _terrain_painter = HT_TerrainPainter.new() - _terrain_painter.set_brush_size(5) - _terrain_painter.get_brush().size_changed.connect(_on_brush_size_changed) - add_child(_terrain_painter) - - _brush_decal = HT_BrushDecal.new() - _brush_decal.set_size(_terrain_painter.get_brush_size()) - - _image_cache = HT_ImageFileCache.new("user://temp_hterrain_image_cache") - - var editor_interface := get_editor_interface() - var base_control := editor_interface.get_base_control() - - _panel = HT_EditPanelScene.instantiate() - HT_Util.apply_dpi_scale(_panel, dpi_scale) - _panel.hide() - add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_BOTTOM, _panel) - # Apparently _ready() still isn't called at this point... - _panel.call_deferred("set_terrain_painter", _terrain_painter) - _panel.call_deferred("setup_dialogs", base_control) - _panel.set_undo_redo(get_undo_redo()) - _panel.set_image_cache(_image_cache) - _panel.detail_selected.connect(_on_detail_selected) - _panel.texture_selected.connect(_on_texture_selected) - _panel.detail_list_changed.connect(_update_brush_buttons_availability) - _panel.edit_texture_pressed.connect(_on_Panel_edit_texture_pressed) - _panel.import_textures_pressed.connect(_on_Panel_import_textures_pressed) - - _toolbar = HBoxContainer.new() - add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, _toolbar) - _toolbar.hide() - - var menu := MenuButton.new() - menu.set_text("Terrain") - menu.get_popup().add_item("Import maps...", MENU_IMPORT_MAPS) - menu.get_popup().add_item("Generate...", MENU_GENERATE) - menu.get_popup().add_item("Resize...", MENU_RESIZE) - menu.get_popup().add_item("Bake global map", MENU_BAKE_GLOBALMAP) - menu.get_popup().add_separator() - menu.get_popup().add_item("Update Editor Collider", MENU_UPDATE_EDITOR_COLLIDER) - menu.get_popup().add_separator() - menu.get_popup().add_item("Generate mesh (heavy)", MENU_GENERATE_MESH) - menu.get_popup().add_separator() - menu.get_popup().add_item("Export heightmap", MENU_EXPORT_HEIGHTMAP) - menu.get_popup().add_separator() - _lookdev_menu = PopupMenu.new() - _lookdev_menu.name = "LookdevMenu" - _lookdev_menu.about_to_popup.connect(_on_lookdev_menu_about_to_show) - _lookdev_menu.id_pressed.connect(_on_lookdev_menu_id_pressed) - menu.get_popup().add_child(_lookdev_menu) - menu.get_popup().add_submenu_item("Lookdev", _lookdev_menu.name, MENU_LOOKDEV) - menu.get_popup().id_pressed.connect(_menu_item_selected) - menu.get_popup().add_separator() - menu.get_popup().add_item("Documentation", MENU_DOCUMENTATION) - menu.get_popup().add_item("About HTerrain...", MENU_ABOUT) - _toolbar.add_child(menu) - _menu_button = menu - - var mode_icons := {} - mode_icons[HT_TerrainPainter.MODE_RAISE] = get_icon("heightmap_raise") - mode_icons[HT_TerrainPainter.MODE_LOWER] = get_icon("heightmap_lower") - mode_icons[HT_TerrainPainter.MODE_SMOOTH] = get_icon("heightmap_smooth") - mode_icons[HT_TerrainPainter.MODE_FLATTEN] = get_icon("heightmap_flatten") - mode_icons[HT_TerrainPainter.MODE_SPLAT] = get_icon("heightmap_paint") - mode_icons[HT_TerrainPainter.MODE_COLOR] = get_icon("heightmap_color") - mode_icons[HT_TerrainPainter.MODE_DETAIL] = get_icon("grass") - mode_icons[HT_TerrainPainter.MODE_MASK] = get_icon("heightmap_mask") - mode_icons[HT_TerrainPainter.MODE_LEVEL] = get_icon("heightmap_level") - mode_icons[HT_TerrainPainter.MODE_ERODE] = get_icon("heightmap_erode") - - var mode_tooltips := {} - mode_tooltips[HT_TerrainPainter.MODE_RAISE] = "Raise height" - mode_tooltips[HT_TerrainPainter.MODE_LOWER] = "Lower height" - mode_tooltips[HT_TerrainPainter.MODE_SMOOTH] = "Smooth height" - mode_tooltips[HT_TerrainPainter.MODE_FLATTEN] = "Flatten (flatten to a specific height)" - mode_tooltips[HT_TerrainPainter.MODE_SPLAT] = "Texture paint" - mode_tooltips[HT_TerrainPainter.MODE_COLOR] = "Color paint" - mode_tooltips[HT_TerrainPainter.MODE_DETAIL] = "Grass paint" - mode_tooltips[HT_TerrainPainter.MODE_MASK] = "Cut holes" - mode_tooltips[HT_TerrainPainter.MODE_LEVEL] = "Level (smoothly flattens to average)" - mode_tooltips[HT_TerrainPainter.MODE_ERODE] = "Erode" - - _toolbar.add_child(VSeparator.new()) - - # I want modes to be in that order in the GUI - var ordered_brush_modes := [ - HT_TerrainPainter.MODE_RAISE, - HT_TerrainPainter.MODE_LOWER, - HT_TerrainPainter.MODE_SMOOTH, - HT_TerrainPainter.MODE_LEVEL, - HT_TerrainPainter.MODE_FLATTEN, - HT_TerrainPainter.MODE_ERODE, - HT_TerrainPainter.MODE_SPLAT, - HT_TerrainPainter.MODE_COLOR, - HT_TerrainPainter.MODE_DETAIL, - HT_TerrainPainter.MODE_MASK - ] - - var mode_group := ButtonGroup.new() - - for mode in ordered_brush_modes: - var button := Button.new() - button.flat = true - button.icon = mode_icons[mode] - button.tooltip_text = mode_tooltips[mode] - button.set_toggle_mode(true) - button.set_button_group(mode_group) - - if mode == _terrain_painter.get_mode(): - button.button_pressed = true - - button.pressed.connect(_on_mode_selected.bind(mode)) - _toolbar.add_child(button) - - _toolbar_brush_buttons[mode] = button - - _generator_dialog = HT_GeneratorDialogScene.instantiate() - _generator_dialog.set_image_cache(_image_cache) - _generator_dialog.set_undo_redo(get_undo_redo()) - base_control.add_child(_generator_dialog) - _generator_dialog.apply_dpi_scale(dpi_scale) - - _import_dialog = HT_ImportDialogScene.instantiate() - _import_dialog.permanent_change_performed.connect(_on_permanent_change_performed) - HT_Util.apply_dpi_scale(_import_dialog, dpi_scale) - base_control.add_child(_import_dialog) - - _progress_window = HT_ProgressWindowScene.instantiate() - base_control.add_child(_progress_window) - - _generate_mesh_dialog = HT_GenerateMeshDialogScene.instantiate() - _generate_mesh_dialog.generate_selected.connect(_on_GenerateMeshDialog_generate_selected) - HT_Util.apply_dpi_scale(_generate_mesh_dialog, dpi_scale) - base_control.add_child(_generate_mesh_dialog) - - _resize_dialog = HT_ResizeDialogScene.instantiate() - _resize_dialog.permanent_change_performed.connect(_on_permanent_change_performed) - HT_Util.apply_dpi_scale(_resize_dialog, dpi_scale) - base_control.add_child(_resize_dialog) - - _globalmap_baker = HT_GlobalMapBaker.new() - _globalmap_baker.progress_notified.connect(_progress_window.handle_progress) - _globalmap_baker.permanent_change_performed.connect(_on_permanent_change_performed) - add_child(_globalmap_baker) - - _export_image_dialog = HT_ExportImageDialogScene.instantiate() - HT_Util.apply_dpi_scale(_export_image_dialog, dpi_scale) - base_control.add_child(_export_image_dialog) - # Need to call deferred because in the specific case where you start the editor - # with the plugin enabled, _ready won't be called at this point - _export_image_dialog.call_deferred("setup_dialogs", base_control) - - _about_dialog = HT_AboutDialogScene.instantiate() - HT_Util.apply_dpi_scale(_about_dialog, dpi_scale) - base_control.add_child(_about_dialog) - - _texture_set_editor = HT_TextureSetEditorScene.instantiate() - _texture_set_editor.set_undo_redo(get_undo_redo()) - HT_Util.apply_dpi_scale(_texture_set_editor, dpi_scale) - base_control.add_child(_texture_set_editor) - _texture_set_editor.call_deferred("setup_dialogs", base_control) - - _texture_set_import_editor = HT_TextureSetImportEditorScene.instantiate() - _texture_set_import_editor.set_undo_redo(get_undo_redo()) - _texture_set_import_editor.set_editor_file_system( - get_editor_interface().get_resource_filesystem()) - HT_Util.apply_dpi_scale(_texture_set_import_editor, dpi_scale) - base_control.add_child(_texture_set_import_editor) - _texture_set_import_editor.call_deferred("setup_dialogs", base_control) - - _texture_set_editor.import_selected.connect(_on_TextureSetEditor_import_selected) - - -func _exit_tree(): - _logger.debug("HTerrain plugin Exit tree") - - # Make sure we release all references to edited stuff - _edit(null) - - _panel.queue_free() - _panel = null - - _toolbar.queue_free() - _toolbar = null - - _generator_dialog.queue_free() - _generator_dialog = null - - _import_dialog.queue_free() - _import_dialog = null - - _progress_window.queue_free() - _progress_window = null - - _generate_mesh_dialog.queue_free() - _generate_mesh_dialog = null - - _resize_dialog.queue_free() - _resize_dialog = null - - _export_image_dialog.queue_free() - _export_image_dialog = null - - _about_dialog.queue_free() - _about_dialog = null - - _texture_set_editor.queue_free() - _texture_set_editor = null - - _texture_set_import_editor.queue_free() - _texture_set_import_editor = null - - get_editor_interface().get_resource_previewer().remove_preview_generator(_preview_generator) - _preview_generator = null - - # TODO Manual clear cuz it can't do it automatically due to a Godot bug - _image_cache.clear() - - # TODO https://github.com/godotengine/godot/issues/6254#issuecomment-246139694 - # This was supposed to be automatic, but was never implemented it seems... - remove_custom_type("HTerrain") - remove_custom_type("HTerrainDetailLayer") - remove_custom_type("HTerrainData") - remove_custom_type("HTerrainTextureSet") - - -func _handles(object): - return _get_terrain_from_object(object) != null - - -func _edit(object): - _logger.debug(str("Edit ", object)) - - var node = _get_terrain_from_object(object) - - if _node != null: - _node.tree_exited.disconnect(_terrain_exited_scene) - - _node = node - - if _node != null: - _node.tree_exited.connect(_terrain_exited_scene) - - _update_brush_buttons_availability() - - _panel.set_terrain(_node) - _generator_dialog.set_terrain(_node) - _import_dialog.set_terrain(_node) - _terrain_painter.set_terrain(_node) - _brush_decal.set_terrain(_node) - _generate_mesh_dialog.set_terrain(_node) - _resize_dialog.set_terrain(_node) - _export_image_dialog.set_terrain(_node) - - if object is HTerrainDetailLayer: - # Auto-select layer for painting - if object.is_layer_index_valid(): - _panel.set_detail_layer_index(object.get_layer_index()) - _on_detail_selected(object.get_layer_index()) - - _update_toolbar_menu_availability() - - -static func _get_terrain_from_object(object): - if object != null and object is Node3D: - if not object.is_inside_tree(): - return null - if object is HTerrain: - return object - if object is HTerrainDetailLayer and object.get_parent() is HTerrain: - return object.get_parent() - return null - - -func _update_brush_buttons_availability(): - if _node == null: - return - if _node.get_data() != null: - var data = _node.get_data() - var has_details = (data.get_map_count(HTerrainData.CHANNEL_DETAIL) > 0) - - if has_details: - var button = _toolbar_brush_buttons[HT_TerrainPainter.MODE_DETAIL] - button.disabled = false - else: - var button = _toolbar_brush_buttons[HT_TerrainPainter.MODE_DETAIL] - if button.button_pressed: - _select_brush_mode(HT_TerrainPainter.MODE_RAISE) - button.disabled = true - - -func _update_toolbar_menu_availability(): - var data_available := false - if _node != null and _node.get_data() != null: - data_available = true - var popup : PopupMenu = _menu_button.get_popup() - for i in popup.get_item_count(): - #var id = popup.get_item_id(i) - # Turn off items if there is no data for them to work on - if data_available: - popup.set_item_disabled(i, false) - popup.set_item_tooltip(i, "") - else: - popup.set_item_disabled(i, true) - popup.set_item_tooltip(i, "Terrain has no data") - - -func _make_visible(visible: bool): - _panel.set_visible(visible) - _toolbar.set_visible(visible) - _brush_decal.update_visibility() - - # TODO Workaround https://github.com/godotengine/godot/issues/6459 - # When the user selects another node, - # I want the plugin to release its references to the terrain. - # This is important because if we don't do that, some modified resources will still be - # loaded in memory, so if the user closes the scene and reopens it later, the changes will - # still be partially present, and this is not expected. - if not visible: - _edit(null) - - -# TODO Can't hint return as `Vector2?` because it's nullable -func _get_pointed_cell_position(mouse_position: Vector2, p_camera: Camera3D):# -> Vector2: - # Need to do an extra conversion in case the editor viewport is in half-resolution mode - var viewport := p_camera.get_viewport() - var viewport_container : Control = viewport.get_parent() - var screen_pos = mouse_position * Vector2(viewport.size) / viewport_container.size - - var origin = p_camera.project_ray_origin(screen_pos) - var dir = p_camera.project_ray_normal(screen_pos) - - var ray_distance := p_camera.far * 1.2 - return _node.cell_raycast(origin, dir, ray_distance) - - -func _forward_3d_gui_input(p_camera: Camera3D, p_event: InputEvent) -> int: - if _node == null || _node.get_data() == null: - return AFTER_GUI_INPUT_PASS - - _node._edit_update_viewer_position(p_camera) - _panel.set_camera_transform(p_camera.global_transform) - - var captured_event = false - - if p_event is InputEventMouseButton: - var mb = p_event - - if mb.button_index == MOUSE_BUTTON_LEFT or mb.button_index == MOUSE_BUTTON_RIGHT: - if mb.pressed == false: - _mouse_pressed = false - - # Need to check modifiers before capturing the event, - # because they are used in navigation schemes - if (not mb.ctrl_pressed) and (not mb.alt_pressed) and mb.button_index == MOUSE_BUTTON_LEFT: - if mb.pressed: - # TODO Allow to paint on click - # TODO `pressure` is not available in button press events - # So I have to assume zero to avoid discontinuities with move events - #_terrain_painter.paint_input(hit_pos_in_cells, 0.0) - _mouse_pressed = true - - captured_event = true - - if not _mouse_pressed: - # Just finished painting - _pending_paint_commit = true - _terrain_painter.get_brush().on_paint_end() - - if _terrain_painter.get_mode() == HT_TerrainPainter.MODE_FLATTEN \ - and _terrain_painter.has_meta("pick_height") \ - and _terrain_painter.get_meta("pick_height"): - _terrain_painter.set_meta("pick_height", false) - # Pick height - var hit_pos_in_cells = _get_pointed_cell_position(mb.position, p_camera) - if hit_pos_in_cells != null: - var h = _node.get_data().get_height_at( - int(hit_pos_in_cells.x), int(hit_pos_in_cells.y)) - _logger.debug("Picking height {0}".format([h])) - _terrain_painter.set_flatten_height(h) - - elif p_event is InputEventMouseMotion: - var mm = p_event - var hit_pos_in_cells = _get_pointed_cell_position(mm.position, p_camera) - if hit_pos_in_cells != null: - _brush_decal.set_position(Vector3(hit_pos_in_cells.x, 0, hit_pos_in_cells.y)) - - if _mouse_pressed: - if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): - _terrain_painter.paint_input(hit_pos_in_cells, mm.pressure) - captured_event = true - - # This is in case the data or textures change as the user edits the terrain, - # to keep the decal working without having to noodle around with nested signals - _brush_decal.update_visibility() - - if captured_event: - return AFTER_GUI_INPUT_STOP - return AFTER_GUI_INPUT_PASS - - -func _process(delta: float): - if _node == null: - return - - var has_data = (_node.get_data() != null) - - if _pending_paint_commit: - if has_data: - if not _terrain_painter.is_operation_pending(): - _pending_paint_commit = false - if _terrain_painter.has_modified_chunks(): - _logger.debug("Paint completed") - var changes : Dictionary = _terrain_painter.commit() - _paint_completed(changes) - else: - _pending_paint_commit = false - - # Poll presence of data resource - if has_data != _terrain_had_data_previous_frame: - _terrain_had_data_previous_frame = has_data - _update_toolbar_menu_availability() - - -func _paint_completed(changes: Dictionary): - var time_before = Time.get_ticks_msec() - - var heightmap_data = _node.get_data() - assert(heightmap_data != null) - - var chunk_positions : Array = changes.chunk_positions - # Should not create an UndoRedo action if nothing changed - assert(len(chunk_positions) > 0) - var changed_maps : Array = changes.maps - - var action_name := "Modify HTerrainData " - for i in len(changed_maps): - var mm = changed_maps[i] - var map_debug_name := HTerrainData.get_map_debug_name(mm.map_type, mm.map_index) - if i > 0: - action_name += " and " - action_name += map_debug_name - - var redo_maps := [] - var undo_maps := [] - var chunk_size := _terrain_painter.get_undo_chunk_size() - - for map in changed_maps: - # Cache images to disk so RAM does not continuously go up (or at least much slower) - for chunks in [map.chunk_initial_datas, map.chunk_final_datas]: - for i in len(chunks): - var im : Image = chunks[i] - chunks[i] = _image_cache.save_image(im) - - redo_maps.append({ - "map_type": map.map_type, - "map_index": map.map_index, - "chunks": map.chunk_final_datas - }) - undo_maps.append({ - "map_type": map.map_type, - "map_index": map.map_index, - "chunks": map.chunk_initial_datas - }) - - var undo_data := { - "chunk_positions": chunk_positions, - "chunk_size": chunk_size, - "maps": undo_maps - } - var redo_data := { - "chunk_positions": chunk_positions, - "chunk_size": chunk_size, - "maps": redo_maps - } - -# { -# chunk_positions: [Vector2, Vector2, ...] -# chunk_size: int -# maps: [ -# { -# map_type: int -# map_index: int -# chunks: [ -# int, int, ... -# ] -# }, -# ... -# ] -# } - - var ur := get_undo_redo() - - ur.create_action(action_name) - ur.add_do_method(heightmap_data, "_edit_apply_undo", redo_data, _image_cache) - ur.add_undo_method(heightmap_data, "_edit_apply_undo", undo_data, _image_cache) - - # Small hack here: - # commit_actions executes the do method, however terrain modifications are heavy ones, - # so we don't really want to re-run an update in every chunk that was modified during painting. - # The data is already in its final state, - # so we just prevent the resource from applying changes here. - heightmap_data._edit_set_disable_apply_undo(true) - ur.commit_action() - heightmap_data._edit_set_disable_apply_undo(false) - - var time_spent = Time.get_ticks_msec() - time_before - _logger.debug(str(action_name, " | ", len(chunk_positions), " chunks | ", time_spent, " ms")) - - -func _terrain_exited_scene(): - _logger.debug("HTerrain exited the scene") - _edit(null) - - -func _menu_item_selected(id: int): - _logger.debug(str("Menu item selected ", id)) - - match id: - MENU_IMPORT_MAPS: - _import_dialog.popup_centered() - - MENU_GENERATE: - _generator_dialog.popup_centered() - - MENU_BAKE_GLOBALMAP: - var data = _node.get_data() - if data != null: - _globalmap_baker.bake(_node) - - MENU_RESIZE: - _resize_dialog.popup_centered() - - MENU_UPDATE_EDITOR_COLLIDER: - # This is for editor tools to be able to use terrain collision. - # It's not automatic because keeping this collider up to date is - # expensive, but not too bad IMO because that feature is not often - # used in editor for now. - # If users complain too much about this, there are ways to improve it: - # - # 1) When the terrain gets deselected, update the terrain collider - # in a thread automatically. This is still expensive but should - # be easy to do. - # - # 2) Bullet actually support modifying the heights dynamically, - # as long as we stay within min and max bounds, - # so PR a change to the Godot heightmap collider to support passing - # a Float Image directly, and make it so the data is in sync - # (no CoW plz!!). It's trickier than 1) but almost free. - # - _node.update_collider() - - MENU_GENERATE_MESH: - if _node != null and _node.get_data() != null: - _generate_mesh_dialog.popup_centered() - - MENU_EXPORT_HEIGHTMAP: - if _node != null and _node.get_data() != null: - _export_image_dialog.popup_centered() - - MENU_LOOKDEV: - # No actions here, it's a submenu - pass - - MENU_DOCUMENTATION: - OS.shell_open(DOCUMENTATION_URL) - - MENU_ABOUT: - _about_dialog.popup_centered() - - -func _on_lookdev_menu_about_to_show(): - _lookdev_menu.clear() - _lookdev_menu.add_check_item("Disabled") - _lookdev_menu.set_item_checked(0, not _node.is_lookdev_enabled()) - _lookdev_menu.add_separator() - var terrain_data : HTerrainData = _node.get_data() - if terrain_data == null: - _lookdev_menu.add_item("No terrain data") - _lookdev_menu.set_item_disabled(0, true) - else: - for map_type in HTerrainData.CHANNEL_COUNT: - var count := terrain_data.get_map_count(map_type) - for map_index in count: - var map_name := HTerrainData.get_map_debug_name(map_type, map_index) - var lookdev_item_index := _lookdev_menu.get_item_count() - _lookdev_menu.add_item(map_name, lookdev_item_index) - _lookdev_menu.set_item_metadata(lookdev_item_index, { - "map_type": map_type, - "map_index": map_index - }) - - -func _on_lookdev_menu_id_pressed(id: int): - var meta = _lookdev_menu.get_item_metadata(id) - if meta == null: - _node.set_lookdev_enabled(false) - else: - _node.set_lookdev_enabled(true) - var data : HTerrainData = _node.get_data() - var map_texture = data.get_texture(meta.map_type, meta.map_index) - _node.set_lookdev_shader_param("u_map", map_texture) - _lookdev_menu.set_item_checked(0, not _node.is_lookdev_enabled()) - - -func _on_mode_selected(mode: int): - _logger.debug(str("On mode selected ", mode)) - _terrain_painter.set_mode(mode) - _panel.set_brush_editor_display_mode(mode) - - -func _on_texture_selected(index: int): - # Switch to texture paint mode when a texture is selected - _select_brush_mode(HT_TerrainPainter.MODE_SPLAT) - _terrain_painter.set_texture_index(index) - - -func _on_detail_selected(index: int): - # Switch to detail paint mode when a detail item is selected - _select_brush_mode(HT_TerrainPainter.MODE_DETAIL) - _terrain_painter.set_detail_index(index) - - -func _select_brush_mode(mode: int): - _toolbar_brush_buttons[mode].button_pressed = true - _on_mode_selected(mode) - - -static func get_size_from_raw_length(flen: int): - var side_len = roundf(sqrt(float(flen/2))) - return int(side_len) - - -func _on_GenerateMeshDialog_generate_selected(lod: int): - var data := _node.get_data() - if data == null: - _logger.error("Terrain has no data, cannot generate mesh") - return - var heightmap := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var scale := _node.map_scale - var mesh := HTerrainMesher.make_heightmap_mesh(heightmap, lod, scale, _logger) - var mi := MeshInstance3D.new() - mi.name = str(_node.name, "_FullMesh") - mi.mesh = mesh - mi.transform = _node.transform - _node.get_parent().add_child(mi) - mi.set_owner(get_editor_interface().get_edited_scene_root()) - - -# TODO Workaround for https://github.com/Zylann/godot_heightmap_plugin/issues/101 -func _on_permanent_change_performed(message: String): - var data := _node.get_data() - if data == null: - _logger.error("Terrain has no data, cannot mark it as changed") - return - var ur := get_undo_redo() - ur.create_action(message) - ur.add_do_method(data, "_dummy_function") - #ur.add_undo_method(data, "_dummy_function") - ur.commit_action() - - -func _on_brush_size_changed(size): - _brush_decal.set_size(size) - - -func _on_Panel_edit_texture_pressed(index: int): - var ts := _node.get_texture_set() - _texture_set_editor.set_texture_set(ts) - _texture_set_editor.select_slot(index) - _texture_set_editor.popup_centered() - - -func _on_TextureSetEditor_import_selected(): - _open_texture_set_import_editor() - - -func _on_Panel_import_textures_pressed(): - _open_texture_set_import_editor() - - -func _open_texture_set_import_editor(): - var ts := _node.get_texture_set() - _texture_set_import_editor.set_texture_set(ts) - _texture_set_import_editor.popup_centered() - - -################ -# DEBUG LAND - -# TEST -#func _physics_process(delta): -# if Input.is_key_pressed(KEY_KP_0): -# _debug_spawn_collider_indicators() - - -func _debug_spawn_collider_indicators(): - var root = get_editor_interface().get_edited_scene_root() - var terrain := HT_Util.find_first_node(root, HTerrain) as HTerrain - if terrain == null: - return - - var test_root : Node3D - if not terrain.has_node("__DEBUG"): - test_root = Node3D.new() - test_root.name = "__DEBUG" - terrain.add_child(test_root) - else: - test_root = terrain.get_node("__DEBUG") - - var space_state := terrain.get_world_3d().direct_space_state - var hit_material := StandardMaterial3D.new() - hit_material.albedo_color = Color(0, 1, 1) - var cube := BoxMesh.new() - - for zi in 16: - for xi in 16: - var hit_name := str(xi, "_", zi) - var pos := Vector3(xi * 16, 1000, zi * 16) - - var query := PhysicsRayQueryParameters3D.new() - query.from = pos - query.to = pos + Vector3(0, -2000, 0) - - var hit := space_state.intersect_ray(query) - - var mi : MeshInstance3D - if not test_root.has_node(hit_name): - mi = MeshInstance3D.new() - mi.name = hit_name - mi.material_override = hit_material - mi.mesh = cube - test_root.add_child(mi) - else: - mi = test_root.get_node(hit_name) - if hit.is_empty(): - mi.hide() - else: - mi.show() - mi.position = hit.position - - -func _spawn_vertical_bound_boxes(): - var data := _node.get_data() -# var sy = data._chunked_vertical_bounds_size_y -# var sx = data._chunked_vertical_bounds_size_x - var mat := StandardMaterial3D.new() - mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA - mat.albedo_color = Color(1,1,1,0.2) - for cy in range(30, 60): - for cx in range(30, 60): - var vb := data._chunked_vertical_bounds.get_pixel(cx, cy) - var minv := vb.r - var maxv := vb.g - var mi := MeshInstance3D.new() - mi.mesh = BoxMesh.new() - var cs := HTerrainData.VERTICAL_BOUNDS_CHUNK_SIZE - mi.mesh.size = Vector3(cs, maxv - minv, cs) - mi.position = Vector3( - (float(cx) + 0.5) * cs, - minv + mi.mesh.size.y * 0.5, - (float(cy) + 0.5) * cs) - mi.position *= _node.map_scale - mi.scale = _node.map_scale - mi.material_override = mat - _node.add_child(mi) - mi.owner = get_editor_interface().get_edited_scene_root() - -# if p_event is InputEventKey: -# if p_event.pressed == false: -# if p_event.scancode == KEY_SPACE and p_event.control: -# _spawn_vertical_bound_boxes() diff --git a/addons/zylann.hterrain/tools/preview_generator.gd b/addons/zylann.hterrain/tools/preview_generator.gd deleted file mode 100644 index 4b6e3db..0000000 --- a/addons/zylann.hterrain/tools/preview_generator.gd +++ /dev/null @@ -1,65 +0,0 @@ -@tool -extends EditorResourcePreviewGenerator - -const HTerrainData = preload("../hterrain_data.gd") -const HT_Errors = preload("../util/errors.gd") -const HT_Logger = preload("../util/logger.gd") - -var _logger = HT_Logger.get_for(self) - - -func _generate(res: Resource, size: Vector2i, metadata: Dictionary) -> Texture2D: - if res == null or not (res is HTerrainData): - return null - var normalmap = res.get_image(HTerrainData.CHANNEL_NORMAL) - if normalmap == null: - return null - return _generate_internal(normalmap, size) - - -func _generate_from_path(path: String, size: Vector2i, metadata: Dictionary) -> Texture2D: - if not path.ends_with("." + HTerrainData.META_EXTENSION): - return null - var data_dir := path.get_base_dir() - var normals_fname := str(HTerrainData.get_channel_name(HTerrainData.CHANNEL_NORMAL), ".png") - var normals_path := data_dir.path_join(normals_fname) - var normals := Image.new() - var err := normals.load(normals_path) - if err != OK: - _logger.error("Could not load '{0}', error {1}" \ - .format([normals_path, HT_Errors.get_message(err)])) - return null - return _generate_internal(normals, size) - - -func _handles(type: String) -> bool: - return type == "Resource" - - -static func _generate_internal(normals: Image, size: Vector2) -> Texture2D: - var im := Image.create(size.x, size.y, false, Image.FORMAT_RGB8) - - var light_dir := Vector3(-1, -0.5, -1).normalized() - - for y in im.get_height(): - for x in im.get_width(): - - var fx := float(x) / float(im.get_width()) - var fy := float(im.get_height() - y - 1) / float(im.get_height()) - var mx := int(fx * normals.get_width()) - var my := int(fy * normals.get_height()) - - var n := _decode_normal(normals.get_pixel(mx, my)) - - var ndot := -n.dot(light_dir) - var gs := clampf(0.5 * ndot + 0.5, 0.0, 1.0) - var col := Color(gs, gs, gs, 1.0) - - im.set_pixel(x, y, col) - - var tex := ImageTexture.create_from_image(im) - return tex - - -static func _decode_normal(c: Color) -> Vector3: - return Vector3(2.0 * c.r - 1.0, 2.0 * c.b - 1.0, 2.0 * c.g - 1.0) diff --git a/addons/zylann.hterrain/tools/progress_window.gd b/addons/zylann.hterrain/tools/progress_window.gd deleted file mode 100644 index 791717f..0000000 --- a/addons/zylann.hterrain/tools/progress_window.gd +++ /dev/null @@ -1,32 +0,0 @@ -@tool -extends AcceptDialog - - -#onready var _label = get_node("VBoxContainer/Label") -@onready var _progress_bar : ProgressBar = $VBoxContainer/ProgressBar - - -func _init(): - get_ok_button().hide() - - -func _show_progress(message, progress): - self.title = message - _progress_bar.ratio = progress - - -func handle_progress(info: Dictionary): - if info.has("finished") and info.finished: - hide() - - else: - if not visible: - popup_centered() - - var message = "" - if info.has("message"): - message = info.message - - _show_progress(info.message, info.progress) - # TODO Have builtin modal progress bar - # https://github.com/godotengine/godot/issues/17763 diff --git a/addons/zylann.hterrain/tools/progress_window.tscn b/addons/zylann.hterrain/tools/progress_window.tscn deleted file mode 100644 index e6d7d19..0000000 --- a/addons/zylann.hterrain/tools/progress_window.tscn +++ /dev/null @@ -1,22 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://b0f3h46ugtni6"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/progress_window.gd" id="1"] - -[node name="WindowDialog" type="AcceptDialog"] -title = "" -size = Vector2i(400, 100) -min_size = Vector2i(400, 40) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -8.0 - -[node name="ProgressBar" type="ProgressBar" parent="VBoxContainer"] -layout_mode = 2 -step = 1.0 diff --git a/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd b/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd deleted file mode 100644 index 617e457..0000000 --- a/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd +++ /dev/null @@ -1,174 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../util/util.gd") -const HT_Logger = preload("../../util/logger.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") - -const ANCHOR_TOP_LEFT = 0 -const ANCHOR_TOP = 1 -const ANCHOR_TOP_RIGHT = 2 -const ANCHOR_LEFT = 3 -const ANCHOR_CENTER = 4 -const ANCHOR_RIGHT = 5 -const ANCHOR_BOTTOM_LEFT = 6 -const ANCHOR_BOTTOM = 7 -const ANCHOR_BOTTOM_RIGHT = 8 -const ANCHOR_COUNT = 9 - -const _anchor_dirs = [ - [-1, -1], - [0, -1], - [1, -1], - [-1, 0], - [0, 0], - [1, 0], - [-1, 1], - [0, 1], - [1, 1] -] - -const _anchor_icon_names = [ - "anchor_top_left", - "anchor_top", - "anchor_top_right", - "anchor_left", - "anchor_center", - "anchor_right", - "anchor_bottom_left", - "anchor_bottom", - "anchor_bottom_right" -] - -signal permanent_change_performed(message) - -@onready var _resolution_dropdown : OptionButton = $VBoxContainer/GridContainer/ResolutionDropdown -@onready var _stretch_checkbox : CheckBox = $VBoxContainer/GridContainer/StretchCheckBox -@onready var _anchor_control : Control = $VBoxContainer/GridContainer/HBoxContainer/AnchorControl - -const _resolutions = HTerrainData.SUPPORTED_RESOLUTIONS - -var _anchor_buttons := [] -var _anchor_buttons_grid := {} -var _anchor_button_group : ButtonGroup = null -var _selected_anchor = ANCHOR_TOP_LEFT -var _logger = HT_Logger.get_for(self) - -var _terrain : HTerrain = null - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -static func _get_icon(name) -> Texture2D: - return load("res://addons/zylann.hterrain/tools/icons/icon_" + name + ".svg") - - -func _init(): - get_ok_button().hide() - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - # TEST - #show() - - for i in len(_resolutions): - _resolution_dropdown.add_item(str(_resolutions[i]), i) - - _anchor_button_group = ButtonGroup.new() - _anchor_buttons.resize(ANCHOR_COUNT) - var x := 0 - var y := 0 - for i in _anchor_control.get_child_count(): - var child_node = _anchor_control.get_child(i) - assert(child_node is Button) - var child := child_node as Button - child.toggle_mode = true - child.custom_minimum_size = child.size - child.icon = null - child.pressed.connect(_on_AnchorButton_pressed.bind(i, x, y)) - child.button_group = _anchor_button_group - _anchor_buttons[i] = child - _anchor_buttons_grid[Vector2(x, y)] = child - x += 1 - if x >= 3: - x = 0 - y += 1 - - _anchor_buttons[_selected_anchor].button_pressed = true - # The signal apparently doesn't trigger in this case - _on_AnchorButton_pressed(_selected_anchor, 0, 0) - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - if visible: - # Select current resolution - if _terrain != null and _terrain.get_data() != null: - var res := _terrain.get_data().get_resolution() - for i in len(_resolutions): - if res == _resolutions[i]: - _resolution_dropdown.select(i) - break - - -func _on_AnchorButton_pressed(anchor0: int, x0: int, y0: int): - _selected_anchor = anchor0 - - for button in _anchor_buttons: - button.icon = null - - for anchor in ANCHOR_COUNT: - var d = _anchor_dirs[anchor] - var nx = x0 + d[0] - var ny = y0 + d[1] - var k = Vector2(nx, ny) - if not _anchor_buttons_grid.has(k): - continue - var button : Button = _anchor_buttons_grid[k] - var icon := _get_icon(_anchor_icon_names[anchor]) - button.icon = icon - - -func _set_anchor_control_active(active: bool): - for button in _anchor_buttons: - button.disabled = not active - - -func _on_ResolutionDropdown_item_selected(id): - pass - - -func _on_StretchCheckBox_toggled(button_pressed: bool): - _set_anchor_control_active(not button_pressed) - - -func _on_ApplyButton_pressed(): - var stretch = _stretch_checkbox.button_pressed - var res = _resolutions[_resolution_dropdown.get_selected_id()] - var dir = _anchor_dirs[_selected_anchor] - _apply(res, stretch, Vector2(dir[0], dir[1])) - hide() - - -func _on_CancelButton_pressed(): - hide() - - -func _apply(p_resolution: int, p_stretch: bool, p_anchor: Vector2): - if _terrain == null: - _logger.error("Cannot apply resize, terrain is not set") - return - - var data = _terrain.get_data() - if data == null: - _logger.error("Cannot apply resize, terrain has no data") - return - - data.resize(p_resolution, p_stretch, p_anchor) - data.notify_full_change() - permanent_change_performed.emit("Resize terrain") diff --git a/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.tscn b/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.tscn deleted file mode 100644 index c0678ae..0000000 --- a/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.tscn +++ /dev/null @@ -1,159 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://gt402qqhab7j"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd" id="1"] -[ext_resource type="Texture2D" uid="uid://b4ya0po3a4nqa" path="res://addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg" id="2"] -[ext_resource type="Texture2D" uid="uid://d3vie0tj3ry6k" path="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg" id="3"] -[ext_resource type="Texture2D" uid="uid://b6l5dys0awbwd" path="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg" id="4"] -[ext_resource type="Texture2D" uid="uid://bdkcgtv1r5j31" path="res://addons/zylann.hterrain/tools/icons/icon_small_circle.svg" id="5"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="6"] - -[node name="ResizeDialog" type="AcceptDialog"] -title = "Resize terrain" -size = Vector2i(300, 201) -min_size = Vector2i(300, 200) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="GridContainer" type="GridContainer" parent="VBoxContainer"] -layout_mode = 2 -columns = 2 - -[node name="Label" type="Label" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -text = "Resolution" - -[node name="ResolutionDropdown" type="OptionButton" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -toggle_mode = false - -[node name="Label3" type="Label" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -text = "Stretch" - -[node name="StretchCheckBox" type="CheckBox" parent="VBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="Label2" type="Label" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -text = "Direction" - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="AnchorControl" type="GridContainer" parent="VBoxContainer/GridContainer/HBoxContainer"] -layout_mode = 2 -columns = 3 - -[node name="TopLeftButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="TopButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="TopRightButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="LeftButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="CenterButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="RightButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="ButtomLeftButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="ButtomButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="BottomRightButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="Reference" type="Control" parent="VBoxContainer/GridContainer/HBoxContainer"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 - -[node name="XArrow" type="TextureRect" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -modulate = Color(1, 0.292969, 0.292969, 1) -layout_mode = 0 -anchor_right = 1.0 -offset_left = 9.0 -offset_bottom = 16.0 -texture = ExtResource("3") - -[node name="ZArrow" type="TextureRect" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -modulate = Color(0.292969, 0.602295, 1, 1) -layout_mode = 0 -anchor_bottom = 1.0 -offset_top = 10.0 -offset_right = 16.0 -texture = ExtResource("4") - -[node name="ZLabel" type="Label" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -layout_mode = 0 -offset_left = 14.0 -offset_top = 54.0 -offset_right = 22.0 -offset_bottom = 68.0 -text = "Z" - -[node name="XLabel" type="Label" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -layout_mode = 0 -offset_left = 52.0 -offset_top = 14.0 -offset_right = 60.0 -offset_bottom = 28.0 -text = "X" - -[node name="Origin" type="TextureRect" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -layout_mode = 0 -offset_left = 3.0 -offset_top = 4.0 -offset_right = 11.0 -offset_bottom = 12.0 -texture = ExtResource("5") - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="ApplyButton" type="Button" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Apply (no undo)" - -[node name="CancelButton" type="Button" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("6")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 292.0 -offset_bottom = 183.0 - -[connection signal="item_selected" from="VBoxContainer/GridContainer/ResolutionDropdown" to="." method="_on_ResolutionDropdown_item_selected"] -[connection signal="toggled" from="VBoxContainer/GridContainer/StretchCheckBox" to="." method="_on_StretchCheckBox_toggled"] -[connection signal="pressed" from="VBoxContainer/HBoxContainer/ApplyButton" to="." method="_on_ApplyButton_pressed"] -[connection signal="pressed" from="VBoxContainer/HBoxContainer/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/addons/zylann.hterrain/tools/terrain_preview.gd b/addons/zylann.hterrain/tools/terrain_preview.gd deleted file mode 100644 index 1c64b6d..0000000 --- a/addons/zylann.hterrain/tools/terrain_preview.gd +++ /dev/null @@ -1,143 +0,0 @@ -@tool -extends SubViewportContainer - -const PREVIEW_MESH_LOD = 2 - -const HTerrainMesher = preload("../hterrain_mesher.gd") -const HT_Util = preload("../util/util.gd") - -signal dragged(relative, button_mask) - -@onready var _viewport : SubViewport = $Viewport -@onready var _mesh_instance : MeshInstance3D = $Viewport/MeshInstance -@onready var _camera : Camera3D = $Viewport/Camera -@onready var _light : DirectionalLight3D = $Viewport/DirectionalLight - -# Use the simplest shader -var _shader : Shader = load("res://addons/zylann.hterrain/shaders/simple4_lite.gdshader") -var _yaw := 0.0 -var _pitch := -PI / 6.0 -var _distance := 0.0 -var _default_distance := 0.0 -var _sea_outline : MeshInstance3D = null -var _sea_plane : MeshInstance3D = null -var _mesh_resolution := 0 - - -func _ready(): - if _sea_outline == null: - var mesh := HT_Util.create_wirecube_mesh() - var mat2 := StandardMaterial3D.new() - mat2.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - mat2.albedo_color = Color(0, 0.5, 1) - mesh.surface_set_material(0, mat2) - _sea_outline = MeshInstance3D.new() - _sea_outline.mesh = mesh - _viewport.add_child(_sea_outline) - - if _sea_plane == null: - var mesh := PlaneMesh.new() - mesh.size = Vector2(1, 1) - var mat2 := StandardMaterial3D.new() - mat2.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - mat2.albedo_color = Color(0, 0.5, 1, 0.5) - mat2.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA - mesh.material = mat2 - _sea_plane = MeshInstance3D.new() - _sea_plane.mesh = mesh - _sea_plane.hide() - _viewport.add_child(_sea_plane) - - -func setup(heights_texture: Texture2D, normals_texture: Texture2D): - var terrain_size := heights_texture.get_width() - var mesh_resolution := terrain_size / PREVIEW_MESH_LOD - - if _mesh_resolution != mesh_resolution or not (_mesh_instance.mesh is ArrayMesh): - _mesh_resolution = mesh_resolution - var mesh := HTerrainMesher.make_flat_chunk( - _mesh_resolution, _mesh_resolution, PREVIEW_MESH_LOD, 0) - _mesh_instance.mesh = mesh - _default_distance = _mesh_instance.get_aabb().size.x - _distance = _default_distance - #_mesh_instance.translation -= 0.5 * Vector3(terrain_size, 0, terrain_size) - _update_camera() - - var mat : ShaderMaterial = _mesh_instance.mesh.surface_get_material(0) - - if mat == null: - mat = ShaderMaterial.new() - mat.shader = _shader - _mesh_instance.mesh.surface_set_material(0, mat) - - mat.set_shader_parameter("u_terrain_heightmap", heights_texture) - mat.set_shader_parameter("u_terrain_normalmap", normals_texture) - mat.set_shader_parameter("u_terrain_inverse_transform", Transform3D()) - mat.set_shader_parameter("u_terrain_normal_basis", Basis()) - - var aabb := _mesh_instance.get_aabb() - _sea_outline.scale = aabb.size - - aabb = _mesh_instance.get_aabb() - _sea_plane.scale = Vector3(aabb.size.x, 1, aabb.size.z) - _sea_plane.position = Vector3(aabb.size.x, 0, aabb.size.z) / 2.0 - - -func set_sea_visible(visible: bool): - _sea_plane.visible = visible - - -func set_shadows_enabled(enabled: bool): - _light.shadow_enabled = enabled - - -func _update_camera(): - var aabb := _mesh_instance.get_aabb() - var target := aabb.position + 0.5 * aabb.size - var trans := Transform3D() - trans.basis = Basis(Quaternion(Vector3(0, 1, 0), _yaw) * Quaternion(Vector3(1, 0, 0), _pitch)) - var back := trans.basis.z - trans.origin = target + back * _distance - _camera.transform = trans - - -func cleanup(): - if _mesh_instance != null: - var mat : ShaderMaterial = _mesh_instance.mesh.surface_get_material(0) - assert(mat != null) - mat.set_shader_parameter("u_terrain_heightmap", null) - mat.set_shader_parameter("u_terrain_normalmap", null) - - -func _gui_input(event: InputEvent): - if HT_Util.is_in_edited_scene(self): - return - - if event is InputEventMouseMotion: - if event.button_mask & MOUSE_BUTTON_MASK_MIDDLE: - var d : Vector2 = 0.01 * event.relative - _yaw -= d.x - _pitch -= d.y - _update_camera() - else: - var rel : Vector2 = 0.01 * event.relative - # Align dragging to view rotation - rel = -rel.rotated(-_yaw) - dragged.emit(rel, event.button_mask) - - elif event is InputEventMouseButton: - if event.pressed: - - var factor := 1.2 - var max_factor := 10.0 - var min_distance := _default_distance / max_factor - var max_distance := _default_distance - - # Zoom in/out - if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: - _distance = clampf(_distance * factor, min_distance, max_distance) - _update_camera() - - elif event.button_index == MOUSE_BUTTON_WHEEL_UP: - _distance = clampf(_distance / factor, min_distance, max_distance) - _update_camera() diff --git a/addons/zylann.hterrain/tools/terrain_preview.tscn b/addons/zylann.hterrain/tools/terrain_preview.tscn deleted file mode 100644 index 0b87a16..0000000 --- a/addons/zylann.hterrain/tools/terrain_preview.tscn +++ /dev/null @@ -1,38 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bue2flijnxa3p"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/terrain_preview.gd" id="1"] - -[sub_resource type="PlaneMesh" id="3"] -size = Vector2(256, 256) - -[node name="TerrainPreview" type="SubViewportContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 0 -stretch = true -script = ExtResource("1") - -[node name="Viewport" type="SubViewport" parent="."] -own_world_3d = true -handle_input_locally = false -size = Vector2i(1152, 648) -render_target_update_mode = 4 - -[node name="DirectionalLight" type="DirectionalLight3D" parent="Viewport"] -transform = Transform3D(-0.901211, 0.315056, -0.297588, 0, 0.686666, 0.726973, 0.433381, 0.655156, -0.618831, 0, 0, 0) -light_bake_mode = 1 -shadow_enabled = true -shadow_bias = 0.5 -directional_shadow_mode = 1 -directional_shadow_max_distance = 1000.0 - -[node name="MeshInstance" type="MeshInstance3D" parent="Viewport"] -mesh = SubResource("3") - -[node name="Camera" type="Camera3D" parent="Viewport"] -transform = Transform3D(-1, 3.31486e-08, -8.08945e-08, 0, 0.925325, 0.379176, 8.74228e-08, 0.379176, -0.925325, -2.25312e-05, 145.456, -348.286) -current = true -fov = 70.0 -near = 1.0 -far = 1000.0 diff --git a/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader b/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader deleted file mode 100644 index 7ac1b98..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader +++ /dev/null @@ -1,6 +0,0 @@ -shader_type canvas_item; - -void fragment() { - float a = texture(TEXTURE, UV).a; - COLOR = vec4(a, a, a, 1.0); -} diff --git a/addons/zylann.hterrain/tools/texture_editor/display_alpha_material.tres b/addons/zylann.hterrain/tools/texture_editor/display_alpha_material.tres deleted file mode 100644 index 34ef863..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/display_alpha_material.tres +++ /dev/null @@ -1,9 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader" type="Shader" id=1] - -[resource] - -render_priority = 0 -shader = ExtResource( 1 ) - diff --git a/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader b/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader deleted file mode 100644 index 384e1a2..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader +++ /dev/null @@ -1,9 +0,0 @@ -shader_type canvas_item; - -uniform sampler2DArray u_texture_array; -uniform float u_index; - -void fragment() { - vec4 col = texture(u_texture_array, vec3(UV.x, UV.y, u_index)); - COLOR = vec4(col.a, col.a, col.a, 1.0); -} diff --git a/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader b/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader deleted file mode 100644 index dcc1fda..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader +++ /dev/null @@ -1,7 +0,0 @@ -shader_type canvas_item; - -void fragment() { - // TODO Have an option to "undo" sRGB, for funzies? - vec4 col = texture(TEXTURE, UV); - COLOR = vec4(col.rgb, 1.0); -} diff --git a/addons/zylann.hterrain/tools/texture_editor/display_color_material.tres b/addons/zylann.hterrain/tools/texture_editor/display_color_material.tres deleted file mode 100644 index 094400f..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/display_color_material.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/display_color.gdshader" type="Shader" id=1] - -[resource] -shader = ExtResource( 1 ) diff --git a/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader b/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader deleted file mode 100644 index d2e4f5c..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader +++ /dev/null @@ -1,9 +0,0 @@ -shader_type canvas_item; - -uniform sampler2DArray u_texture_array; -uniform float u_index; - -void fragment() { - vec4 col = texture(u_texture_array, vec3(UV.x, UV.y, u_index)); - COLOR = vec4(col.rgb, 1.0); -} diff --git a/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader b/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader deleted file mode 100644 index 665af53..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader +++ /dev/null @@ -1,28 +0,0 @@ -shader_type canvas_item; - -uniform float u_strength = 1.0; -uniform bool u_flip_y = false; - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec3 pack_normal(vec3 n) { - n.z *= -1.0; - return 0.5 * (n.xzy + vec3(1.0)); -} - -void fragment() { - vec4 col = texture(TEXTURE, UV); - vec3 n = unpack_normal(col); - n = normalize(mix(n, vec3(-n.x, n.y, -n.z), 0.5 - 0.5 * u_strength)); - if (u_flip_y) { - n.z = -n.z; - } - col.rgb = pack_normal(n); - COLOR = vec4(col.rgb, 1.0); -} diff --git a/addons/zylann.hterrain/tools/texture_editor/flow_container.gd b/addons/zylann.hterrain/tools/texture_editor/flow_container.gd deleted file mode 100644 index 4425134..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/flow_container.gd +++ /dev/null @@ -1,41 +0,0 @@ -@tool -extends Container - -const SEPARATION = 2 - - -func _notification(what: int): - if what == NOTIFICATION_SORT_CHILDREN: - _sort_children2() - - -# TODO Function with ugly name to workaround a Godot 3.1 issue -# See https://github.com/godotengine/godot/pull/38396 -func _sort_children2(): - var max_x := size.x - SEPARATION - var pos := Vector2(SEPARATION, SEPARATION) - var line_height := 0 - - for i in get_child_count(): - var child_node = get_child(i) - if not child_node is Control: - continue - var child := child_node as Control - - var rect := child.get_rect() - - if rect.size.y > line_height: - line_height = rect.size.y - - if pos.x + rect.size.x > max_x: - pos.x = SEPARATION - pos.y += line_height + SEPARATION - line_height = rect.size.y - - rect.position = pos - fit_child_in_rect(child, rect) - - pos.x += rect.size.x + SEPARATION - - custom_minimum_size.y = pos.y + line_height - diff --git a/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd b/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd deleted file mode 100644 index 834accb..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd +++ /dev/null @@ -1,60 +0,0 @@ -@tool -extends Control - -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_EmptyTexture = preload("../../icons/empty.png") -const EMPTY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal load_pressed -signal clear_pressed - - -@onready var _label : Label = $Label -@onready var _texture_rect : TextureRect = $TextureRect - -@onready var _buttons = [ - $LoadButton, - $ClearButton -] - -var _material : Material -var _is_empty := true - - -func set_label(text: String): - _label.text = text - - -func set_texture(tex: Texture): - if tex == null: - _texture_rect.texture = load(EMPTY_TEXTURE_PATH) - _texture_rect.material = null - _is_empty = true - else: - _texture_rect.texture = tex - _texture_rect.material = _material - _is_empty = false - - -func set_texture_tooltip(msg: String): - _texture_rect.tooltip_text = msg - - -func _on_LoadButton_pressed(): - load_pressed.emit() - - -func _on_ClearButton_pressed(): - clear_pressed.emit() - - -func set_material(mat: Material): - _material = mat - if not _is_empty: - _texture_rect.material = _material - - -func set_enabled(enabled: bool): - for b in _buttons: - b.disabled = not enabled - diff --git a/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn b/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn deleted file mode 100644 index 9907e0c..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn +++ /dev/null @@ -1,29 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dqgaomu3tr1ym"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd" id="2"] - -[node name="SourceFileItem" type="VBoxContainer"] -offset_right = 128.0 -offset_bottom = 194.0 -script = ExtResource("2") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -text = "Albedo" - -[node name="TextureRect" type="TextureRect" parent="."] -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="LoadButton" type="Button" parent="."] -layout_mode = 2 -text = "Load..." - -[node name="ClearButton" type="Button" parent="."] -layout_mode = 2 -text = "Clear" - -[connection signal="pressed" from="LoadButton" to="." method="_on_LoadButton_pressed"] -[connection signal="pressed" from="ClearButton" to="." method="_on_ClearButton_pressed"] diff --git a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd b/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd deleted file mode 100644 index 9d11bef..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd +++ /dev/null @@ -1,529 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrainTextureSet = preload("../../../hterrain_texture_set.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_Util = preload("../../../util/util.gd") -const HT_Logger = preload("../../../util/logger.gd") - -const HT_ColorShader = preload("../display_color.gdshader") -const HT_ColorSliceShader = preload("../display_color_slice.gdshader") -const HT_AlphaShader = preload("../display_alpha.gdshader") -const HT_AlphaSliceShader = preload("../display_alpha_slice.gdshader") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_EmptyTexture = preload("../../icons/empty.png") -const EMPTY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal import_selected - -@onready var _slots_list : ItemList = $VB/HS/VB/SlotsList -@onready var _albedo_preview : TextureRect = $VB/HS/VB2/GC/AlbedoPreview -@onready var _bump_preview : TextureRect = $VB/HS/VB2/GC/BumpPreview -@onready var _normal_preview : TextureRect = $VB/HS/VB2/GC/NormalPreview -@onready var _roughness_preview : TextureRect = $VB/HS/VB2/GC/RoughnessPreview -@onready var _load_albedo_button : Button = $VB/HS/VB2/GC/LoadAlbedo -@onready var _load_normal_button : Button = $VB/HS/VB2/GC/LoadNormal -@onready var _clear_albedo_button : Button = $VB/HS/VB2/GC/ClearAlbedo -@onready var _clear_normal_button : Button = $VB/HS/VB2/GC/ClearNormal -@onready var _mode_selector : OptionButton = $VB/HS/VB2/GC2/ModeSelector -@onready var _add_slot_button : Button = $VB/HS/VB/HB/AddSlot -@onready var _remove_slot_button : Button = $VB/HS/VB/HB/RemoveSlot - -var _texture_set : HTerrainTextureSet -var _undo_redo_manager : EditorUndoRedoManager - -var _mode_confirmation_dialog : ConfirmationDialog -var _delete_slot_confirmation_dialog : ConfirmationDialog -var _load_texture_dialog : ConfirmationDialog -var _load_texture_array_dialog : ConfirmationDialog -var _load_texture_type := -1 - -var _logger = HT_Logger.get_for(self) - - -func _init(): - get_ok_button().hide() - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - for id in HTerrainTextureSet.MODE_COUNT: - var mode_name = HTerrainTextureSet.get_import_mode_name(id) - _mode_selector.add_item(mode_name, id) - - -func setup_dialogs(parent: Node): - var d = HT_EditorUtil.create_open_texture_dialog() - d.file_selected.connect(_on_LoadTextureDialog_file_selected) - _load_texture_dialog = d - add_child(d) - - d = HT_EditorUtil.create_open_texture_array_dialog() - d.file_selected.connect(_on_LoadTextureArrayDialog_file_selected) - _load_texture_array_dialog = d - add_child(d) - - d = ConfirmationDialog.new() - d.confirmed.connect(_on_ModeConfirmationDialog_confirmed) - # This is ridiculous. - # See https://github.com/godotengine/godot/issues/17460 -# d.connect("modal_closed", self, "_on_ModeConfirmationDialog_cancelled") -# d.get_close_button().connect("pressed", self, "_on_ModeConfirmationDialog_cancelled") -# d.get_cancel().connect("pressed", self, "_on_ModeConfirmationDialog_cancelled") - _mode_confirmation_dialog = d - add_child(d) - - -func _notification(what: int): - if HT_Util.is_in_edited_scene(self): - return - - if what == NOTIFICATION_EXIT_TREE: - # Have to check for null in all of them, - # because otherwise it breaks in the scene editor... - if _load_texture_dialog != null: - _load_texture_dialog.queue_free() - if _load_texture_array_dialog != null: - _load_texture_array_dialog.queue_free() - - if what == NOTIFICATION_VISIBILITY_CHANGED: - if not visible: - # Cleanup referenced resources - set_texture_set(null) - - -func set_undo_redo(ur: EditorUndoRedoManager): - _undo_redo_manager = ur - - -func set_texture_set(texture_set: HTerrainTextureSet): - if _texture_set == texture_set: - return - - if _texture_set != null: - _texture_set.changed.disconnect(_on_texture_set_changed) - - _texture_set = texture_set - - if _texture_set != null: - _texture_set.changed.connect(_on_texture_set_changed) - _update_ui_from_data() - - -func _on_texture_set_changed(): - _update_ui_from_data() - - -func _update_ui_from_data(): - var prev_selected_items = _slots_list.get_selected_items() - - _slots_list.clear() - - var slots_count := _texture_set.get_slots_count() - for slot_index in slots_count: - _slots_list.add_item("Texture {0}".format([slot_index])) - - _set_selected_id(_mode_selector, _texture_set.get_mode()) - - if _slots_list.get_item_count() > 0: - if len(prev_selected_items) > 0: - var i : int = prev_selected_items[0] - if i >= _slots_list.get_item_count(): - i = _slots_list.get_item_count() - 1 - _select_slot(i) - else: - _select_slot(0) - else: - _clear_previews() - - var max_slots := HTerrainTextureSet.get_max_slots_for_mode(_texture_set.get_mode()) - _add_slot_button.disabled = slots_count >= max_slots - _remove_slot_button.disabled = slots_count == 0 - - var buttons := [ - _load_albedo_button, - _load_normal_button, - _clear_albedo_button, - _clear_normal_button - ] - - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _add_slot_button.visible = true - _remove_slot_button.visible = true - _load_albedo_button.text = "Load..." - _load_normal_button.text = "Load..." - - for b in buttons: - b.disabled = (slots_count == 0) - - else: - _add_slot_button.visible = false - _remove_slot_button.visible = false - _load_albedo_button.text = "Load Array..." - _load_normal_button.text = "Load Array..." - - for b in buttons: - b.disabled = false - - -static func _set_selected_id(ob: OptionButton, id: int): - for i in ob.get_item_count(): - if ob.get_item_id(i) == id: - ob.selected = i - break - - -func select_slot(slot_index: int): - var count = _texture_set.get_slots_count() - if count > 0: - if slot_index >= count: - slot_index = count - 1 - _select_slot(slot_index) - - -func _clear_previews(): - var empty_texture : Texture2D = load(EMPTY_TEXTURE_PATH) - if empty_texture == null: - _logger.error(str("Failed to load empty texture ", EMPTY_TEXTURE_PATH)) - - _albedo_preview.texture = empty_texture - _bump_preview.texture = empty_texture - _normal_preview.texture = empty_texture - _roughness_preview.texture = empty_texture - - _albedo_preview.tooltip_text = _get_resource_path_or_empty(null) - _bump_preview.tooltip_text = _get_resource_path_or_empty(null) - _normal_preview.tooltip_text = _get_resource_path_or_empty(null) - _roughness_preview.tooltip_text = _get_resource_path_or_empty(null) - - -func _select_slot(slot_index: int): - assert(slot_index >= 0) - assert(slot_index < _texture_set.get_slots_count()) - - var empty_texture : Texture2D = load(EMPTY_TEXTURE_PATH) - if empty_texture == null: - _logger.error(str("Failed to load empty texture ", EMPTY_TEXTURE_PATH)) - - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - var albedo_tex := \ - _texture_set.get_texture(slot_index, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - var normal_tex := \ - _texture_set.get_texture(slot_index, HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - _albedo_preview.texture = albedo_tex if albedo_tex != null else empty_texture - _bump_preview.texture = albedo_tex if albedo_tex != null else empty_texture - _normal_preview.texture = normal_tex if normal_tex != null else empty_texture - _roughness_preview.texture = normal_tex if normal_tex != null else empty_texture - - _albedo_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _bump_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _normal_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - _roughness_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - - _albedo_preview.material.shader = HT_ColorShader - _bump_preview.material.shader = HT_AlphaShader - _normal_preview.material.shader = HT_ColorShader - _roughness_preview.material.shader = HT_AlphaShader - - _albedo_preview.material.set_shader_parameter("u_texture_array", null) - _bump_preview.material.set_shader_parameter("u_texture_array", null) - _normal_preview.material.set_shader_parameter("u_texture_array", null) - _roughness_preview.material.set_shader_parameter("u_texture_array", null) - - else: - var albedo_tex := _texture_set.get_texture_array(HTerrainTextureSet.TYPE_ALBEDO_BUMP) - var normal_tex := _texture_set.get_texture_array(HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - _albedo_preview.texture = empty_texture - _bump_preview.texture = empty_texture - _normal_preview.texture = empty_texture - _roughness_preview.texture = empty_texture - - _albedo_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _bump_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _normal_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - _roughness_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - - _albedo_preview.material.shader = HT_ColorSliceShader - _bump_preview.material.shader = HT_AlphaSliceShader - _normal_preview.material.shader = \ - HT_ColorSliceShader if normal_tex != null else HT_ColorShader - _roughness_preview.material.shader = \ - HT_AlphaSliceShader if normal_tex != null else HT_AlphaShader - - _albedo_preview.material.set_shader_parameter("u_texture_array", albedo_tex) - _bump_preview.material.set_shader_parameter("u_texture_array", albedo_tex) - _normal_preview.material.set_shader_parameter("u_texture_array", normal_tex) - _roughness_preview.material.set_shader_parameter("u_texture_array", normal_tex) - - _albedo_preview.material.set_shader_parameter("u_index", slot_index) - _bump_preview.material.set_shader_parameter("u_index", slot_index) - _normal_preview.material.set_shader_parameter("u_index", slot_index) - _roughness_preview.material.set_shader_parameter("u_index", slot_index) - - _slots_list.select(slot_index) - - -static func _get_resource_path_or_empty(res: Resource) -> String: - if res != null: - return res.resource_path - return "" - - -func _on_ImportButton_pressed(): - import_selected.emit() - - -func _on_CloseButton_pressed(): - hide() - - -func _get_undo_redo_for_texture_set() -> UndoRedo: - return _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_texture_set)) - - -func _on_AddSlot_pressed(): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES) - var slot_index = _texture_set.get_slots_count() - var ur := _get_undo_redo_for_texture_set() - ur.create_action("HTerrainTextureSet: add slot") - ur.add_do_method(_texture_set.insert_slot.bind(-1)) - ur.add_undo_method(_texture_set.remove_slot.bind(slot_index)) - ur.commit_action() - - -func _on_RemoveSlot_pressed(): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES) - - var slot_index = _slots_list.get_selected_items()[0] - var textures = [] - for type in HTerrainTextureSet.TYPE_COUNT: - textures.append(_texture_set.get_texture(slot_index, type)) - - var ur := _get_undo_redo_for_texture_set() - - ur.create_action("HTerrainTextureSet: remove slot") - - ur.add_do_method(_texture_set.remove_slot.bind(slot_index)) - - ur.add_undo_method(_texture_set.insert_slot.bind(slot_index)) - for type in len(textures): - var texture = textures[type] - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture == null: - ur.add_undo_method(_texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_undo_method(_texture_set.set_texture.bind(slot_index, type, texture)) - - ur.commit_action() - - -func _on_SlotsList_item_selected(index: int): - _select_slot(index) - - -func _open_load_texture_dialog(type: int): - _load_texture_type = type - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _load_texture_dialog.popup_centered_ratio() - else: - _load_texture_array_dialog.popup_centered_ratio() - - -func _on_LoadAlbedo_pressed(): - _open_load_texture_dialog(HTerrainTextureSet.TYPE_ALBEDO_BUMP) - - -func _on_LoadNormal_pressed(): - _open_load_texture_dialog(HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - -func _set_texture_action(slot_index: int, texture: Texture, type: int): - var prev_texture = _texture_set.get_texture(slot_index, type) - - var ur := _get_undo_redo_for_texture_set() - - ur.create_action("HTerrainTextureSet: load texture") - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture == null: - ur.add_do_method(_texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_do_method(_texture_set.set_texture.bind(slot_index, type, texture)) - ur.add_do_method(self._select_slot.bind(slot_index)) - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if prev_texture == null: - ur.add_undo_method(_texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_undo_method(_texture_set.set_texture.bind(slot_index, type, prev_texture)) - ur.add_undo_method(self._select_slot.bind(slot_index)) - - ur.commit_action() - - -func _set_texture_array_action(slot_index: int, texture_array: TextureLayered, type: int): - var prev_texture_array = _texture_set.get_texture_array(type) - - var ur := _get_undo_redo_for_texture_set() - - ur.create_action("HTerrainTextureSet: load texture array") - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture_array == null: - ur.add_do_method(_texture_set.set_texture_array_null.bind(type)) - # Can't select a slot after this because there won't be any after the array is removed - else: - ur.add_do_method(_texture_set.set_texture_array.bind(type, texture_array)) - ur.add_do_method(self._select_slot.bind(slot_index)) - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if prev_texture_array == null: - ur.add_undo_method(_texture_set.set_texture_array_null.bind(type)) - # Can't select a slot after this because there won't be any after the array is removed - else: - ur.add_undo_method(_texture_set.set_texture_array.bind(type, prev_texture_array)) - ur.add_undo_method(self._select_slot.bind(slot_index)) - - ur.commit_action() - - -func _on_LoadTextureDialog_file_selected(fpath: String): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES) - var texture = load(fpath) - assert(texture != null) - var slot_index : int = _slots_list.get_selected_items()[0] - _set_texture_action(slot_index, texture, _load_texture_type) - - -func _on_LoadTextureArrayDialog_file_selected(fpath: String): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURE_ARRAYS) - var texture_array = load(fpath) - assert(texture_array != null) - # It's possible no slot exists at the moment, - # because there could be no texture array already set. - # The number of slots in the new array might also be different. - # So in this case we'll default to selecting the first slot. - var slot_index := 0 - _set_texture_array_action(slot_index, texture_array, _load_texture_type) - - -func _on_ClearAlbedo_pressed(): - var slot_index : int = _slots_list.get_selected_items()[0] - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _set_texture_action(slot_index, null, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - else: - _set_texture_array_action(slot_index, null, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - - -func _on_ClearNormal_pressed(): - var slot_index : int = _slots_list.get_selected_items()[0] - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _set_texture_action(slot_index, null, HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - else: - _set_texture_array_action(slot_index, null, HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - -func _on_ModeSelector_item_selected(index: int): - var id = _mode_selector.get_selected_id() - if id == _texture_set.get_mode(): - return - - # Early-cancel the change in OptionButton, so we won't need to rely on - # the (inexistent) cancel signal from ConfirmationDialog - _set_selected_id(_mode_selector, _texture_set.get_mode()) - - if not _texture_set.has_any_textures(): - _switch_mode_action() - - else: - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _mode_confirmation_dialog.window_title = "Switch to TextureArrays" - _mode_confirmation_dialog.dialog_text = \ - "This will unload all textures currently setup. Do you want to continue?" - _mode_confirmation_dialog.popup_centered() - - else: - _mode_confirmation_dialog.window_title = "Switch to Textures" - _mode_confirmation_dialog.dialog_text = \ - "This will unload all textures currently setup. Do you want to continue?" - _mode_confirmation_dialog.popup_centered() - - -func _on_ModeConfirmationDialog_confirmed(): - _switch_mode_action() - - -func _switch_mode_action(): - var mode := _texture_set.get_mode() - var ur := _get_undo_redo_for_texture_set() - - if mode == HTerrainTextureSet.MODE_TEXTURES: - ur.create_action("HTerrainTextureSet: switch to TextureArrays") - ur.add_do_method(_texture_set.set_mode.bind(HTerrainTextureSet.MODE_TEXTURE_ARRAYS)) - backup_for_undo(_texture_set, ur) - - else: - ur.create_action("HTerrainTextureSet: switch to Textures") - ur.add_do_method(_texture_set.set_mode.bind(HTerrainTextureSet.MODE_TEXTURES)) - backup_for_undo(_texture_set, ur) - - ur.commit_action() - - -static func backup_for_undo(texture_set: HTerrainTextureSet, ur: UndoRedo): - var mode := texture_set.get_mode() - - ur.add_undo_method(texture_set.clear) - ur.add_undo_method(texture_set.set_mode.bind(mode)) - - if mode == HTerrainTextureSet.MODE_TEXTURES: - # Backup slots - var slot_count := texture_set.get_slots_count() - var type_textures := [] - for type in HTerrainTextureSet.TYPE_COUNT: - var textures := [] - for slot_index in slot_count: - textures.append(texture_set.get_texture(slot_index, type)) - type_textures.append(textures) - - for type in len(type_textures): - var textures = type_textures[type] - for slot_index in len(textures): - ur.add_undo_method(texture_set.insert_slot.bind(slot_index)) - var texture = textures[slot_index] - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture == null: - ur.add_undo_method(texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_undo_method(texture_set.set_texture.bind(slot_index, type, texture)) - - else: - # Backup slots - var type_textures := [] - for type in HTerrainTextureSet.TYPE_COUNT: - type_textures.append(texture_set.get_texture_array(type)) - - for type in len(type_textures): - var texture_array = type_textures[type] - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture_array == null: - ur.add_undo_method(texture_set.set_texture_array_null.bind(type)) - else: - ur.add_undo_method(texture_set.set_texture_array.bind(type, texture_array)) - - -#func _on_ModeConfirmationDialog_cancelled(): -# print("Cancelled") -# _set_selected_id(_mode_selector, _texture_set.get_mode()) - diff --git a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.tscn b/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.tscn deleted file mode 100644 index f69c89a..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.tscn +++ /dev/null @@ -1,194 +0,0 @@ -[gd_scene load_steps=9 format=3 uid="uid://c0e7ifnoygvr6"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd" id="1"] -[ext_resource type="Shader" path="res://addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader" id="2"] -[ext_resource type="Shader" path="res://addons/zylann.hterrain/tools/texture_editor/display_color.gdshader" id="3"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="5"] - -[sub_resource type="ShaderMaterial" id="1"] -shader = ExtResource("3") - -[sub_resource type="ShaderMaterial" id="2"] -shader = ExtResource("2") - -[sub_resource type="ShaderMaterial" id="3"] -shader = ExtResource("3") - -[sub_resource type="ShaderMaterial" id="4"] -shader = ExtResource("2") - -[node name="TextureSetEditor" type="AcceptDialog"] -title = "TextureSet Editor" -size = Vector2i(666, 341) -min_size = Vector2i(652, 320) -script = ExtResource("1") - -[node name="VB" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="HS" type="HSplitContainer" parent="VB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VB" type="VBoxContainer" parent="VB/HS"] -layout_mode = 2 - -[node name="SlotsList" type="ItemList" parent="VB/HS/VB"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -size_flags_vertical = 3 - -[node name="HB" type="HBoxContainer" parent="VB/HS/VB"] -layout_mode = 2 - -[node name="AddSlot" type="Button" parent="VB/HS/VB/HB"] -layout_mode = 2 -text = "+" - -[node name="Control" type="Control" parent="VB/HS/VB/HB"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="RemoveSlot" type="Button" parent="VB/HS/VB/HB"] -layout_mode = 2 -text = "-" - -[node name="VB2" type="VBoxContainer" parent="VB/HS"] -layout_mode = 2 - -[node name="GC" type="GridContainer" parent="VB/HS/VB2"] -layout_mode = 2 -columns = 4 - -[node name="AlbedoLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Albedo" - -[node name="AlbedoExtraLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "+ alpha bump" - -[node name="NormalLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Normal" - -[node name="NormalExtraLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "+ alpha roughness" - -[node name="AlbedoPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("1") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="BumpPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("2") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="NormalPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("3") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="RoughnessPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("4") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="LoadAlbedo" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Load..." - -[node name="Spacer" type="Control" parent="VB/HS/VB2/GC"] -layout_mode = 2 - -[node name="LoadNormal" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Load..." - -[node name="Spacer2" type="Control" parent="VB/HS/VB2/GC"] -layout_mode = 2 - -[node name="ClearAlbedo" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Clear" - -[node name="Spacer3" type="Control" parent="VB/HS/VB2/GC"] -layout_mode = 2 - -[node name="ClearNormal" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Clear" - -[node name="HSeparator" type="Control" parent="VB/HS/VB2"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 - -[node name="GC2" type="HBoxContainer" parent="VB/HS/VB2"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/HS/VB2/GC2"] -layout_mode = 2 -text = "Mode" - -[node name="ModeSelector" type="OptionButton" parent="VB/HS/VB2/GC2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Spacer" type="Control" parent="VB/HS/VB2/GC2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Spacer" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="VB"] -layout_mode = 2 -alignment = 1 - -[node name="ImportButton" type="Button" parent="VB/HB"] -layout_mode = 2 -text = "Import..." - -[node name="CloseButton" type="Button" parent="VB/HB"] -layout_mode = 2 -text = "Close" - -[node name="Spacer2" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 2) -layout_mode = 2 - -[node name="DialogFitter" parent="." instance=ExtResource("5")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 658.0 -offset_bottom = 323.0 - -[connection signal="item_selected" from="VB/HS/VB/SlotsList" to="." method="_on_SlotsList_item_selected"] -[connection signal="pressed" from="VB/HS/VB/HB/AddSlot" to="." method="_on_AddSlot_pressed"] -[connection signal="pressed" from="VB/HS/VB/HB/RemoveSlot" to="." method="_on_RemoveSlot_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/LoadAlbedo" to="." method="_on_LoadAlbedo_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/LoadNormal" to="." method="_on_LoadNormal_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/ClearAlbedo" to="." method="_on_ClearAlbedo_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/ClearNormal" to="." method="_on_ClearNormal_pressed"] -[connection signal="item_selected" from="VB/HS/VB2/GC2/ModeSelector" to="." method="_on_ModeSelector_item_selected"] -[connection signal="pressed" from="VB/HB/ImportButton" to="." method="_on_ImportButton_pressed"] -[connection signal="pressed" from="VB/HB/CloseButton" to="." method="_on_CloseButton_pressed"] diff --git a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd b/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd deleted file mode 100644 index f865f63..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd +++ /dev/null @@ -1,920 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrainTextureSet = preload("../../../hterrain_texture_set.gd") -const HT_Logger = preload("../../../util/logger.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_Errors = preload("../../../util/errors.gd") -const HT_TextureSetEditor = preload("./texture_set_editor.gd") -const HT_Result = preload("../../util/result.gd") -const HT_Util = preload("../../../util/util.gd") -const HT_PackedTextureUtil = preload("../../packed_textures/packed_texture_util.gd") -const ResourceImporterTexture_Unexposed = preload("../../util/resource_importer_texture.gd") -const ResourceImporterTextureLayered_Unexposed = preload( - "../../util/resource_importer_texture_layered.gd") - -const HT_NormalMapPreviewShader = preload("../display_normal.gdshader") - -const COMPRESS_RAW = 0 -const COMPRESS_LOSSLESS = 1 -const COMPRESS_LOSSY = 1 -const COMPRESS_VRAM = 2 -const COMPRESS_COUNT = 3 - -const _compress_names = ["Raw", "Lossless", "Lossy", "VRAM"] - -# Indexed by HTerrainTextureSet.SRC_TYPE_* constants -const _smart_pick_file_keywords = [ - ["albedo", "color", "col", "diffuse"], - ["bump", "height", "depth", "displacement", "disp"], - ["normal", "norm", "nrm"], - ["roughness", "rough", "rgh"] -] - -signal import_finished - -@onready var _texture_editors = [ - $Import/HS/VB2/HB/Albedo, - $Import/HS/VB2/HB/Bump, - $Import/HS/VB2/HB/Normal, - $Import/HS/VB2/HB/Roughness -] - -@onready var _slots_list : ItemList = $Import/HS/VB/SlotsList - -# TODO Some shortcuts to import options were disabled in the GUI because of Godot issues. -# If users want to customize that, they need to do it on the files directly. -# -# There is no script API in Godot to choose the import settings of a generated file. -# They always start with the defaults, and the only implemented case is for the import dock. -# It appeared possible to reverse-engineer and write a .import file as done in HTerrainData, -# however when I tried this with custom importers, Godot stopped importing after scan(), -# and the resources could not load. However, selecting them each and clicking "Reimport" -# did import them fine. Unfortunately, this short-circuits the workflow. -# Since I have no idea what's going on with this reverse-engineering, I had to drop those options. -# Godot needs an API to import specific files and choose settings before the first import. -# -# Godot 4: now we'll really need it, let's enable and we'll see if it works -# when we can test the workflow... -const _WRITE_IMPORT_FILES = true - -@onready var _import_mode_selector : OptionButton = $Import/GC/ImportModeSelector -@onready var _compression_selector : OptionButton = $Import/GC/CompressionSelector -@onready var _resolution_spinbox : SpinBox = $Import/GC/ResolutionSpinBox -@onready var _mipmaps_checkbox : CheckBox = $Import/GC/MipmapsCheckbox -@onready var _add_slot_button : Button = $Import/HS/VB/HB/AddSlotButton -@onready var _remove_slot_button : Button = $Import/HS/VB/HB/RemoveSlotButton -@onready var _import_directory_line_edit : LineEdit = $Import/HB2/ImportDirectoryLineEdit -@onready var _normalmap_flip_checkbox : CheckBox = $Import/HS/VB2/HB/Normal/NormalMapFlipY - -var _texture_set : HTerrainTextureSet -var _undo_redo_manager : EditorUndoRedoManager -var _logger = HT_Logger.get_for(self) - -# This is normally an `EditorFileDialog`. I can't type-hint this one properly, -# because when I test this UI in isolation, I can't use `EditorFileDialog`. -var _load_texture_dialog : ConfirmationDialog -var _load_texture_type : int = -1 -var _error_popup : AcceptDialog -var _info_popup : AcceptDialog -var _delete_confirmation_popup : ConfirmationDialog -var _open_dir_dialog : ConfirmationDialog -var _editor_file_system : EditorFileSystem -var _normalmap_material : ShaderMaterial - -var _import_mode := HTerrainTextureSet.MODE_TEXTURES - -class HT_TextureSetImportEditorSlot: - # Array of strings. - # Can be either path to images, hexadecimal colors starting with #, or empty string for "null". - var texture_paths := [] - var flip_normalmap_y := false - - func _init(): - for i in HTerrainTextureSet.SRC_TYPE_COUNT: - texture_paths.append("") - -# Array of HT_TextureSetImportEditorSlot -var _slots_data := [] - -var _import_settings := { - "mipmaps": true, - "compression": COMPRESS_VRAM, - "resolution": 512 -} - - -func _init(): - get_ok_button().hide() - - # Default data - _slots_data.clear() - for i in 4: - _slots_data.append(HT_TextureSetImportEditorSlot.new()) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - for src_type in len(_texture_editors): - var ed = _texture_editors[src_type] - var typename = HTerrainTextureSet.get_source_texture_type_name(src_type) - ed.set_label(typename.capitalize()) - ed.load_pressed.connect(_on_texture_load_pressed.bind(src_type)) - ed.clear_pressed.connect(_on_texture_clear_pressed.bind(src_type)) - - for import_mode in HTerrainTextureSet.MODE_COUNT: - var n = HTerrainTextureSet.get_import_mode_name(import_mode) - _import_mode_selector.add_item(n, import_mode) - - for compress_mode in COMPRESS_COUNT: - var n = _compress_names[compress_mode] - _compression_selector.add_item(n, compress_mode) - - _normalmap_material = ShaderMaterial.new() - _normalmap_material.shader = HT_NormalMapPreviewShader - _texture_editors[HTerrainTextureSet.SRC_TYPE_NORMAL].set_material(_normalmap_material) - - -func setup_dialogs(parent: Node): - var d = HT_EditorUtil.create_open_image_dialog() - d.file_selected.connect(_on_LoadTextureDialog_file_selected) - _load_texture_dialog = d - add_child(d) - - d = AcceptDialog.new() - d.title = "Import error" - _error_popup = d - add_child(_error_popup) - - d = AcceptDialog.new() - d.title = "Info" - _info_popup = d - add_child(_info_popup) - - d = ConfirmationDialog.new() - d.confirmed.connect(_on_delete_confirmation_popup_confirmed) - _delete_confirmation_popup = d - add_child(_delete_confirmation_popup) - - d = HT_EditorUtil.create_open_dir_dialog() - d.title = "Choose import directory" - d.dir_selected.connect(_on_OpenDirDialog_dir_selected) - _open_dir_dialog = d - add_child(_open_dir_dialog) - - _update_ui_from_data() - - -func _notification(what: int): - if what == NOTIFICATION_EXIT_TREE: - # Have to check for null in all of them, - # because otherwise it breaks in the scene editor... - if _load_texture_dialog != null: - _load_texture_dialog.queue_free() - if _error_popup != null: - _error_popup.queue_free() - if _delete_confirmation_popup != null: - _delete_confirmation_popup.queue_free() - if _open_dir_dialog != null: - _open_dir_dialog.queue_free() - if _info_popup != null: - _info_popup.queue_free() - - -# TODO Is it still necessary for an import tab? -func set_undo_redo(ur: EditorUndoRedoManager): - _undo_redo_manager = ur - - -func set_editor_file_system(efs: EditorFileSystem): - _editor_file_system = efs - - -func set_texture_set(texture_set: HTerrainTextureSet): - if _texture_set == texture_set: - # TODO What if the set was actually modified since? - return - _texture_set = texture_set - - _slots_data.clear() - - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - var slots_count = _texture_set.get_slots_count() - - for slot_index in slots_count: - var slot := HT_TextureSetImportEditorSlot.new() - - for type in HTerrainTextureSet.TYPE_COUNT: - var texture = _texture_set.get_texture(slot_index, type) - - if texture == null or texture.resource_path == "": - continue - - if not texture.resource_path.ends_with(".packed_tex"): - continue - - var import_data := _parse_json_file(texture.resource_path) - if import_data.is_empty() or not import_data.has("src"): - continue - - var src_types = HTerrainTextureSet.get_src_types_from_type(type) - - var src_data = import_data["src"] - if src_data.has("rgb"): - slot.texture_paths[src_types[0]] = src_data["rgb"] - if src_data.has("a"): - slot.texture_paths[src_types[1]] = src_data["a"] - - _slots_data.append(slot) - - else: - var slots_count := _texture_set.get_slots_count() - - for type in HTerrainTextureSet.TYPE_COUNT: - var texture_array := _texture_set.get_texture_array(type) - - if texture_array == null or texture_array.resource_path == "": - continue - - if not texture_array.resource_path.ends_with(".packed_texarr"): - continue - - var import_data := _parse_json_file(texture_array.resource_path) - if import_data.is_empty() or not import_data.has("layers"): - continue - - var layers_data = import_data["layers"] - - for slot_index in len(layers_data): - var src_data = layers_data[slot_index] - - var src_types = HTerrainTextureSet.get_src_types_from_type(type) - - while slot_index >= len(_slots_data): - var slot = HT_TextureSetImportEditorSlot.new() - _slots_data.append(slot) - - var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] - - if src_data.has("rgb"): - slot.texture_paths[src_types[0]] = src_data["rgb"] - if src_data.has("a"): - slot.texture_paths[src_types[1]] = src_data["a"] - - # TODO If the set doesn't have a file, use terrain path by default? - if texture_set.resource_path != "": - var dir = texture_set.resource_path.get_base_dir() - _import_directory_line_edit.text = dir - - _update_ui_from_data() - - -func _parse_json_file(fpath: String) -> Dictionary: - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - _logger.error("Could not load {0}: {1}".format([fpath, HT_Errors.get_message(err)])) - return {} - - var json_text := f.get_as_text() - var json := JSON.new() - var json_err := json.parse(json_text) - if json_err != OK: - _logger.error("Failed to parse {0}: {1}".format([fpath, json.get_error_message()])) - return {} - - return json.data - - -func _update_ui_from_data(): - var prev_selected_items := _slots_list.get_selected_items() - - _slots_list.clear() - - for slot_index in len(_slots_data): - _slots_list.add_item("Texture {0}".format([slot_index])) - - _resolution_spinbox.value = _import_settings.resolution - _mipmaps_checkbox.button_pressed = _import_settings.mipmaps - _set_selected_id(_compression_selector, _import_settings.compression) - _set_selected_id(_import_mode_selector, _import_mode) - - var has_slots : bool = _slots_list.get_item_count() > 0 - - for ed in _texture_editors: - ed.set_enabled(has_slots) - _normalmap_flip_checkbox.disabled = not has_slots - - if has_slots: - if len(prev_selected_items) > 0: - var i : int = prev_selected_items[0] - if i >= _slots_list.get_item_count(): - i = _slots_list.get_item_count() - 1 - _select_slot(i) - else: - _select_slot(0) - else: - for type in HTerrainTextureSet.SRC_TYPE_COUNT: - _set_ui_slot_texture_from_path("", type) - - var max_slots := HTerrainTextureSet.get_max_slots_for_mode(_import_mode) - _add_slot_button.disabled = (len(_slots_data) >= max_slots) - _remove_slot_button.disabled = (len(_slots_data) == 0) - - -static func _set_selected_id(ob: OptionButton, id: int): - for i in ob.get_item_count(): - if ob.get_item_id(i) == id: - ob.selected = i - break - - -func _select_slot(slot_index: int): - assert(slot_index >= 0) - assert(slot_index < len(_slots_data)) - var slot = _slots_data[slot_index] - - for type in HTerrainTextureSet.SRC_TYPE_COUNT: - var im_path : String = slot.texture_paths[type] - _set_ui_slot_texture_from_path(im_path, type) - - _slots_list.select(slot_index) - - _normalmap_flip_checkbox.button_pressed = slot.flip_normalmap_y - _normalmap_material.set_shader_parameter("u_flip_y", slot.flip_normalmap_y) - - -func _set_ui_slot_texture_from_path(im_path: String, type: int): - var ed = _texture_editors[type] - - if im_path == "": - ed.set_texture(null) - ed.set_texture_tooltip("") - return - - var im : Image - - if im_path.begins_with("#") and im_path.find(".") == -1: - # The path is actually a preset for a uniform color. - # This is a feature of packed texture descriptor files. - # Make a small placeholder image. - var color := Color(im_path) - im = Image.create(4, 4, false, Image.FORMAT_RGBA8) - im.fill(color) - - else: - # Regular path - im = Image.new() - var err := im.load(im_path) - if err != OK: - _logger.error(str("Unable to load image from ", im_path)) - # TODO Different icon for images that can't load? - ed.set_texture(null) - ed.set_texture_tooltip("") - return - - var tex := ImageTexture.create_from_image(im) - ed.set_texture(tex) - ed.set_texture_tooltip(im_path) - - -func _set_source_image(fpath: String, type: int): - _set_ui_slot_texture_from_path(fpath, type) - - var slot_index : int = _slots_list.get_selected_items()[0] - #var prev_path = _texture_set.get_source_image_path(slot_index, type) - - var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] - slot.texture_paths[type] = fpath - - -func _set_import_property(key: String, value): - var prev_value = _import_settings[key] - # This is needed, notably because CheckBox emits a signal too when we set it from code... - if prev_value == value: - return - - _import_settings[key] = value - - -func _on_texture_load_pressed(type: int): - _load_texture_type = type - _load_texture_dialog.popup_centered_ratio() - - -func _on_LoadTextureDialog_file_selected(fpath: String): - _set_source_image(fpath, _load_texture_type) - - if _load_texture_type == HTerrainTextureSet.SRC_TYPE_ALBEDO: - _smart_pick_files(fpath) - - -# Attempts to load source images of other types by looking at how the albedo file was named -func _smart_pick_files(albedo_fpath: String): - var albedo_words = _smart_pick_file_keywords[HTerrainTextureSet.SRC_TYPE_ALBEDO] - - var albedo_fname := albedo_fpath.get_file() - var albedo_fname_lower = albedo_fname.to_lower() - var fname_pattern = "" - - for albedo_word in albedo_words: - var i = albedo_fname_lower.find(albedo_word, 0) - if i != -1: - fname_pattern = \ - albedo_fname.substr(0, i) + "{0}" + albedo_fname.substr(i + len(albedo_word)) - break - - if fname_pattern == "": - return - - var dirpath := albedo_fpath.get_base_dir() - var fnames := _get_files_in_directory(dirpath, _logger) - - var types := [ - HTerrainTextureSet.SRC_TYPE_BUMP, - HTerrainTextureSet.SRC_TYPE_NORMAL, - HTerrainTextureSet.SRC_TYPE_ROUGHNESS - ] - - var slot_index : int = _slots_list.get_selected_items()[0] - - for type in types: - var slot = _slots_data[slot_index] - if slot.texture_paths[type] != "": - # Already set, don't overwrite unwantedly - continue - - var keywords = _smart_pick_file_keywords[type] - - for key in keywords: - var expected_fname = fname_pattern.format([key]) - - var found := false - - for i in len(fnames): - var fname : String = fnames[i] - - # TODO We should probably ignore extensions? - if fname.to_lower() == expected_fname.to_lower(): - var fpath = dirpath.path_join(fname) - _set_source_image(fpath, type) - found = true - break - - if found: - break - - -static func _get_files_in_directory(dirpath: String, logger) -> Array: - var dir := DirAccess.open(dirpath) - var err := DirAccess.get_open_error() - if err != OK: - logger.error("Could not open directory {0}: {1}" \ - .format([dirpath, HT_Errors.get_message(err)])) - return [] - - dir.include_hidden = false - dir.include_navigational = false - - err = dir.list_dir_begin() - if err != OK: - logger.error("Could not probe directory {0}: {1}" \ - .format([dirpath, HT_Errors.get_message(err)])) - return [] - - var files := [] - var fname := dir.get_next() - while fname != "": - if not dir.current_is_dir(): - files.append(fname) - fname = dir.get_next() - - return files - - -func _on_texture_clear_pressed(type: int): - _set_source_image("", type) - - -func _on_SlotsList_item_selected(index: int): - _select_slot(index) - - -func _on_ImportModeSelector_item_selected(index: int): - var mode : int = _import_mode_selector.get_item_id(index) - if mode != _import_mode: - #_set_import_property("mode", mode) - _import_mode = mode - _update_ui_from_data() - - -func _on_CompressionSelector_item_selected(index: int): - var compression : int = _compression_selector.get_item_id(index) - _set_import_property("compression", compression) - - -func _on_MipmapsCheckbox_toggled(button_pressed: bool): - _set_import_property("mipmaps", button_pressed) - - -func _on_ResolutionSpinBox_value_changed(value): - _set_import_property("resolution", int(value)) - - -func _on_TextureArrayPrefixLineEdit_text_changed(new_text: String): - _set_import_property("output_prefix", new_text) - - -func _on_AddSlotButton_pressed(): - var i := len(_slots_data) - _slots_data.append(HT_TextureSetImportEditorSlot.new()) - _update_ui_from_data() - _select_slot(i) - - -func _on_RemoveSlotButton_pressed(): - if _slots_list.get_item_count() == 0: - return - var selected_item = _slots_list.get_selected_items()[0] - _delete_confirmation_popup.title = "Delete slot {0}".format([selected_item]) - _delete_confirmation_popup.dialog_text = "Delete import slot {0}?".format([selected_item]) - _delete_confirmation_popup.popup_centered() - - -func _on_delete_confirmation_popup_confirmed(): - var selected_item : int = _slots_list.get_selected_items()[0] - _slots_data.remove_at(selected_item) - _update_ui_from_data() - - -func _on_CancelButton_pressed(): - hide() - - -func _on_BrowseImportDirectory_pressed(): - _open_dir_dialog.popup_centered_ratio() - - -func _on_ImportDirectoryLineEdit_text_changed(new_text: String): - pass - - -func _on_OpenDirDialog_dir_selected(dir_path: String): - _import_directory_line_edit.text = dir_path - - -func _show_error(message: String): - _error_popup.dialog_text = message - _error_popup.popup_centered() - - -func _on_NormalMapFlipY_toggled(button_pressed: bool): - var slot_index : int = _slots_list.get_selected_items()[0] - var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] - slot.flip_normalmap_y = button_pressed - _normalmap_material.set_shader_parameter("u_flip_y", slot.flip_normalmap_y) - - -# class ButtonDisabler: -# var _button : Button - -# func _init(b: Button): -# _button = b -# _button.disabled = true - -# func _notification(what: int): -# if what == NOTIFICATION_PREDELETE: -# _button.disabled = false - - -func _get_undo_redo_for_texture_set() -> UndoRedo: - return _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_texture_set)) - - -func _on_ImportButton_pressed(): - if _texture_set == null: - _show_error("No HTerrainTextureSet selected.") - return - - var import_dir := _import_directory_line_edit.text.strip_edges() - - var prefix := "" - if _texture_set.resource_path != "": - prefix = _texture_set.resource_path.get_file().get_basename() + "_" - - var files_data_result : HT_Result - if _import_mode == HTerrainTextureSet.MODE_TEXTURES: - files_data_result = _generate_packed_images(import_dir, prefix) - else: - files_data_result = _generate_packed_texarray_images(import_dir, prefix) - - if not files_data_result.success: - _show_error(files_data_result.get_message()) - return - - var files_data : Array = files_data_result.value - - if len(files_data) == 0: - _show_error("There are no files to save.\nYou must setup at least one slot of textures.") - return - - for fd in files_data: - var dir_path : String = fd.path.get_base_dir() - if not DirAccess.dir_exists_absolute(dir_path): - _show_error("The directory {0} could not be found.".format([dir_path])) - return - - if _WRITE_IMPORT_FILES: - for fd in files_data: - var import_fpath = fd.path + ".import" - if not HT_Util.write_import_file(fd.import_file_data, import_fpath, _logger): - _show_error("Failed to write file {0}: {1}".format([import_fpath])) - return - - if _editor_file_system == null: - _show_error("EditorFileSystem is not setup, can't trigger import system.") - return - - # ______ - # .-" "-. - # / \ - # _ | | _ - # ( \ |, .-. .-. ,| / ) - # > "=._ | )(__/ \__)( | _.=" < - # (_/"=._"=._ |/ /\ \| _.="_.="\_) - # "=._ (_ ^^ _)"_.=" - # "=\__|IIIIII|__/=" - # _.="| \IIIIII/ |"=._ - # _ _.="_.="\ /"=._"=._ _ - # ( \_.="_.=" `--------` "=._"=._/ ) - # > _.=" "=._ < - # (_/ \_) - # - # TODO What I need here is a way to trigger the import of specific files! - # It exists, but is not exposed, so I have to rely on a VERY fragile and hacky use of scan()... - # I'm not even sure it works tbh. It's terrible. - # See https://github.com/godotengine/godot-proposals/issues/1615 - _editor_file_system.scan() - while _editor_file_system.is_scanning(): - _logger.debug("Waiting for scan to complete...") - await get_tree().process_frame - if not is_inside_tree(): - # oops? - return - _logger.debug("Scanning complete") - # Looks like import takes place AFTER scanning, so let's yield some more... - for fd in len(files_data) * 2: - _logger.debug("Yielding some more") - await get_tree().process_frame - - var failed_resource_paths := [] - - # Using UndoRedo is mandatory for Godot to consider the resource as modified... - # ...yet if files get deleted, that won't be undoable anyways, but whatever :shrug: - var ur := _get_undo_redo_for_texture_set() - - # Check imported textures - if _import_mode == HTerrainTextureSet.MODE_TEXTURES: - for fd in files_data: - var texture : Texture2D = load(fd.path) - if texture == null: - failed_resource_paths.append(fd.path) - continue - fd.texture = texture - - else: - for fd in files_data: - var texture_array : TextureLayered = load(fd.path) - if texture_array == null: - failed_resource_paths.append(fd.path) - continue - fd.texture_array = texture_array - - if len(failed_resource_paths) > 0: - var failed_list := "\n".join(PackedStringArray(failed_resource_paths)) - _show_error("Some resources failed to load:\n" + failed_list) - return - - # All is OK, commit action to modify the texture set with imported textures - - if _import_mode == HTerrainTextureSet.MODE_TEXTURES: - ur.create_action("HTerrainTextureSet: import textures") - - HT_TextureSetEditor.backup_for_undo(_texture_set, ur) - - ur.add_do_method(_texture_set.clear) - ur.add_do_method(_texture_set.set_mode.bind(_import_mode)) - - for i in len(_slots_data): - ur.add_do_method(_texture_set.insert_slot.bind(-1)) - for fd in files_data: - ur.add_do_method(_texture_set.set_texture.bind(fd.slot_index, fd.type, fd.texture)) - - else: - ur.create_action("HTerrainTextureSet: import texture arrays") - - HT_TextureSetEditor.backup_for_undo(_texture_set, ur) - - ur.add_do_method(_texture_set.clear) - ur.add_do_method(_texture_set.set_mode.bind(_import_mode)) - - for fd in files_data: - ur.add_do_method(_texture_set.set_texture_array.bind(fd.type, fd.texture_array)) - - ur.commit_action() - - _logger.debug("Done importing") - - _info_popup.dialog_text = "Importing complete!" - _info_popup.popup_centered() - - import_finished.emit() - - -class HT_PackedImageInfo: - var path := "" # Where the packed image is saved - var slot_index : int # Slot in texture set, when using individual textures - var type : int # 0:Albedo+Bump, 1:Normal+Roughness - var import_file_data := {} # Data to write into the .import file (when enabled...) - var image : Image - var is_default := false - var texture : Texture2D - var texture_array : TextureLayered - - -# Shared code between the two import modes -func _generate_packed_images2() -> HT_Result: - var resolution : int = _import_settings.resolution - var images_infos := [] - - for type in HTerrainTextureSet.TYPE_COUNT: - var src_types := HTerrainTextureSet.get_src_types_from_type(type) - - for slot_index in len(_slots_data): - var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] - - # Albedo or Normal - var src0 : String = slot.texture_paths[src_types[0]] - # Bump or Roughness - var src1 : String = slot.texture_paths[src_types[1]] - - if src0 == "": - if src_types[0] == HTerrainTextureSet.SRC_TYPE_ALBEDO: - return HT_Result.new(false, - "Albedo texture is missing in slot {0}".format([slot_index])) - - var is_default := (src0 == "" and src1 == "") - - if src0 == "": - src0 = HTerrainTextureSet.get_source_texture_default_color_code(src_types[0]) - if src1 == "": - src1 = HTerrainTextureSet.get_source_texture_default_color_code(src_types[1]) - - var pack_sources := { - "rgb": src0, - "a": src1 - } - - if HTerrainTextureSet.SRC_TYPE_NORMAL in src_types and slot.flip_normalmap_y: - pack_sources["normalmap_flip_y"] = true - - var packed_image_result := HT_PackedTextureUtil.generate_image( - pack_sources, resolution, _logger) - if not packed_image_result.success: - return packed_image_result - var packed_image : Image = packed_image_result.value - - var fd := HT_PackedImageInfo.new() - fd.slot_index = slot_index - fd.type = type - fd.image = packed_image - fd.is_default = is_default - - images_infos.append(fd) - - return HT_Result.new(true).with_value(images_infos) - - -func _generate_packed_images(import_dir: String, prefix: String) -> HT_Result: - var images_infos_result := _generate_packed_images2() - if not images_infos_result.success: - return images_infos_result - var images_infos : Array = images_infos_result.value - - for info_index in len(images_infos): - var info : HT_PackedImageInfo = images_infos[info_index] - - var type_name := HTerrainTextureSet.get_texture_type_name(info.type) - var fpath := import_dir.path_join( - str(prefix, "slot", info.slot_index, "_", type_name, ".png")) - - var err := info.image.save_png(fpath) - if err != OK: - return HT_Result.new(false, - "Could not save image {0}, {1}".format([fpath, HT_Errors.get_message(err)])) - - info.path = fpath - info.import_file_data = { - "remap": { - "importer": "texture", - "type": "CompressedTexture2D" - }, - "deps": { - "source_file": fpath - }, - "params": { - "compress/mode": ResourceImporterTexture_Unexposed.COMPRESS_VRAM_COMPRESSED, - "compress/high_quality": false, - "compress/lossy_quality": 0.7, - "mipmaps/generate": true, - "mipmaps/limit": -1, - "roughness/mode": ResourceImporterTexture_Unexposed.ROUGHNESS_DISABLED, - "process/fix_alpha_border": false - } - } - - return HT_Result.new(true).with_value(images_infos) - - -static func _assemble_texarray_images(images: Array[Image], resolution: Vector2i) -> Image: - # Godot expects some kind of grid. Let's be lazy and do a grid with only one row. - var atlas := Image.create(resolution.x * len(images), resolution.y, false, Image.FORMAT_RGBA8) - for index in len(images): - var image : Image = images[index] - if image.get_size() != resolution: - image.resize(resolution.x, resolution.y, Image.INTERPOLATE_BILINEAR) - atlas.blit_rect(image, - Rect2i(0, 0, image.get_width(), image.get_height()), - Vector2i(index * resolution.x, 0)) - return atlas - - -func _generate_packed_texarray_images(import_dir: String, prefix: String) -> HT_Result: - var images_infos_result := _generate_packed_images2() - if not images_infos_result.success: - return images_infos_result - var individual_images_infos : Array = images_infos_result.value - - var resolution : int = _import_settings.resolution - - var texarray_images_infos := [] - var slot_count := len(_slots_data) - - for type in HTerrainTextureSet.TYPE_COUNT: - var texarray_images : Array[Image] = [] - texarray_images.resize(slot_count) - - var fully_defaulted_slots := 0 - - for i in slot_count: - var info : HT_PackedImageInfo = individual_images_infos[type * slot_count + i] - if info.type == type: - texarray_images[i] = info.image - if info.is_default: - fully_defaulted_slots += 1 - - if fully_defaulted_slots == len(texarray_images): - # No need to generate this file at all - continue - - var texarray_image := _assemble_texarray_images(texarray_images, - Vector2i(resolution, resolution)) - - var type_name := HTerrainTextureSet.get_texture_type_name(type) - var fpath := import_dir.path_join(str(prefix, type_name, "_array.png")) - - var err := texarray_image.save_png(fpath) - if err != OK: - return HT_Result.new(false, - "Could not save image {0}, {1}".format([fpath, HT_Errors.get_message(err)])) - - var texarray_image_info := HT_PackedImageInfo.new() - texarray_image_info.type = type - texarray_image_info.path = fpath - texarray_image_info.import_file_data = { - "remap": { - "importer": "2d_array_texture", - "type": "CompressedTexture2DArray" - }, - "deps": { - "source_file": fpath - }, - "params": { - "compress/mode": ResourceImporterTextureLayered_Unexposed.COMPRESS_VRAM_COMPRESSED, - "compress/high_quality": false, - "compress/lossy_quality": 0.7, - "mipmaps/generate": true, - "mipmaps/limit": -1, - "process/fix_alpha_border": false, - "slices/horizontal": len(texarray_images), - "slices/vertical": 1 - } - } - - texarray_images_infos.append(texarray_image_info) - - return HT_Result.new(true).with_value(texarray_images_infos) - diff --git a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.tscn b/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.tscn deleted file mode 100644 index 549f7a1..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.tscn +++ /dev/null @@ -1,218 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://3indvrto5vd5"] - -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="1"] -[ext_resource type="PackedScene" uid="uid://dqgaomu3tr1ym" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn" id="3"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd" id="4"] - -[node name="TextureSetImportEditor" type="AcceptDialog"] -title = "Texture Set Import Tool" -size = Vector2i(652, 623) -min_size = Vector2i(652, 480) -script = ExtResource("4") - -[node name="Import" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="HS" type="HSplitContainer" parent="Import"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VB" type="VBoxContainer" parent="Import/HS"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Label" type="Label" parent="Import/HS/VB"] -visible = false -layout_mode = 2 -text = "Slots" - -[node name="SlotsList" type="ItemList" parent="Import/HS/VB"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -size_flags_vertical = 3 -item_count = 7 -item_0/text = "Item 0" -item_1/text = "Item 1" -item_2/text = "Item 2" -item_3/text = "Item 3" -item_4/text = "Item 4" -item_5/text = "Item 5" -item_6/text = "Item 6" - -[node name="HB" type="HBoxContainer" parent="Import/HS/VB"] -layout_mode = 2 - -[node name="AddSlotButton" type="Button" parent="Import/HS/VB/HB"] -layout_mode = 2 -text = "+" - -[node name="Control" type="Control" parent="Import/HS/VB/HB"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="RemoveSlotButton" type="Button" parent="Import/HS/VB/HB"] -layout_mode = 2 -text = "-" - -[node name="VB2" type="VBoxContainer" parent="Import/HS"] -layout_mode = 2 - -[node name="Label" type="Label" parent="Import/HS/VB2"] -visible = false -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="Import/HS/VB2"] -layout_mode = 2 - -[node name="Albedo" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="Bump" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="Normal" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="NormalMapFlipY" type="CheckBox" parent="Import/HS/VB2/HB/Normal"] -layout_mode = 2 -text = "Flip Y" - -[node name="Roughness" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="Control" type="Control" parent="Import/HS/VB2"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 - -[node name="Control2" type="Control" parent="Import/HS/VB2"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Label3" type="Label" parent="Import/HS/VB2"] -modulate = Color(0.564706, 0.564706, 0.564706, 1) -layout_mode = 2 -text = "These images should remain accessible for import to work. -Tip: you can place them in a folder with a `.gdignore` file, so they won't take space in your exported game." -autowrap_mode = 2 - -[node name="Spacer3" type="Control" parent="Import"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="Import"] -layout_mode = 2 - -[node name="GC" type="GridContainer" parent="Import"] -layout_mode = 2 -columns = 4 - -[node name="Label2" type="Label" parent="Import/GC"] -layout_mode = 2 -text = "Import mode: " - -[node name="ImportModeSelector" type="OptionButton" parent="Import/GC"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="MipmapsCheckbox" type="CheckBox" parent="Import/GC"] -visible = false -layout_mode = 2 -text = "Mipmaps" - -[node name="Spacer2" type="Control" parent="Import/GC"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Label" type="Label" parent="Import/GC"] -visible = false -layout_mode = 2 -text = "Compression:" - -[node name="CompressionSelector" type="OptionButton" parent="Import/GC"] -visible = false -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="FilterCheckBox" type="CheckBox" parent="Import/GC"] -visible = false -layout_mode = 2 -text = "Filter" - -[node name="Spacer" type="Control" parent="Import/GC"] -layout_mode = 2 - -[node name="Label3" type="Label" parent="Import/GC"] -layout_mode = 2 -text = "Resolution:" - -[node name="ResolutionSpinBox" type="SpinBox" parent="Import/GC"] -layout_mode = 2 -min_value = 1.0 -max_value = 4096.0 -value = 1.0 - -[node name="HB2" type="HBoxContainer" parent="Import"] -layout_mode = 2 - -[node name="Label2" type="Label" parent="Import/HB2"] -layout_mode = 2 -text = "Import directory" - -[node name="ImportDirectoryLineEdit" type="LineEdit" parent="Import/HB2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="BrowseImportDirectory" type="Button" parent="Import/HB2"] -layout_mode = 2 -text = "..." - -[node name="Spacer" type="Control" parent="Import"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="Import"] -layout_mode = 2 -alignment = 1 - -[node name="ImportButton" type="Button" parent="Import/HB"] -layout_mode = 2 -text = "Import to TextureSet" - -[node name="CancelButton" type="Button" parent="Import/HB"] -layout_mode = 2 -text = "Close" - -[node name="Spacer2" type="Control" parent="Import"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="DialogFitter" parent="." instance=ExtResource("1")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 644.0 -offset_bottom = 605.0 - -[connection signal="item_selected" from="Import/HS/VB/SlotsList" to="." method="_on_SlotsList_item_selected"] -[connection signal="pressed" from="Import/HS/VB/HB/AddSlotButton" to="." method="_on_AddSlotButton_pressed"] -[connection signal="pressed" from="Import/HS/VB/HB/RemoveSlotButton" to="." method="_on_RemoveSlotButton_pressed"] -[connection signal="toggled" from="Import/HS/VB2/HB/Normal/NormalMapFlipY" to="." method="_on_NormalMapFlipY_toggled"] -[connection signal="item_selected" from="Import/GC/ImportModeSelector" to="." method="_on_ImportModeSelector_item_selected"] -[connection signal="toggled" from="Import/GC/MipmapsCheckbox" to="." method="_on_MipmapsCheckbox_toggled"] -[connection signal="item_selected" from="Import/GC/CompressionSelector" to="." method="_on_CompressionSelector_item_selected"] -[connection signal="toggled" from="Import/GC/FilterCheckBox" to="." method="_on_FilterCheckBox_toggled"] -[connection signal="value_changed" from="Import/GC/ResolutionSpinBox" to="." method="_on_ResolutionSpinBox_value_changed"] -[connection signal="text_changed" from="Import/HB2/ImportDirectoryLineEdit" to="." method="_on_ImportDirectoryLineEdit_text_changed"] -[connection signal="pressed" from="Import/HB2/BrowseImportDirectory" to="." method="_on_BrowseImportDirectory_pressed"] -[connection signal="pressed" from="Import/HB/ImportButton" to="." method="_on_ImportButton_pressed"] -[connection signal="pressed" from="Import/HB/CancelButton" to="." method="_on_CancelButton_pressed"] - -[editable path="Import/HS/VB2/HB/Normal"] diff --git a/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd b/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd deleted file mode 100644 index e3e337f..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd +++ /dev/null @@ -1,134 +0,0 @@ -@tool -extends Control - -const HTerrain = preload("../../hterrain.gd") -const HTerrainTextureSet = preload("../../hterrain_texture_set.gd") -const HT_TextureList = preload("./texture_list.gd") -const HT_Logger = preload("../../util/logger.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const EMPTY_ICON_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal texture_selected(index) -signal edit_pressed(index) -signal import_pressed - -@onready var _textures_list: HT_TextureList = $TextureList -@onready var _buttons_container : HBoxContainer = $HBoxContainer - -var _terrain : HTerrain = null -var _texture_set : HTerrainTextureSet = null - -var _texture_list_need_update := false -var _empty_icon : Texture2D - -var _logger = HT_Logger.get_for(self) - - -func _ready(): - _empty_icon = load(EMPTY_ICON_TEXTURE_PATH) - if _empty_icon == null: - _logger.error(str("Failed to load empty icon ", EMPTY_ICON_TEXTURE_PATH)) - - # Default amount, will be updated when a terrain is assigned - _textures_list.clear() - for i in range(4): - _textures_list.add_item(str(i), _empty_icon) - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -static func _get_slot_count(terrain: HTerrain) -> int: - var texture_set = terrain.get_texture_set() - if texture_set == null: - return 0 - return texture_set.get_slots_count() - - -func _process(delta: float): - var texture_set = null - if _terrain != null: - texture_set = _terrain.get_texture_set() - - if _texture_set != texture_set: - if _texture_set != null: - _texture_set.changed.disconnect(_on_texture_set_changed) - - _texture_set = texture_set - - if _texture_set != null: - _texture_set.changed.connect(_on_texture_set_changed) - - _update_texture_list() - - if _texture_list_need_update: - _update_texture_list() - _texture_list_need_update = false - - -func _on_texture_set_changed(): - _texture_list_need_update = true - - -func _update_texture_list(): - _textures_list.clear() - - if _terrain == null: - _set_buttons_active(false) - return - var texture_set := _terrain.get_texture_set() - if texture_set == null: - _set_buttons_active(false) - return - _set_buttons_active(true) - - var slots_count := texture_set.get_slots_count() - - match texture_set.get_mode(): - HTerrainTextureSet.MODE_TEXTURES: - for slot_index in slots_count: - var texture := texture_set.get_texture( - slot_index, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - var hint := _get_slot_hint_name(slot_index, _terrain.get_shader_type()) - if texture == null: - texture = _empty_icon - _textures_list.add_item(hint, texture) - - HTerrainTextureSet.MODE_TEXTURE_ARRAYS: - var texture_array = texture_set.get_texture_array(HTerrainTextureSet.TYPE_ALBEDO_BUMP) - for slot_index in slots_count: - var hint := _get_slot_hint_name(slot_index, _terrain.get_shader_type()) - _textures_list.add_item(hint, texture_array, slot_index) - - -func _set_buttons_active(active: bool): - for i in _buttons_container.get_child_count(): - var child = _buttons_container.get_child(i) - if child is Button: - child.disabled = not active - - -static func _get_slot_hint_name(i: int, stype: String) -> String: - if i == 3 and (stype == HTerrain.SHADER_CLASSIC4 or stype == HTerrain.SHADER_CLASSIC4_LITE): - return "cliff" - return str(i) - - -func _on_TextureList_item_selected(index: int): - texture_selected.emit(index) - - -func _on_TextureList_item_activated(index: int): - edit_pressed.emit(index) - - -func _on_EditButton_pressed(): - var selected_slot := _textures_list.get_selected_item() - if selected_slot == -1: - selected_slot = 0 - edit_pressed.emit(selected_slot) - - -func _on_ImportButton_pressed(): - import_pressed.emit() diff --git a/addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn b/addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn deleted file mode 100644 index 885f344..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn +++ /dev/null @@ -1,48 +0,0 @@ -[gd_scene load_steps=3 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/texture_editor.gd" type="Script" id=1] -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/texture_list.tscn" type="PackedScene" id=2] - -[node name="TextureEditor" type="Control"] -offset_right = 352.0 -offset_bottom = 104.0 -custom_minimum_size = Vector2( 100, 0 ) -size_flags_horizontal = 3 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="TextureList" parent="." instance=ExtResource( 2 )] -offset_bottom = -26.0 - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -24.0 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="EditButton" type="Button" parent="HBoxContainer"] -offset_right = 48.0 -offset_bottom = 24.0 -text = "Edit..." - -[node name="ImportButton" type="Button" parent="HBoxContainer"] -offset_left = 52.0 -offset_right = 120.0 -offset_bottom = 24.0 -text = "Import..." - -[node name="Label" type="Label" parent="HBoxContainer"] -offset_left = 124.0 -offset_top = 5.0 -offset_right = 179.0 -offset_bottom = 19.0 -text = "Textures" -[connection signal="item_activated" from="TextureList" to="." method="_on_TextureList_item_activated"] -[connection signal="item_selected" from="TextureList" to="." method="_on_TextureList_item_selected"] -[connection signal="pressed" from="HBoxContainer/EditButton" to="." method="_on_EditButton_pressed"] -[connection signal="pressed" from="HBoxContainer/ImportButton" to="." method="_on_ImportButton_pressed"] diff --git a/addons/zylann.hterrain/tools/texture_editor/texture_list.gd b/addons/zylann.hterrain/tools/texture_editor/texture_list.gd deleted file mode 100644 index 7391f85..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/texture_list.gd +++ /dev/null @@ -1,79 +0,0 @@ - -# I needed a custom container for this because textures edited by this plugin are often -# unfit to display in a GUI, they need to go through a shader (either discarding alpha, -# or picking layers of a TextureArray). Unfortunately, ItemList does not have custom item drawing, -# and items cannot have individual shaders. -# I could create new textures just for that but it would be expensive. - -@tool -extends ScrollContainer - -const HT_TextureListItemScene = preload("./texture_list_item.tscn") -const HT_TextureListItem = preload("./texture_list_item.gd") - -signal item_selected(index) -signal item_activated(index) - -@onready var _container : Container = $Container - - -var _selected_item := -1 - - -# TEST -#func _ready(): -# add_item("First", load("res://addons/zylann.hterrain_demo/textures/ground/bricks_albedo_bump.png"), 0) -# add_item("Second", load("res://addons/zylann.hterrain_demo/textures/ground/grass_albedo_bump.png"), 0) -# add_item("Third", load("res://addons/zylann.hterrain_demo/textures/ground/leaves_albedo_bump.png"), 0) -# add_item("Fourth", load("res://addons/zylann.hterrain_demo/textures/ground/sand_albedo_bump.png"), 0) -# var texture_array = load("res://tests/texarray/textures/array_albedo_atlas.png") -# add_item("Ninth", texture_array, 2) -# add_item("Sixth", texture_array, 3) - - -# Note: the texture can be a TextureArray, which does not inherit Texture -func add_item(text: String, texture: Texture, texture_layer: int = 0): - var item : HT_TextureListItem = HT_TextureListItemScene.instantiate() - _container.add_child(item) - item.set_text(text) - item.set_texture(texture, texture_layer) - - -func get_item_count() -> int: - return _container.get_child_count() - - -func set_item_texture(index: int, tex: Texture, layer: int = 0): - var child : HT_TextureListItem = _container.get_child(index) - child.set_texture(tex, layer) - - -func get_selected_item() -> int: - return _selected_item - - -func clear(): - for i in _container.get_child_count(): - var child = _container.get_child(i) - if child is Control: - child.queue_free() - _selected_item = -1 - - -func _on_item_selected(item: HT_TextureListItem): - _selected_item = item.get_index() - for i in _container.get_child_count(): - var child = _container.get_child(i) - if child is HT_TextureListItem and child != item: - child.set_selected(false, false) - item_selected.emit(_selected_item) - - -func _on_item_activated(item: HT_TextureListItem): - item_activated.emit(item.get_index()) - - -func _draw(): - # TODO Draw same background as Panel - # Draw a background - draw_rect(get_rect(), Color(0,0,0,0.3)) diff --git a/addons/zylann.hterrain/tools/texture_editor/texture_list.tscn b/addons/zylann.hterrain/tools/texture_editor/texture_list.tscn deleted file mode 100644 index df5e1e2..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/texture_list.tscn +++ /dev/null @@ -1,20 +0,0 @@ -[gd_scene load_steps=3 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/texture_list.gd" type="Script" id=1] -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/flow_container.gd" type="Script" id=2] - -[node name="TextureList" type="ScrollContainer"] -anchor_right = 1.0 -anchor_bottom = 1.0 -scroll_horizontal_enabled = false -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Container" type="Container" parent="."] -offset_right = 800.0 -offset_bottom = 82.0 -custom_minimum_size = Vector2( 0, 82 ) -size_flags_horizontal = 3 -script = ExtResource( 2 ) diff --git a/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd b/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd deleted file mode 100644 index 098f349..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd +++ /dev/null @@ -1,72 +0,0 @@ -@tool -extends PanelContainer -# Had to use PanelContainer, because due to variable font sizes in the editor, -# the contents of the VBoxContainer can vary in size, and so in height. -# Which means the entire item can have variable size, not just because of DPI. -# In such cases, the hierarchy must be made of containers that grow based on their children. - -const HT_ColorMaterial = preload("./display_color_material.tres") -const HT_ColorSliceShader = preload("./display_color_slice.gdshader") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_DummyTexture = preload("../icons/empty.png") -const DUMMY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -@onready var _texture_rect : TextureRect = $VB/TextureRect -@onready var _label : Label = $VB/Label - - -var _selected := false - - -func set_text(text: String): - _label.text = text - - -func set_texture(texture: Texture, texture_layer: int): - if texture is TextureLayered: - var mat = _texture_rect.material - if mat == null or not (mat is ShaderMaterial): - mat = ShaderMaterial.new() - mat.shader = HT_ColorSliceShader - _texture_rect.material = mat - mat.set_shader_parameter("u_texture_array", texture) - mat.set_shader_parameter("u_index", texture_layer) - _texture_rect.texture = load(DUMMY_TEXTURE_PATH) - else: - _texture_rect.texture = texture - _texture_rect.material = HT_ColorMaterial - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - if event.button_index == MOUSE_BUTTON_LEFT: - grab_focus() - set_selected(true, true) - if event.double_click: - # Don't do this at home. - # I do it here because this script is very related to its container anyways. - get_parent().get_parent()._on_item_activated(self) - - -func set_selected(selected: bool, notify: bool): - if selected == _selected: - return - _selected = selected - queue_redraw() - if _selected: - _label.modulate = Color(0,0,0) - else: - _label.modulate = Color(1,1,1) - if notify: - get_parent().get_parent()._on_item_selected(self) - - -func _draw(): - var color : Color - if _selected: - color = get_theme_color("accent_color", "Editor") - else: - color = Color(0.0, 0.0, 0.0, 0.5) - # Draw background - draw_rect(Rect2(Vector2(), size), color) diff --git a/addons/zylann.hterrain/tools/texture_editor/texture_list_item.tscn b/addons/zylann.hterrain/tools/texture_editor/texture_list_item.tscn deleted file mode 100644 index 4340f55..0000000 --- a/addons/zylann.hterrain/tools/texture_editor/texture_list_item.tscn +++ /dev/null @@ -1,25 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://daugk4kdnx6vy"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd" id="2"] - -[node name="TextureListItem" type="PanelContainer"] -custom_minimum_size = Vector2(64, 80) -offset_right = 64.0 -offset_bottom = 80.0 -focus_mode = 1 -script = ExtResource("2") - -[node name="VB" type="VBoxContainer" parent="."] -layout_mode = 2 -mouse_filter = 2 - -[node name="TextureRect" type="TextureRect" parent="VB"] -custom_minimum_size = Vector2(60, 60) -layout_mode = 2 -size_flags_vertical = 3 -mouse_filter = 2 -expand_mode = 1 - -[node name="Label" type="Label" parent="VB"] -layout_mode = 2 -text = "Texture" diff --git a/addons/zylann.hterrain/tools/util/dialog_fitter.gd b/addons/zylann.hterrain/tools/util/dialog_fitter.gd deleted file mode 100644 index 59bb194..0000000 --- a/addons/zylann.hterrain/tools/util/dialog_fitter.gd +++ /dev/null @@ -1,53 +0,0 @@ - -# If you make a container-based UI inside a WindowDialog, there is a chance it will overflow -# because WindowDialogs don't adjust by themselves. This happens when the user has a different -# font size than yours, and can cause controls to be unusable (like buttons at the bottom). -# This script adjusts the size of the parent WindowDialog based on the first Container it finds -# when the node becomes visible. - -@tool -# Needs to be a Control, otherwise we don't receive the notification... -extends Control - -const HT_Util = preload("../../util/util.gd") - - -func _notification(what: int): - if HT_Util.is_in_edited_scene(self): - return - if is_inside_tree() and what == Control.NOTIFICATION_VISIBILITY_CHANGED: - #print("Visible ", is_visible_in_tree(), ", ", visible) - call_deferred("_fit_to_contents") - - -func _fit_to_contents(): - var dialog : Window = get_parent() - for child in dialog.get_children(): - if child is Container: - var child_rect : Rect2 = child.get_global_rect() - var dialog_rect := Rect2(Vector2(), dialog.size) - #print("Dialog: ", dialog_rect, ", contents: ", child_rect, " ", child.get_path()) - if not dialog_rect.encloses(child_rect): - var margin : Vector2 = child.get_rect().position - #print("Fitting ", dialog.get_path(), " from ", dialog.rect_size, - # " to ", child_rect.size + margin * 2.0) - dialog.min_size = child_rect.size + margin * 2.0 - - -#func _process(delta): -# update() - -# DEBUG -#func _draw(): -# var self_global_pos = get_global_rect().position -# -# var dialog : Control = get_parent() -# var dialog_rect := dialog.get_global_rect() -# dialog_rect.position -= self_global_pos -# draw_rect(dialog_rect, Color(1,1,0), false) -# -# for child in dialog.get_children(): -# if child is Container: -# var child_rect : Rect2 = child.get_global_rect() -# child_rect.position -= self_global_pos -# draw_rect(child_rect, Color(1,1,0,0.1)) diff --git a/addons/zylann.hterrain/tools/util/dialog_fitter.tscn b/addons/zylann.hterrain/tools/util/dialog_fitter.tscn deleted file mode 100644 index 2e3b00c..0000000 --- a/addons/zylann.hterrain/tools/util/dialog_fitter.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/util/dialog_fitter.gd" type="Script" id=1] - -[node name="DialogFitter" type="Control"] -mouse_filter = 2 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} diff --git a/addons/zylann.hterrain/tools/util/editor_util.gd b/addons/zylann.hterrain/tools/util/editor_util.gd deleted file mode 100644 index a6d9eff..0000000 --- a/addons/zylann.hterrain/tools/util/editor_util.gd +++ /dev/null @@ -1,104 +0,0 @@ - -# Editor-specific utilities. -# This script cannot be loaded in an exported game. - -@tool - - -# This is normally an `EditorFileDialog`. I can't type-hint this one properly, -# because when I test UI in isolation, I can't use `EditorFileDialog`. -static func create_open_file_dialog() -> ConfirmationDialog: - var d - if Engine.is_editor_hint(): - # TODO Workaround bug when editor-only classes are created in source code, even if not run - # https://github.com/godotengine/godot/issues/73525 -# d = EditorFileDialog.new() - d = ClassDB.instantiate(&"EditorFileDialog") - d.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - d.access = EditorFileDialog.ACCESS_RESOURCES - else: - d = FileDialog.new() - d.file_mode = FileDialog.FILE_MODE_OPEN_FILE - d.access = FileDialog.ACCESS_RESOURCES - d.unresizable = false - return d - - -static func create_open_dir_dialog() -> ConfirmationDialog: - var d - if Engine.is_editor_hint(): - # TODO Workaround bug when editor-only classes are created in source code, even if not run - # https://github.com/godotengine/godot/issues/73525 -# d = EditorFileDialog.new() - d = ClassDB.instantiate(&"EditorFileDialog") - d.file_mode = EditorFileDialog.FILE_MODE_OPEN_DIR - d.access = EditorFileDialog.ACCESS_RESOURCES - else: - d = FileDialog.new() - d.file_mode = FileDialog.FILE_MODE_OPEN_DIR - d.access = FileDialog.ACCESS_RESOURCES - d.unresizable = false - return d - - -# If you want to open using Image.load() -static func create_open_image_dialog() -> ConfirmationDialog: - var d = create_open_file_dialog() - _add_image_filters(d) - return d - - -# If you want to open using load(), -# although it might still fail if the file is imported as Image... -static func create_open_texture_dialog() -> ConfirmationDialog: - var d = create_open_file_dialog() - _add_texture_filters(d) - return d - - -static func create_open_texture_array_dialog() -> ConfirmationDialog: - var d = create_open_file_dialog() - _add_texture_array_filters(d) - return d - -# TODO Post a proposal, we need a file dialog filtering on resource types, not on file extensions! - -static func _add_image_filters(file_dialog): - file_dialog.add_filter("*.png ; PNG files") - file_dialog.add_filter("*.jpg ; JPG files") - #file_dialog.add_filter("*.exr ; EXR files") - - -static func _add_texture_filters(file_dialog): - _add_image_filters(file_dialog) - # Godot - file_dialog.add_filter("*.ctex ; CompressedTexture files") - # Packed textures - file_dialog.add_filter("*.packed_tex ; HTerrainPackedTexture files") - - -static func _add_texture_array_filters(file_dialog): - _add_image_filters(file_dialog) - # Godot - file_dialog.add_filter("*.ctexarray ; TextureArray files") - # Packed textures - file_dialog.add_filter("*.packed_texarr ; HTerrainPackedTextureArray files") - - -# Tries to load a texture with the ResourceLoader, and if it fails, attempts -# to load it manually as an ImageTexture -static func load_texture(path: String, logger) -> Texture: - var tex : Texture = load(path) - if tex != null: - return tex - # This can unfortunately happen when the editor didn't import assets yet. - # See https://github.com/godotengine/godot/issues/17483 - logger.error(str("Failed to load texture ", path, ", attempting to load manually")) - var im := Image.new() - var err = im.load(path) - if err != OK: - logger.error(str("Failed to load image ", path)) - return null - var itex := ImageTexture.create_from_image(im) - return itex - diff --git a/addons/zylann.hterrain/tools/util/interval_slider.gd b/addons/zylann.hterrain/tools/util/interval_slider.gd deleted file mode 100644 index 481d08b..0000000 --- a/addons/zylann.hterrain/tools/util/interval_slider.gd +++ /dev/null @@ -1,197 +0,0 @@ - -# Slider with two handles representing an interval. - -@tool -extends Control - -const VALUE_LOW = 0 -const VALUE_HIGH = 1 -const VALUE_COUNT = 2 - -const FG_MARGIN = 1 - -signal changed - -var _min_value := 0.0 -var _max_value := 1.0 -var _values = [0.2, 0.6] -var _grabbing := false - - -func _get_property_list(): - return [ - { - "name": "min_value", - "type": TYPE_FLOAT, - "usage": PROPERTY_USAGE_EDITOR - }, - { - "name": "max_value", - "type": TYPE_FLOAT, - "usage": PROPERTY_USAGE_EDITOR - }, - { - "name": "range", - "type": TYPE_VECTOR2, - "usage": PROPERTY_USAGE_STORAGE - } - ] - - -func _get(key: StringName): - match key: - &"min_value": - return _min_value - &"max_value": - return _max_value - &"range": - return Vector2(_min_value, _max_value) - - -func _set(key: StringName, value): - match key: - &"min_value": - _min_value = min(value, _max_value) - queue_redraw() - &"max_value": - _max_value = max(value, _min_value) - queue_redraw() - &"range": - _min_value = value.x - _max_value = value.y - - -func set_values(low: float, high: float): - if low > high: - low = high - if high < low: - high = low - _values[VALUE_LOW] = low - _values[VALUE_HIGH] = high - queue_redraw() - - -func set_value(i: int, v: float, notify_change: bool): - var min_value = _min_value - var max_value = _max_value - - match i: - VALUE_LOW: - max_value = _values[VALUE_HIGH] - VALUE_HIGH: - min_value = _values[VALUE_LOW] - _: - assert(false) - - v = clampf(v, min_value, max_value) - if v != _values[i]: - _values[i] = v - queue_redraw() - if notify_change: - changed.emit() - - -func get_value(i: int) -> float: - return _values[i] - - -func get_low_value() -> float: - return _values[VALUE_LOW] - - -func get_high_value() -> float: - return _values[VALUE_HIGH] - - -func get_ratio(i: int) -> float: - return _value_to_ratio(_values[i]) - - -func get_low_ratio() -> float: - return get_ratio(VALUE_LOW) - - -func get_high_ratio() -> float: - return get_ratio(VALUE_HIGH) - - -func _ratio_to_value(r: float) -> float: - return r * (_max_value - _min_value) + _min_value - - -func _value_to_ratio(v: float) -> float: - if absf(_max_value - _min_value) < 0.001: - return 0.0 - return (v - _min_value) / (_max_value - _min_value) - - -func _get_closest_index(ratio: float) -> int: - var distance_low := absf(ratio - get_low_ratio()) - var distance_high := absf(ratio - get_high_ratio()) - if distance_low < distance_high: - return VALUE_LOW - return VALUE_HIGH - - -func _set_from_pixel(px: float): - var r := (px - FG_MARGIN) / (size.x - FG_MARGIN * 2.0) - var i := _get_closest_index(r) - var v := _ratio_to_value(r) - set_value(i, v, true) - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - if event.button_index == MOUSE_BUTTON_LEFT: - _grabbing = true - _set_from_pixel(event.position.x) - else: - if event.button_index == MOUSE_BUTTON_LEFT: - _grabbing = false - - elif event is InputEventMouseMotion: - if _grabbing: - _set_from_pixel(event.position.x) - - -func _draw(): - var grabber_width := 3 - var background_v_margin := 0 - var foreground_margin := FG_MARGIN - var grabber_color := Color(0.8, 0.8, 0.8) - var interval_color := Color(0.4,0.4,0.4) - var background_color := Color(0.1, 0.1, 0.1) - - var control_rect := Rect2(Vector2(), size) - - var bg_rect := Rect2( - control_rect.position.x, - control_rect.position.y + background_v_margin, - control_rect.size.x, - control_rect.size.y - 2 * background_v_margin) - draw_rect(bg_rect, background_color) - - var fg_rect := control_rect.grow(-foreground_margin) - - var low_ratio := get_low_ratio() - var high_ratio := get_high_ratio() - - var low_x := fg_rect.position.x + low_ratio * fg_rect.size.x - var high_x := fg_rect.position.x + high_ratio * fg_rect.size.x - - var interval_rect := Rect2( - low_x, fg_rect.position.y, high_x - low_x, fg_rect.size.y) - draw_rect(interval_rect, interval_color) - - low_x = fg_rect.position.x + low_ratio * (fg_rect.size.x - grabber_width) - high_x = fg_rect.position.x + high_ratio * (fg_rect.size.x - grabber_width) - - for x in [low_x, high_x]: - var grabber_rect := Rect2( - x, - fg_rect.position.y, - grabber_width, - fg_rect.size.y) - draw_rect(grabber_rect, grabber_color) - diff --git a/addons/zylann.hterrain/tools/util/resource_importer_texture.gd b/addons/zylann.hterrain/tools/util/resource_importer_texture.gd deleted file mode 100644 index b24f0e2..0000000 --- a/addons/zylann.hterrain/tools/util/resource_importer_texture.gd +++ /dev/null @@ -1,19 +0,0 @@ -@tool - -# Stuff not exposed by Godot for making .import files - -const COMPRESS_LOSSLESS = 0 -const COMPRESS_LOSSY = 1 -const COMPRESS_VRAM_COMPRESSED = 2 -const COMPRESS_VRAM_UNCOMPRESSED = 3 -const COMPRESS_BASIS_UNIVERSAL = 4 - -const ROUGHNESS_DETECT = 0 -const ROUGHNESS_DISABLED = 1 -# Godot internally subtracts 2 to magically obtain a `Image.RoughnessChannel` enum -# (also not exposed) -const ROUGHNESS_RED = 2 -const ROUGHNESS_GREEN = 3 -const ROUGHNESS_BLUE = 4 -const ROUGHNESS_ALPHA = 5 -const ROUGHNESS_GRAY = 6 diff --git a/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd b/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd deleted file mode 100644 index ff77b1a..0000000 --- a/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd +++ /dev/null @@ -1,9 +0,0 @@ -@tool - -# Stuff not exposed by Godot for making .import files - -const COMPRESS_LOSSLESS = 0 -const COMPRESS_LOSSY = 1 -const COMPRESS_VRAM_COMPRESSED = 2 -const COMPRESS_VRAM_UNCOMPRESSED = 3 -const COMPRESS_BASIS_UNIVERSAL = 4 diff --git a/addons/zylann.hterrain/tools/util/result.gd b/addons/zylann.hterrain/tools/util/result.gd deleted file mode 100644 index 5e897f1..0000000 --- a/addons/zylann.hterrain/tools/util/result.gd +++ /dev/null @@ -1,36 +0,0 @@ -# Data structure to hold the result of a function that can be expected to fail. -# The use case is to report errors back to the GUI and act accordingly, -# instead of forgetting them to the console or having the script break on an assertion. -# This is a C-like way of things, where the result can bubble, and does not require globals. - -@tool - -# Replace `success` with `error : int`? -var success := false -var value = null -var message := "" -var inner_result = null - - -func _init(p_success: bool, p_message := "", p_inner = null): - success = p_success - message = p_message - inner_result = p_inner - - -# TODO Can't type-hint self return -func with_value(v): - value = v - return self - - -func get_message() -> String: - var msg := message - if inner_result != null: - msg += "\n" - msg += inner_result.get_message() - return msg - - -func is_ok() -> bool: - return success diff --git a/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd b/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd deleted file mode 100644 index 242fe6e..0000000 --- a/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd +++ /dev/null @@ -1,11 +0,0 @@ -@tool -extends RichTextLabel - - -func _init(): - meta_clicked.connect(_on_meta_clicked) - - -func _on_meta_clicked(meta): - OS.shell_open(meta) - diff --git a/addons/zylann.hterrain/tools/util/spin_slider.gd b/addons/zylann.hterrain/tools/util/spin_slider.gd deleted file mode 100644 index fa690d5..0000000 --- a/addons/zylann.hterrain/tools/util/spin_slider.gd +++ /dev/null @@ -1,385 +0,0 @@ -@tool -extends Control - -const FG_MARGIN = 2 -const MAX_DECIMALS_VISUAL = 3 - -signal value_changed(value) - - -var _value := 0.0 -@export var value: float: - get: - return _value - set(v): - set_value_no_notify(v) - - -var _min_value := 0.0 -@export var min_value: float: - get: - return _min_value - set(v): - set_min_value(v) - - -var _max_value := 100.0 -@export var max_value: float: - get: - return _max_value - set(v): - set_max_value(v) - - -var _prefix := "" -@export var prefix: String: - get: - return _prefix - set(v): - set_prefix(v) - - -var _suffix := "" -@export var suffix: String: - get: - return _suffix - set(v): - set_suffix(v) - - -var _rounded := false -@export var rounded: bool: - get: - return _rounded - set(v): - set_rounded(v) - - -var _centered := true -@export var centered: bool: - get: - return _centered - set(v): - set_centered(v) - - -var _allow_greater := false -@export var allow_greater: bool: - get: - return _allow_greater - set(v): - set_allow_greater(v) - - -# There is still a limit when typing a larger value, but this one is to prevent software -# crashes or freezes. The regular min and max values are for slider UX. Exceeding it should be -# a corner case. -var _greater_max_value := 10000.0 -@export var greater_max_value: float: - get: - return _greater_max_value - set(v): - set_greater_max_value(v) - - -var _label : Label -var _label2 : Label -var _line_edit : LineEdit -var _ignore_line_edit := false -var _pressing := false -var _grabbing := false -var _press_pos := Vector2() - - -func _init(): - custom_minimum_size = Vector2(32, 28) - - _label = Label.new() - _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - _label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - _label.clip_text = true - #_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL - _label.anchor_top = 0 - _label.anchor_left = 0 - _label.anchor_right = 1 - _label.anchor_bottom = 1 - _label.mouse_filter = Control.MOUSE_FILTER_IGNORE - _label.add_theme_color_override("font_color_shadow", Color(0,0,0,0.5)) - _label.add_theme_constant_override("shadow_offset_x", 1) - _label.add_theme_constant_override("shadow_offset_y", 1) - add_child(_label) - - _label2 = Label.new() - _label2.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT - _label2.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - _label2.clip_text = true - #_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL - _label2.anchor_top = 0 - _label2.anchor_left = 0 - _label2.anchor_right = 1 - _label2.anchor_bottom = 1 - _label2.offset_left = 8 - _label2.mouse_filter = Control.MOUSE_FILTER_IGNORE - _label2.add_theme_color_override("font_color_shadow", Color(0,0,0,0.5)) - _label2.add_theme_constant_override("shadow_offset_x", 1) - _label2.add_theme_constant_override("shadow_offset_y", 1) - _label2.hide() - add_child(_label2) - - _line_edit = LineEdit.new() - _line_edit.alignment = HORIZONTAL_ALIGNMENT_CENTER - _line_edit.anchor_top = 0 - _line_edit.anchor_left = 0 - _line_edit.anchor_right = 1 - _line_edit.anchor_bottom = 1 - _line_edit.gui_input.connect(_on_LineEdit_gui_input) - _line_edit.focus_exited.connect(_on_LineEdit_focus_exited) - _line_edit.text_submitted.connect(_on_LineEdit_text_submitted) - _line_edit.hide() - add_child(_line_edit) - - mouse_default_cursor_shape = Control.CURSOR_HSIZE - - -func _ready(): - pass # Replace with function body. - - -func set_centered(p_centered: bool): - _centered = p_centered - if _centered: - _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - _label.offset_right = 0 - _label2.hide() - else: - _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - _label.offset_right = -8 - _label2.show() - queue_redraw() - - -func is_centered() -> bool: - return _centered - - -func set_value_no_notify(v: float): - set_value(v, false, false) - - -func set_value(v: float, notify_change: bool, use_slider_maximum: bool = false): - if _allow_greater and not use_slider_maximum: - v = clampf(v, _min_value, _greater_max_value) - else: - v = clampf(v, _min_value, _max_value) - - if v != _value: - _value = v - - queue_redraw() - - if notify_change: - value_changed.emit(get_value()) - - -func get_value(): - if _rounded: - return int(roundf(_value)) - return _value - - -func set_min_value(minv: float): - _min_value = minv - #queue_redraw() - - -func get_min_value() -> float: - return _min_value - - -func set_max_value(maxv: float): - _max_value = maxv - #queue_redraw() - - -func get_max_value() -> float: - return _max_value - - -func set_greater_max_value(gmax: float): - _greater_max_value = gmax - - -func get_greater_max_value() -> float: - return _greater_max_value - - -func set_rounded(b: bool): - _rounded = b - queue_redraw() - - -func is_rounded() -> bool: - return _rounded - - -func set_prefix(p_prefix: String): - _prefix = p_prefix - queue_redraw() - - -func get_prefix() -> String: - return _prefix - - -func set_suffix(p_suffix: String): - _suffix = p_suffix - queue_redraw() - - -func get_suffix() -> String: - return _suffix - - -func set_allow_greater(allow: bool): - _allow_greater = allow - - -func is_allowing_greater() -> bool: - return _allow_greater - - -func _set_from_pixel(px: float): - var r := (px - FG_MARGIN) / (size.x - FG_MARGIN * 2.0) - var v := _ratio_to_value(r) - set_value(v, true, true) - - -func get_ratio() -> float: - return _value_to_ratio(get_value()) - - -func _ratio_to_value(r: float) -> float: - return r * (_max_value - _min_value) + _min_value - - -func _value_to_ratio(v: float) -> float: - if absf(_max_value - _min_value) < 0.001: - return 0.0 - return (v - _min_value) / (_max_value - _min_value) - - -func _on_LineEdit_gui_input(event: InputEvent): - if event is InputEventKey: - if event.pressed: - if event.keycode == KEY_ESCAPE: - _ignore_line_edit = true - _hide_line_edit() - grab_focus() - _ignore_line_edit = false - - -func _on_LineEdit_focus_exited(): - if _ignore_line_edit: - return - _enter_text() - - -func _on_LineEdit_text_submitted(text: String): - _enter_text() - - -func _enter_text(): - var s = _line_edit.text.strip_edges() - if s.is_valid_float(): - var v := s.to_float() - if not _allow_greater: - v = minf(v, _max_value) - set_value(v, true, false) - _hide_line_edit() - - -func _hide_line_edit(): - _line_edit.hide() - _label.show() - queue_redraw() - - -func _show_line_edit(): - _line_edit.show() - _line_edit.text = str(get_value()) - _line_edit.select_all() - _line_edit.grab_focus() - _label.hide() - queue_redraw() - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - if event.button_index == MOUSE_BUTTON_LEFT: - _press_pos = event.position - _pressing = true - else: - if event.button_index == MOUSE_BUTTON_LEFT: - _pressing = false - if _grabbing: - _grabbing = false - _set_from_pixel(event.position.x) - else: - _show_line_edit() - - elif event is InputEventMouseMotion: - if _pressing and _press_pos.distance_to(event.position) > 2.0: - _grabbing = true - if _grabbing: - _set_from_pixel(event.position.x) - - -func _draw(): - if _line_edit.visible: - return - - #var grabber_width := 3 - var background_v_margin := 0 - var foreground_margin := FG_MARGIN - #var grabber_color := Color(0.8, 0.8, 0.8) - var interval_color := Color(0.4,0.4,0.4) - var background_color := Color(0.1, 0.1, 0.1) - - var control_rect := Rect2(Vector2(), size) - - var bg_rect := Rect2( - control_rect.position.x, - control_rect.position.y + background_v_margin, - control_rect.size.x, - control_rect.size.y - 2 * background_v_margin) - draw_rect(bg_rect, background_color) - - var fg_rect := control_rect.grow(-foreground_margin) - # Clamping the ratio because the value can be allowed to exceed the slider's boundaries - var ratio := clampf(get_ratio(), 0.0, 1.0) - fg_rect.size.x *= ratio - draw_rect(fg_rect, interval_color) - - var value_text := str(get_value()) - - var dot_pos := value_text.find(".") - if dot_pos != -1: - var decimal_count := len(value_text) - dot_pos - if decimal_count > MAX_DECIMALS_VISUAL: - value_text = value_text.substr(0, dot_pos + MAX_DECIMALS_VISUAL + 1) - - if _centered: - var text := value_text - if _prefix != "": - text = str(_prefix, " ", text) - if _suffix != "": - text = str(text, " ", _suffix) - _label.text = text - - else: - _label2.text = _prefix - var text := value_text - if _suffix != "": - text = str(text, " ", _suffix) - _label.text = text diff --git a/addons/zylann.hterrain/tools/util/spin_slider.tscn b/addons/zylann.hterrain/tools/util/spin_slider.tscn deleted file mode 100644 index 70a0da8..0000000 --- a/addons/zylann.hterrain/tools/util/spin_slider.tscn +++ /dev/null @@ -1,13 +0,0 @@ -[gd_scene load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/util/spin_slider.gd" type="Script" id=1] - -[node name="SpinSlider" type="Control"] -anchor_right = 1.0 -anchor_bottom = 1.0 -rect_min_size = Vector2( 32, 28 ) -mouse_default_cursor_shape = 10 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} diff --git a/addons/zylann.hterrain/util/direct_mesh_instance.gd b/addons/zylann.hterrain/util/direct_mesh_instance.gd deleted file mode 100644 index 17c89c9..0000000 --- a/addons/zylann.hterrain/util/direct_mesh_instance.gd +++ /dev/null @@ -1,65 +0,0 @@ -@tool - -# Implementation of MeshInstance which doesn't use the scene tree - -var _mesh_instance := RID() -# Need to keep a reference so that the mesh RID doesn't get freed -var _mesh : Mesh - - -func _init(): - var rs = RenderingServer - _mesh_instance = rs.instance_create() - rs.instance_set_visible(_mesh_instance, true) - - -func _notification(p_what: int): - if p_what == NOTIFICATION_PREDELETE: - if _mesh_instance != RID(): - RenderingServer.free_rid(_mesh_instance) - _mesh_instance = RID() - - -func enter_world(world: World3D): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, world.get_scenario()) - - -func exit_world(): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, RID()) - - -func set_world(world: World3D): - if world != null: - enter_world(world) - else: - exit_world() - - -func set_transform(world_transform: Transform3D): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_transform(_mesh_instance, world_transform) - - -func set_mesh(mesh: Mesh): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_base(_mesh_instance, mesh.get_rid() if mesh != null else RID()) - _mesh = mesh - - -func set_material(material: Material): - assert(_mesh_instance != RID()) - RenderingServer.instance_geometry_set_material_override( \ - _mesh_instance, material.get_rid() if material != null else RID()) - - -func set_visible(visible: bool): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_visible(_mesh_instance, visible) - - -func set_aabb(aabb: AABB): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_custom_aabb(_mesh_instance, aabb) - diff --git a/addons/zylann.hterrain/util/direct_multimesh_instance.gd b/addons/zylann.hterrain/util/direct_multimesh_instance.gd deleted file mode 100644 index dbb899b..0000000 --- a/addons/zylann.hterrain/util/direct_multimesh_instance.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool - -# Implementation of MultiMeshInstance which doesn't use the scene tree - -var _multimesh_instance := RID() - - -func _init(): - _multimesh_instance = RenderingServer.instance_create() - - -func _notification(what: int): - if what == NOTIFICATION_PREDELETE: - RenderingServer.free_rid(_multimesh_instance) - - -func set_world(world: World3D): - RenderingServer.instance_set_scenario( - _multimesh_instance, world.get_scenario() if world != null else RID()) - - -func set_visible(visible: bool): - RenderingServer.instance_set_visible(_multimesh_instance, visible) - - -func set_transform(trans: Transform3D): - RenderingServer.instance_set_transform(_multimesh_instance, trans) - - -func set_multimesh(mm: MultiMesh): - RenderingServer.instance_set_base(_multimesh_instance, mm.get_rid() if mm != null else RID()) - - -func set_material_override(material: Material): - RenderingServer.instance_geometry_set_material_override( \ - _multimesh_instance, material.get_rid() if material != null else RID()) - - -func set_aabb(aabb: AABB): - RenderingServer.instance_set_custom_aabb(_multimesh_instance, aabb) - - -func set_layer_mask(mask: int): - RenderingServer.instance_set_layer_mask(_multimesh_instance, mask) - - -func set_cast_shadow(cast_shadow: int): - RenderingServer.instance_geometry_set_cast_shadows_setting(_multimesh_instance, cast_shadow) diff --git a/addons/zylann.hterrain/util/errors.gd b/addons/zylann.hterrain/util/errors.gd deleted file mode 100644 index c6a2c63..0000000 --- a/addons/zylann.hterrain/util/errors.gd +++ /dev/null @@ -1,58 +0,0 @@ -@tool - -# Taken from https://docs.godotengine.org/en/3.0/classes/class_@globalscope.html#enum-globalscope-error -const _names = { - OK: "ok", - FAILED: "Generic error.", - ERR_UNAVAILABLE: "Unavailable error", - ERR_UNCONFIGURED: "Unconfigured error", - ERR_UNAUTHORIZED: "Unauthorized error", - ERR_PARAMETER_RANGE_ERROR: "Parameter range error", - ERR_OUT_OF_MEMORY: "Out of memory (OOM) error", - ERR_FILE_NOT_FOUND: "File Not found error", - ERR_FILE_BAD_DRIVE: "File Bad drive error", - ERR_FILE_BAD_PATH: "File Bad path error", - ERR_FILE_NO_PERMISSION: "File No permission error", - ERR_FILE_ALREADY_IN_USE: "File Already in use error", - ERR_FILE_CANT_OPEN: "File Can't open error", - ERR_FILE_CANT_WRITE: "File Can't write error", - ERR_FILE_CANT_READ: "File Can't read error", - ERR_FILE_UNRECOGNIZED: "File Unrecognized error", - ERR_FILE_CORRUPT: "File Corrupt error", - ERR_FILE_MISSING_DEPENDENCIES: "File Missing dependencies error", - ERR_FILE_EOF: "File End of file (EOF) error", - ERR_CANT_OPEN: "Can't open error", - ERR_CANT_CREATE: "Can't create error", - ERR_QUERY_FAILED: "Query failed error", - ERR_ALREADY_IN_USE: "Already in use error", - ERR_LOCKED: "Locked error", - ERR_TIMEOUT: "Timeout error", - ERR_CANT_CONNECT: "Can't connect", - ERR_CANT_RESOLVE: "Can't resolve", - ERR_CONNECTION_ERROR: "Connection error", - ERR_CANT_ACQUIRE_RESOURCE: "Can't acquire resource error", - ERR_CANT_FORK: "Can't fork", - ERR_INVALID_DATA: "Invalid data error", - ERR_INVALID_PARAMETER: "Invalid parameter error", - ERR_ALREADY_EXISTS: "Already exists error", - ERR_DOES_NOT_EXIST: "Does not exist error", - ERR_DATABASE_CANT_READ: "Database Read error", - ERR_DATABASE_CANT_WRITE: "Database Write error", - ERR_COMPILATION_FAILED: "Compilation failed error", - ERR_METHOD_NOT_FOUND: "Method not found error", - ERR_LINK_FAILED: "Linking failed error", - ERR_SCRIPT_FAILED: "Script failed error", - ERR_CYCLIC_LINK: "Cycling link (import cycle) error", - ERR_INVALID_DECLARATION: "Invalid declaration", - ERR_DUPLICATE_SYMBOL: "Duplicate symbol", - ERR_PARSE_ERROR: "Parse error", - ERR_BUSY: "Busy error", - ERR_SKIP: "Skip error", - ERR_HELP: "Help error", - ERR_BUG: "Bug error", - ERR_PRINTER_ON_FIRE: "The printer is on fire" -} - -static func get_message(err_code: int): - return str("[", err_code, "]: ", _names[err_code]) - diff --git a/addons/zylann.hterrain/util/grid.gd b/addons/zylann.hterrain/util/grid.gd deleted file mode 100644 index b28e83b..0000000 --- a/addons/zylann.hterrain/util/grid.gd +++ /dev/null @@ -1,203 +0,0 @@ - -# Note: `tool` is optional but without it there are no error reporting in the editor -@tool - -# TODO Remove grid_ prefixes, context is already given by the script itself - - -# Performs a positive integer division rounded to upper (4/2 = 2, 5/3 = 2) -static func up_div(a: int, b: int): - if a % b != 0: - return a / b + 1 - return a / b - - -# Creates a 2D array as an array of arrays. -# if v is provided, all cells will contain the same value. -# if v is a funcref, it will be executed to fill the grid cell per cell. -static func create_grid(w: int, h: int, v=null): - var is_create_func = typeof(v) == TYPE_CALLABLE - var grid := [] - grid.resize(h) - for y in range(grid.size()): - var row := [] - row.resize(w) - if is_create_func: - for x in range(row.size()): - row[x] = v.call(x, y) - else: - for x in range(row.size()): - row[x] = v - grid[y] = row - return grid - - -# Creates a 2D array that is a copy of another 2D array -static func clone_grid(other_grid): - var grid := [] - grid.resize(other_grid.size()) - for y in range(0, grid.size()): - var row := [] - var other_row = other_grid[y] - row.resize(other_row.size()) - grid[y] = row - for x in range(0, row.size()): - row[x] = other_row[x] - return grid - - -# Resizes a 2D array and allows to set or call functions for each deleted and created cells. -# This is especially useful if cells contain objects and you don't want to loose existing data. -static func resize_grid(grid, new_width, new_height, create_func=null, delete_func=null): - # Check parameters - assert(new_width >= 0 and new_height >= 0) - assert(grid != null) - if delete_func != null: - assert(typeof(delete_func) == TYPE_CALLABLE) - # `create_func` can also be a default value - var is_create_func = typeof(create_func) == TYPE_CALLABLE - - # Get old size (supposed to be rectangular!) - var old_height = grid.size() - var old_width = 0 - if grid.size() != 0: - old_width = grid[0].size() - - # Delete old rows - if new_height < old_height: - if delete_func != null: - for y in range(new_height, grid.size()): - var row = grid[y] - for x in len(row): - var elem = row[x] - delete_func.call(elem) - grid.resize(new_height) - - # Delete old columns - if new_width < old_width: - for y in len(grid): - var row = grid[y] - if delete_func != null: - for x in range(new_width, row.size()): - var elem = row[x] - delete_func.call(elem) - row.resize(new_width) - - # Create new columns - if new_width > old_width: - for y in len(grid): - var row = grid[y] - row.resize(new_width) - if is_create_func: - for x in range(old_width, new_width): - row[x] = create_func.call(x,y) - else: - for x in range(old_width, new_width): - row[x] = create_func - - # Create new rows - if new_height > old_height: - grid.resize(new_height) - for y in range(old_height, new_height): - var row = [] - row.resize(new_width) - grid[y] = row - if is_create_func: - for x in new_width: - row[x] = create_func.call(x,y) - else: - for x in new_width: - row[x] = create_func - - # Debug test check - assert(grid.size() == new_height) - for y in len(grid): - assert(len(grid[y]) == new_width) - - -# Retrieves the minimum and maximum values from a grid -static func grid_min_max(grid): - if grid.size() == 0 or grid[0].size() == 0: - return [0,0] - var vmin = grid[0][0] - var vmax = vmin - for y in len(grid): - var row = grid[y] - for x in len(row): - var v = row[x] - if v > vmax: - vmax = v - elif v < vmin: - vmin = v - return [vmin, vmax] - - -# Copies a sub-region of a grid as a new grid. No boundary check! -static func grid_extract_area(src_grid, x0, y0, w, h): - var dst = create_grid(w, h) - for y in h: - var dst_row = dst[y] - var src_row = src_grid[y0+y] - for x in w: - dst_row[x] = src_row[x0+x] - return dst - - -# Extracts data and crops the result if the requested rect crosses the bounds -static func grid_extract_area_safe_crop(src_grid, x0, y0, w, h): - # Return empty is completely out of bounds - var gw = src_grid.size() - if gw == 0: - return [] - var gh = src_grid[0].size() - if x0 >= gw or y0 >= gh: - return [] - - # Crop min pos - if x0 < 0: - w += x0 - x0 = 0 - if y0 < 0: - h += y0 - y0 = 0 - - # Crop max pos - if x0 + w >= gw: - w = gw-x0 - if y0 + h >= gh: - h = gh-y0 - - return grid_extract_area(src_grid, x0, y0, w, h) - - -# Sets values from a grid inside another grid. No boundary check! -static func grid_paste(src_grid, dst_grid, x0, y0): - for y in range(0, src_grid.size()): - var src_row = src_grid[y] - var dst_row = dst_grid[y0+y] - for x in range(0, src_row.size()): - dst_row[x0+x] = src_row[x] - - -# Tests if two grids are the same size and contain the same values -static func grid_equals(a, b): - if a.size() != b.size(): - return false - for y in a.size(): - var a_row = a[y] - var b_row = b[y] - if a_row.size() != b_row.size(): - return false - for x in b_row.size(): - if a_row[x] != b_row[x]: - return false - return true - - -static func grid_get_or_default(grid, x, y, defval=null): - if y >= 0 and y < len(grid): - var row = grid[y] - if x >= 0 and x < len(row): - return row[x] - return defval - diff --git a/addons/zylann.hterrain/util/image_file_cache.gd b/addons/zylann.hterrain/util/image_file_cache.gd deleted file mode 100644 index e39e4cd..0000000 --- a/addons/zylann.hterrain/util/image_file_cache.gd +++ /dev/null @@ -1,291 +0,0 @@ -@tool - -# Used to store temporary images on disk. -# This is useful for undo/redo as image edition can quickly fill up memory. - -# Image data is stored in archive files together, -# because when dealing with many images it speeds up filesystem I/O on Windows. -# If the file exceeds a predefined size, a new one is created. -# Writing to disk is performed from a thread, to leave the main thread responsive. -# However if you want to obtain an image back while it didn't save yet, the main thread will block. -# When the application or plugin is closed, the files get cleared. - -const HT_Logger = preload("./logger.gd") -const HT_Errors = preload("./errors.gd") - -const CACHE_FILE_SIZE_THRESHOLD = 1048576 -# For debugging -const USE_THREAD = true - -var _cache_dir := "" -var _next_id := 0 -var _session_id := "" -var _cache_image_info := {} -var _logger = HT_Logger.get_for(self) -var _current_cache_file_index := 0 -var _cache_file_offset := 0 - -var _saving_thread := Thread.new() -var _save_queue := [] -var _save_queue_mutex := Mutex.new() -var _save_semaphore := Semaphore.new() -var _save_thread_running := false - - -func _init(cache_dir: String): - assert(cache_dir != "") - _cache_dir = cache_dir - var rng := RandomNumberGenerator.new() - rng.randomize() - for i in 16: - _session_id += str(rng.randi() % 10) - _logger.debug(str("Image cache session ID: ", _session_id)) - if not DirAccess.dir_exists_absolute(_cache_dir): - var err := DirAccess.make_dir_absolute(_cache_dir) - if err != OK: - _logger.error("Could not create directory {0}: {1}" \ - .format([_cache_dir, HT_Errors.get_message(err)])) - _save_thread_running = true - if USE_THREAD: - _saving_thread.start(_save_thread_func) - - -# TODO Cannot cleanup the cache in destructor! -# Godot doesn't allow me to call clear()... -# https://github.com/godotengine/godot/issues/31166 -func _notification(what: int): - if what == NOTIFICATION_PREDELETE: - #clear() - _save_thread_running = false - _save_semaphore.post() - if USE_THREAD: - _saving_thread.wait_to_finish() - - -func _create_new_cache_file(fpath: String): - var f := FileAccess.open(fpath, FileAccess.WRITE) - if f == null: - var err = FileAccess.get_open_error() - _logger.error("Failed to create new cache file {0}: {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return - - -func _get_current_cache_file_name() -> String: - return _cache_dir.path_join(str(_session_id, "_", _current_cache_file_index, ".cache")) - - -func save_image(im: Image) -> int: - assert(im != null) - if im.has_mipmaps(): - # TODO Add support for this? Didn't need it so far - _logger.error("Caching an image with mipmaps, this isn't supported") - - var fpath := _get_current_cache_file_name() - if _next_id == 0: - # First file - _create_new_cache_file(fpath) - - var id := _next_id - _next_id += 1 - - var item := { - # Duplicate the image so we are sure nothing funny will happen to it - # while the thread saves it - "image": im.duplicate(), - "path": fpath, - "data_offset": _cache_file_offset, - "saved": false - } - - _cache_file_offset += _get_image_data_size(im) - if _cache_file_offset >= CACHE_FILE_SIZE_THRESHOLD: - _cache_file_offset = 0 - _current_cache_file_index += 1 - _create_new_cache_file(_get_current_cache_file_name()) - - _cache_image_info[id] = item - - _save_queue_mutex.lock() - _save_queue.append(item) - _save_queue_mutex.unlock() - - _save_semaphore.post() - - if not USE_THREAD: - var before = Time.get_ticks_msec() - while len(_save_queue) > 0: - _save_thread_func() - if Time.get_ticks_msec() - before > 10_000: - _logger.error("Taking to long to empty save queue in non-threaded mode!") - - return id - - -static func _get_image_data_size(im: Image) -> int: - return 1 + 4 + 4 + 4 + len(im.get_data()) - - -static func _write_image(f: FileAccess, im: Image): - f.store_8(im.get_format()) - f.store_32(im.get_width()) - f.store_32(im.get_height()) - var data : PackedByteArray = im.get_data() - f.store_32(len(data)) - f.store_buffer(data) - - -static func _read_image(f: FileAccess) -> Image: - var format := f.get_8() - var width := f.get_32() - var height := f.get_32() - var data_size := f.get_32() - var data := f.get_buffer(data_size) - var im := Image.create_from_data(width, height, false, format, data) - return im - - -func load_image(id: int) -> Image: - var info := _cache_image_info[id] as Dictionary - - var timeout := 5.0 - var time_before := Time.get_ticks_msec() - # We could just grab `image`, because the thread only reads it. - # However it's still not safe to do that if we write or even lock it, - # so we have to assume it still has ownership of it. - while not info.saved: - OS.delay_msec(8.0) - _logger.debug("Waiting for cached image {0}...".format([id])) - if Time.get_ticks_msec() - time_before > timeout: - _logger.error("Could not get image {0} from cache. Something went wrong.".format([id])) - return null - - var fpath := info.path as String - - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - _logger.error("Could not load cached image from {0}: {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return null - - f.seek(info.data_offset) - var im = _read_image(f) - f = null # close file - - assert(im != null) - return im - - -func clear(): - _logger.debug("Clearing image cache") - - var dir := DirAccess.open(_cache_dir) - if dir == null: - #var err = DirAccess.get_open_error() - _logger.error("Could not open image file cache directory '{0}'" \ - .format([_cache_dir])) - return - - dir.include_hidden = false - dir.include_navigational = false - - var err := dir.list_dir_begin() - if err != OK: - _logger.error("Could not start list_dir_begin in '{0}'".format([_cache_dir])) - return - - # Delete all cache files - while true: - var fpath := dir.get_next() - if fpath == "": - break - if fpath.ends_with(".cache"): - _logger.debug(str("Deleting ", fpath)) - err = dir.remove(fpath) - if err != OK: - _logger.error("Failed to delete cache file '{0}': {1}" \ - .format([_cache_dir.path_join(fpath), HT_Errors.get_message(err)])) - - _cache_image_info.clear() - - -func _save_thread_func(): - # Threads keep a reference to the object of the function they run. - # So if the object is a Reference, and that reference owns the thread... we get a cycle. - # We can break the cycle by removing 1 to the count inside the thread. - # The thread's reference will never die unexpectedly because we stop and destroy the thread - # in the destructor of the reference. - # If that workaround explodes one day, another way could be to use an intermediary instance - # extending Object, and run a function on that instead. - # - # I added this in Godot 3, and it seems to still be relevant in Godot 4 because if I don't - # do it, objects are leaking. - # - # BUT it seems to end up triggering a crash in debug Godot builds due to unrefing RefCounted - # with refcount == 0, so I guess it's wrong now? - # So basically, either I do it and I risk a crash, - # or I don't do it and then it causes a leak... - # TODO Make this shit use `Object` - # - # if USE_THREAD: - # unreference() - - while _save_thread_running: - _save_queue_mutex.lock() - var to_save := _save_queue.duplicate(false) - _save_queue.clear() - _save_queue_mutex.unlock() - - if len(to_save) == 0: - if USE_THREAD: - _save_semaphore.wait() - continue - - var f : FileAccess - var path := "" - - for item in to_save: - # Keep re-using the same file if we did not change path. - # It makes I/Os faster. - if item.path != path: - # Close previous file - f = null - - path = item.path - - f = FileAccess.open(path, FileAccess.READ_WRITE) - if f == null: - var err := FileAccess.get_open_error() - call_deferred("_on_error", "Could not open file {0}: {1}" \ - .format([path, HT_Errors.get_message(err)])) - path = "" - continue - - f.seek(item.data_offset) - _write_image(f, item.image) - # Notify main thread. - # The thread does not modify data, only reads it. - call_deferred("_on_image_saved", item) - - # Workaround some weird behavior in Godot 4: - # when the next loop runs, `f` IS NOT CLEANED UP. A reference is still held before `var f` - # is reached, which means the file is still locked while the thread is waiting on the - # semaphore... so I have to explicitely "close" the file here. - f = null - - if not USE_THREAD: - break - - -func _on_error(msg: String): - _logger.error(msg) - - -func _on_image_saved(item: Dictionary): - _logger.debug(str("Saved ", item.path)) - item.saved = true - # Should remove image from memory (for usually being last reference) - item.image = null - - diff --git a/addons/zylann.hterrain/util/logger.gd b/addons/zylann.hterrain/util/logger.gd deleted file mode 100644 index fcc78a3..0000000 --- a/addons/zylann.hterrain/util/logger.gd +++ /dev/null @@ -1,34 +0,0 @@ -@tool - -class HT_LoggerBase: - var _context := "" - - func _init(p_context): - _context = p_context - - func debug(msg: String): - pass - - func warn(msg: String): - push_warning("{0}: {1}".format([_context, msg])) - - func error(msg: String): - push_error("{0}: {1}".format([_context, msg])) - - -class HT_LoggerVerbose extends HT_LoggerBase: - func _init(p_context: String): - super(p_context) - - func debug(msg: String): - print(_context, ": ", msg) - - -static func get_for(owner: Object) -> HT_LoggerBase: - # Note: don't store the owner. If it's a Reference, it could create a cycle - var script : Script = owner.get_script() - var context := script.resource_path.get_file() - if OS.is_stdout_verbose(): - return HT_LoggerVerbose.new(context) - return HT_LoggerBase.new(context) - diff --git a/addons/zylann.hterrain/util/util.gd b/addons/zylann.hterrain/util/util.gd deleted file mode 100644 index e2cd32c..0000000 --- a/addons/zylann.hterrain/util/util.gd +++ /dev/null @@ -1,549 +0,0 @@ -@tool - -const HT_Errors = preload("./errors.gd") - - -# Godot has this internally but doesn't expose it -static func next_power_of_two(x: int) -> int: - x -= 1 - x |= x >> 1 - x |= x >> 2 - x |= x >> 4 - x |= x >> 8 - x |= x >> 16 - x += 1 - return x - - -# CubeMesh doesn't have a wireframe option -static func create_wirecube_mesh(color = Color(1,1,1)) -> Mesh: - var positions := PackedVector3Array([ - Vector3(0, 0, 0), - Vector3(1, 0, 0), - Vector3(1, 0, 1), - Vector3(0, 0, 1), - Vector3(0, 1, 0), - Vector3(1, 1, 0), - Vector3(1, 1, 1), - Vector3(0, 1, 1), - ]) - var colors := PackedColorArray([ - color, color, color, color, - color, color, color, color, - ]) - var indices := PackedInt32Array([ - 0, 1, - 1, 2, - 2, 3, - 3, 0, - - 4, 5, - 5, 6, - 6, 7, - 7, 4, - - 0, 4, - 1, 5, - 2, 6, - 3, 7 - ]) - var arrays := [] - arrays.resize(Mesh.ARRAY_MAX) - arrays[Mesh.ARRAY_VERTEX] = positions - arrays[Mesh.ARRAY_COLOR] = colors - arrays[Mesh.ARRAY_INDEX] = indices - var mesh := ArrayMesh.new() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_LINES, arrays) - return mesh - - -static func integer_square_root(x: int) -> int: - assert(typeof(x) == TYPE_INT) - var r := int(roundf(sqrt(x))) - if r * r == x: - return r - # Does not exist - return -1 - - -# Formats integer using a separator between each 3-digit group -static func format_integer(n: int, sep := ",") -> String: - assert(typeof(n) == TYPE_INT) - - var negative := false - if n < 0: - negative = true - n = -n - - var s = "" - while n >= 1000: - s = str(sep, str(n % 1000).pad_zeros(3), s) - n /= 1000 - - if negative: - return str("-", str(n), s) - else: - return str(str(n), s) - - -# Goes up all parents until a node of the given class is found -static func get_node_in_parents(node: Node, klass) -> Node: - while node != null: - node = node.get_parent() - if node != null and is_instance_of(node, klass): - return node - return null - - -# Goes down all children until a node of the given class is found -static func find_first_node(node: Node, klass) -> Node: - if is_instance_of(node, klass): - return node - for i in node.get_child_count(): - var child := node.get_child(i) - var found_node := find_first_node(child, klass) - if found_node != null: - return found_node - return null - - -static func is_in_edited_scene(node: Node) -> bool: - if not node.is_inside_tree(): - return false - var edited_scene := node.get_tree().edited_scene_root - if node == edited_scene: - return true - return edited_scene != null and edited_scene.is_ancestor_of(node) - - -# Get an extended or cropped version of an image, -# with optional anchoring to decide in which direction to extend or crop. -# New pixels are filled with the provided fill color. -static func get_cropped_image(src: Image, width: int, height: int, - fill_color=null, anchor=Vector2(-1, -1)) -> Image: - - width = int(width) - height = int(height) - if width == src.get_width() and height == src.get_height(): - return src - var im := Image.create(width, height, false, src.get_format()) - if fill_color != null: - im.fill(fill_color) - var p = get_cropped_image_params( - src.get_width(), src.get_height(), width, height, anchor) - im.blit_rect(src, p.src_rect, p.dst_pos) - return im - - -static func get_cropped_image_params(src_w: int, src_h: int, dst_w: int, dst_h: int, - anchor: Vector2) -> Dictionary: - - var rel_anchor := (anchor + Vector2(1, 1)) / 2.0 - - var dst_x := (dst_w - src_w) * rel_anchor.x - var dst_y := (dst_h - src_h) * rel_anchor.y - - var src_x := 0 - var src_y := 0 - - if dst_x < 0: - src_x -= dst_x - src_w -= dst_x - dst_x = 0 - - if dst_y < 0: - src_y -= dst_y - src_h -= dst_y - dst_y = 0 - - if dst_x + src_w >= dst_w: - src_w = dst_w - dst_x - - if dst_y + src_h >= dst_h: - src_h = dst_h - dst_y - - return { - "src_rect": Rect2i(src_x, src_y, src_w, src_h), - "dst_pos": Vector2i(dst_x, dst_y) - } - -# TODO Workaround for https://github.com/godotengine/godot/issues/24488 -# TODO Simplify in Godot 3.1 if that's still not fixed, -# using https://github.com/godotengine/godot/pull/21806 -# And actually that function does not even work. -#static func get_shader_param_or_default(mat: Material, name: String): -# assert(mat.shader != null) -# var v = mat.get_shader_param(name) -# if v != null: -# return v -# var params = VisualServer.shader_get_param_list(mat.shader) -# for p in params: -# if p.name == name: -# match p.type: -# TYPE_OBJECT: -# return null -# # I should normally check default values, -# # however they are not accessible -# TYPE_BOOL: -# return false -# TYPE_REAL: -# return 0.0 -# TYPE_VECTOR2: -# return Vector2() -# TYPE_VECTOR3: -# return Vector3() -# TYPE_COLOR: -# return Color() -# return null - - -# Generic way to apply editor scale to a plugin UI scene. -# It is slower than doing it manually on specific controls. -# Takes a node as root because since Godot 4 Window dialogs are no longer Controls. -static func apply_dpi_scale(root: Node, dpi_scale: float): - if dpi_scale == 1.0: - return - var to_process := [root] - while len(to_process) > 0: - var node : Node = to_process[-1] - to_process.pop_back() - if node is Window: - node.size = Vector2(node.size) * dpi_scale - elif node is Viewport or node is SubViewport: - continue - elif node is Control: - if node.custom_minimum_size != Vector2(0, 0): - node.custom_minimum_size = node.custom_minimum_size * dpi_scale - var parent = node.get_parent() - if parent != null: - if not (parent is Container): - node.offset_bottom *= dpi_scale - node.offset_left *= dpi_scale - node.offset_top *= dpi_scale - node.offset_right *= dpi_scale - for i in node.get_child_count(): - to_process.append(node.get_child(i)) - - -# TODO AABB has `intersects_segment` but doesn't provide the hit point -# So we have to rely on a less efficient method. -# Returns a list of intersections between an AABB and a segment, sorted -# by distance to the beginning of the segment. -static func get_aabb_intersection_with_segment(aabb: AABB, - segment_begin: Vector3, segment_end: Vector3) -> Array: - - var hits := [] - - if not aabb.intersects_segment(segment_begin, segment_end): - return hits - - var hit - - var x_rect := Rect2(aabb.position.y, aabb.position.z, aabb.size.y, aabb.size.z) - - hit = Plane(Vector3(1, 0, 0), aabb.position.x) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and x_rect.has_point(Vector2(hit.y, hit.z)): - hits.append(hit) - - hit = Plane(Vector3(1, 0, 0), aabb.end.x) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and x_rect.has_point(Vector2(hit.y, hit.z)): - hits.append(hit) - - var y_rect := Rect2(aabb.position.x, aabb.position.z, aabb.size.x, aabb.size.z) - - hit = Plane(Vector3(0, 1, 0), aabb.position.y) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and y_rect.has_point(Vector2(hit.x, hit.z)): - hits.append(hit) - - hit = Plane(Vector3(0, 1, 0), aabb.end.y) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and y_rect.has_point(Vector2(hit.x, hit.z)): - hits.append(hit) - - var z_rect := Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y) - - hit = Plane(Vector3(0, 0, 1), aabb.position.z) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and z_rect.has_point(Vector2(hit.x, hit.y)): - hits.append(hit) - - hit = Plane(Vector3(0, 0, 1), aabb.end.z) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and z_rect.has_point(Vector2(hit.x, hit.y)): - hits.append(hit) - - if len(hits) == 2: - # The segment has two hit points. Sort them by distance - var d0 = hits[0].distance_squared_to(segment_begin) - var d1 = hits[1].distance_squared_to(segment_begin) - if d0 > d1: - var temp = hits[0] - hits[0] = hits[1] - hits[1] = temp - else: - assert(len(hits) < 2) - - return hits - - -class HT_GridRaytraceResult2D: - var hit_cell_pos: Vector2 - var prev_cell_pos: Vector2 - - -# Iterates through a virtual 2D grid of unit-sized square cells, -# and executes an action on each cell intersecting the given segment, -# ordered from begin to end. -# One of my most re-used pieces of code :) -# -# Initially inspired by http://www.cse.yorku.ca/~amana/research/grid.pdf -# -# Ported from https://github.com/bulletphysics/bullet3/blob/ -# 687780af6b491056700cfb22cab57e61aeec6ab8/src/BulletCollision/CollisionShapes/ -# btHeightfieldTerrainShape.cpp#L418 -# -static func grid_raytrace_2d(ray_origin: Vector2, ray_direction: Vector2, - quad_predicate: Callable, max_distance: float) -> HT_GridRaytraceResult2D: - - if max_distance < 0.0001: - # Consider the ray is too small to hit anything - return null - - var xi_step := 0 - if ray_direction.x > 0: - xi_step = 1 - elif ray_direction.x < 0: - xi_step = -1 - - var yi_step := 0 - if ray_direction.y > 0: - yi_step = 1 - elif ray_direction.y < 0: - yi_step = -1 - - var infinite := 9999999.0 - - var param_delta_x := infinite - if xi_step != 0: - param_delta_x = 1.0 / absf(ray_direction.x) - - var param_delta_y := infinite - if yi_step != 0: - param_delta_y = 1.0 / absf(ray_direction.y) - - # pos = param * dir - # At which value of `param` we will cross a x-axis lane? - var param_cross_x := infinite - # At which value of `param` we will cross a y-axis lane? - var param_cross_y := infinite - - # param_cross_x and param_cross_z are initialized as being the first cross - # X initialization - if xi_step != 0: - if xi_step == 1: - param_cross_x = (ceilf(ray_origin.x) - ray_origin.x) * param_delta_x - else: - param_cross_x = (ray_origin.x - floorf(ray_origin.x)) * param_delta_x - else: - # Will never cross on X - param_cross_x = infinite - - # Y initialization - if yi_step != 0: - if yi_step == 1: - param_cross_y = (ceilf(ray_origin.y) - ray_origin.y) * param_delta_y - else: - param_cross_y = (ray_origin.y - floorf(ray_origin.y)) * param_delta_y - else: - # Will never cross on Y - param_cross_y = infinite - - var x := int(floorf(ray_origin.x)) - var y := int(floorf(ray_origin.y)) - - # Workaround cases where the ray starts at an integer position - if param_cross_x == 0.0: - param_cross_x += param_delta_x - # If going backwards, we should ignore the position we would get by the above flooring, - # because the ray is not heading in that direction - if xi_step == -1: - x -= 1 - - if param_cross_y == 0.0: - param_cross_y += param_delta_y - if yi_step == -1: - y -= 1 - - var prev_x := x - var prev_y := y - var param := 0.0 - var prev_param := 0.0 - - while true: - prev_x = x - prev_y = y - prev_param = param - - if param_cross_x < param_cross_y: - # X lane - x += xi_step - # Assign before advancing the param, - # to be in sync with the initialization step - param = param_cross_x - param_cross_x += param_delta_x - - else: - # Y lane - y += yi_step - param = param_cross_y - param_cross_y += param_delta_y - - if param > max_distance: - param = max_distance - # quad coordinates, enter param, exit/end param - if quad_predicate.call(prev_x, prev_y, prev_param, param): - var res := HT_GridRaytraceResult2D.new() - res.hit_cell_pos = Vector2(x, y) - res.prev_cell_pos = Vector2(prev_x, prev_y) - return res - else: - break - - elif quad_predicate.call(prev_x, prev_y, prev_param, param): - var res := HT_GridRaytraceResult2D.new() - res.hit_cell_pos = Vector2(x, y) - res.prev_cell_pos = Vector2(prev_x, prev_y) - return res - - return null - - -static func get_segment_clipped_by_rect(rect: Rect2, - segment_begin: Vector2, segment_end: Vector2) -> Array: - - # / - # A-----/---B A-----+---B - # | / | => | / | - # | / | | / | - # C--/------D C--+------D - # / - - if rect.has_point(segment_begin) and rect.has_point(segment_end): - return [segment_begin, segment_end] - - var a := rect.position - var b := Vector2(rect.end.x, rect.position.y) - var c := Vector2(rect.position.x, rect.end.y) - var d := rect.end - - var ab = Geometry2D.segment_intersects_segment(segment_begin, segment_end, a, b) - var cd = Geometry2D.segment_intersects_segment(segment_begin, segment_end, c, d) - var ac = Geometry2D.segment_intersects_segment(segment_begin, segment_end, a, c) - var bd = Geometry2D.segment_intersects_segment(segment_begin, segment_end, b, d) - - var hits = [] - if ab != null: - hits.append(ab) - if cd != null: - hits.append(cd) - if ac != null: - hits.append(ac) - if bd != null: - hits.append(bd) - - # Now we need to order the hits from begin to end - if len(hits) == 1: - if rect.has_point(segment_begin): - hits = [segment_begin, hits[0]] - elif rect.has_point(segment_end): - hits = [hits[0], segment_end] - else: - # TODO This has a tendency to happen with integer coordinates... - # How can you get only 1 hit and have no end of the segment - # inside of the rectangle? Float precision shit? Assume no hit... - return [] - - elif len(hits) == 2: - var d0 = hits[0].distance_squared_to(segment_begin) - var d1 = hits[1].distance_squared_to(segment_begin) - if d0 > d1: - hits = [hits[1], hits[0]] - - return hits - - -static func get_pixel_clamped(im: Image, x: int, y: int) -> Color: - x = clampi(x, 0, im.get_width() - 1) - y = clampi(y, 0, im.get_height() - 1) - return im.get_pixel(x, y) - - -static func update_configuration_warning(node: Node, recursive: bool): - if not Engine.is_editor_hint(): - return - node.update_configuration_warnings() - if recursive: - for i in node.get_child_count(): - var child = node.get_child(i) - update_configuration_warning(child, true) - - -static func write_import_file(settings: Dictionary, imp_fpath: String, logger) -> bool: - # TODO Should use ConfigFile instead - var f := FileAccess.open(imp_fpath, FileAccess.WRITE) - if f == null: - var err = FileAccess.get_open_error() - logger.error("Could not open '{0}' for write, error {1}" \ - .format([imp_fpath, HT_Errors.get_message(err)])) - return false - - for section in settings: - f.store_line(str("[", section, "]")) - f.store_line("") - var params = settings[section] - for key in params: - var v = params[key] - var sv - match typeof(v): - TYPE_STRING: - sv = str('"', v.replace('"', '\"'), '"') - TYPE_BOOL: - sv = "true" if v else "false" - _: - sv = str(v) - f.store_line(str(key, "=", sv)) - f.store_line("") - - return true - - -static func update_texture_partial( - tex: ImageTexture, im: Image, src_rect: Rect2i, dst_pos: Vector2i): - - # ..ooo@@@XXX%%%xx.. - # .oo@@XXX%x%xxx.. ` . - # .o@XX%%xx.. ` . - # o@X%.. ..ooooooo - # .@X%x. ..o@@^^ ^^@@o - # .ooo@@@@@@ooo.. ..o@@^ @X% - # o@@^^^ ^^^@@@ooo.oo@@^ % - # xzI -*-- ^^^o^^ --*- % - # @@@o ooooooo^@@^o^@X^@oooooo .X%x - # I@@@@@@@@@XX%%xx ( o@o )X%x@ROMBASED@@@X%x - # I@@@@XX%%xx oo@@@@X% @@X%x ^^^@@@@@@@X%x - # @X%xx o@@@@@@@X% @@XX%%x ) ^^@X%x - # ^ xx o@@@@@@@@Xx ^ @XX%%x xxx - # o@@^^^ooo I^^ I^o ooo . x - # oo @^ IX I ^X @^ oo - # IX U . V IX - # V . . V - # - - # TODO Optimize: Godot 4 has lost the ability to update textures partially! - var fuck = tex.get_image() - fuck.blit_rect(im, src_rect, dst_pos) - tex.update(fuck) - diff --git a/addons/zylann.hterrain/util/xyz_format.gd b/addons/zylann.hterrain/util/xyz_format.gd deleted file mode 100644 index 86e4a1a..0000000 --- a/addons/zylann.hterrain/util/xyz_format.gd +++ /dev/null @@ -1,109 +0,0 @@ -@tool - -# XYZ files are text files containing a list of 3D points. -# They can be found in GIS software as an export format for heightmaps. -# In order to turn it into a heightmap we may calculate bounds first -# to find the origin and then set points in an image. - - -class HT_XYZBounds: - # Note: it is important for these to be double-precision floats, - # GIS data can have large coordinates - var min_x := 0.0 - var min_y := 0.0 - - var max_x := 0.0 - var max_y := 0.0 - - var line_count := 0 - - var image_width := 0 - var image_height := 0 - - -# TODO `split_float` returns 32-bit floats, despite internally parsing doubles... -# Despite that, I still use it here because it doesn't seem to cause issues and is faster. -# If it becomes an issue, we'll have to switch to `split` and casting to `float`. - -static func load_bounds(f: FileAccess) -> HT_XYZBounds: - # It is faster to get line and split floats than using CSV functions - var line := f.get_line() - var floats := line.split_floats(" ") - - # We only care about X and Y, it makes less operations to do in the loop. - # Z is the height and will remain as-is at the end. - var min_pos_x := floats[0] - var min_pos_y := floats[1] - - var max_pos_x := min_pos_x - var max_pos_y := min_pos_y - - # Start at 1 because we just read the first line - var line_count := 1 - - # We know the file is a series of float triplets - while not f.eof_reached(): - line = f.get_line() - - # The last line can be empty - if len(line) < 2: - break - - floats = line.split_floats(" ") - - var pos_x := floats[0] - var pos_y := floats[1] - - min_pos_x = minf(min_pos_x, pos_x) - min_pos_y = minf(min_pos_y, pos_y) - - max_pos_x = maxf(max_pos_x, pos_x) - max_pos_y = maxf(max_pos_y, pos_y) - - line_count += 1 - - var bounds := HT_XYZBounds.new() - bounds.min_x = min_pos_x - bounds.min_y = min_pos_y - bounds.max_x = max_pos_x - bounds.max_y = max_pos_y - bounds.line_count = line_count - bounds.image_width = int(max_pos_x - min_pos_x) + 1 - bounds.image_height = int(max_pos_y - min_pos_y) + 1 - return bounds - - -# Loads points into an image with existing dimensions and format. -# `f` must be positioned at the beginning of the series of points. -# If `bounds` is `null`, it will be computed. -static func load_heightmap(f: FileAccess, dst_image: Image, bounds: HT_XYZBounds): - # We are not going to read the entire file directly in memory, because it can be really big. - # Instead we'll parse it directly and the only thing we retain in memory is the heightmap. - # This can be really slow on big files. If we can assume the file is square and points - # separated by 1 unit each in a grid pattern, it could be a bit faster, but - # parsing points from text really is the main bottleneck (40 seconds to load a 2000x2000 file!). - - # Bounds can be precalculated - if bounds == null: - var file_begin := f.get_position() - bounds = load_bounds(f) - f.seek(file_begin) - - # Put min coordinates on the GDScript stack so they are faster to access - var min_pos_x := bounds.min_x - var min_pos_y := bounds.min_y - var line_count := bounds.line_count - - for i in line_count: - var line := f.get_line() - var floats := line.split_floats(" ") - var x := int(floats[0] - min_pos_x) - var y := int(floats[1] - min_pos_y) - - # Make sure the coordinate is inside the image, - # due to float imprecision or potentially non-grid-aligned points. - # Could use `Rect2` to check faster but it uses floats. - # `Rect2i` would be better but is only available in Godot 4. - if x >= 0 and y >= 0 and x < dst_image.get_width() and y < dst_image.get_height(): - dst_image.set_pixel(x, y, Color(floats[2], 0, 0)) - diff --git a/asset/models/decorations/asset_Jalan_Batu_1.res b/asset/models/decorations/asset_Jalan_Batu_1.res index bd296d2..fa41e60 100644 Binary files a/asset/models/decorations/asset_Jalan_Batu_1.res and b/asset/models/decorations/asset_Jalan_Batu_1.res differ diff --git a/asset/models/decorations/asset_Jalan_Batu_2.res b/asset/models/decorations/asset_Jalan_Batu_2.res index 900815a..61e70a5 100644 Binary files a/asset/models/decorations/asset_Jalan_Batu_2.res and b/asset/models/decorations/asset_Jalan_Batu_2.res differ diff --git a/asset/models/decorations/asset_Jalan_Batu_3.res b/asset/models/decorations/asset_Jalan_Batu_3.res index 68b8e8b..f355d78 100644 Binary files a/asset/models/decorations/asset_Jalan_Batu_3.res and b/asset/models/decorations/asset_Jalan_Batu_3.res differ diff --git a/asset/models/decorations/asset_Jalan_Batu_4.res b/asset/models/decorations/asset_Jalan_Batu_4.res index fda30f9..75abf0e 100644 Binary files a/asset/models/decorations/asset_Jalan_Batu_4.res and b/asset/models/decorations/asset_Jalan_Batu_4.res differ diff --git a/asset/models/decorations/asset_Jalan_Batu_5.res b/asset/models/decorations/asset_Jalan_Batu_5.res index 7dd8d8e..b5d2b96 100644 Binary files a/asset/models/decorations/asset_Jalan_Batu_5.res and b/asset/models/decorations/asset_Jalan_Batu_5.res differ diff --git a/asset/models/decorations/asset_Pagar_1.res b/asset/models/decorations/asset_Pagar_1.res index 565b656..015e39c 100644 Binary files a/asset/models/decorations/asset_Pagar_1.res and b/asset/models/decorations/asset_Pagar_1.res differ diff --git a/asset/models/decorations/asset_Pagar_2.res b/asset/models/decorations/asset_Pagar_2.res index 25b9b0c..65e85c1 100644 Binary files a/asset/models/decorations/asset_Pagar_2.res and b/asset/models/decorations/asset_Pagar_2.res differ diff --git a/asset/models/decorations/asset_Pinus_1.res b/asset/models/decorations/asset_Pinus_1.res index 153ac6d..9decfff 100644 Binary files a/asset/models/decorations/asset_Pinus_1.res and b/asset/models/decorations/asset_Pinus_1.res differ diff --git a/asset/models/decorations/asset_Pinus_2.res b/asset/models/decorations/asset_Pinus_2.res index fe9b0ad..3d9c0fa 100644 Binary files a/asset/models/decorations/asset_Pinus_2.res and b/asset/models/decorations/asset_Pinus_2.res differ diff --git a/asset/models/decorations/asset_Pinus_3.res b/asset/models/decorations/asset_Pinus_3.res index 81a97ed..0bd94af 100644 Binary files a/asset/models/decorations/asset_Pinus_3.res and b/asset/models/decorations/asset_Pinus_3.res differ diff --git a/asset/models/decorations/asset_Pinus_4.res b/asset/models/decorations/asset_Pinus_4.res index adc7231..5a3cba0 100644 Binary files a/asset/models/decorations/asset_Pinus_4.res and b/asset/models/decorations/asset_Pinus_4.res differ diff --git a/asset/models/decorations/asset_Pinus_5.res b/asset/models/decorations/asset_Pinus_5.res index 014f0e2..fd4a9bf 100644 Binary files a/asset/models/decorations/asset_Pinus_5.res and b/asset/models/decorations/asset_Pinus_5.res differ diff --git a/asset/models/decorations/asset_Pohon_1.res b/asset/models/decorations/asset_Pohon_1.res index e5165ce..71a4f97 100644 Binary files a/asset/models/decorations/asset_Pohon_1.res and b/asset/models/decorations/asset_Pohon_1.res differ diff --git a/asset/models/decorations/asset_Pohon_2.res b/asset/models/decorations/asset_Pohon_2.res index 35d9e79..d38a31e 100644 Binary files a/asset/models/decorations/asset_Pohon_2.res and b/asset/models/decorations/asset_Pohon_2.res differ diff --git a/asset/models/decorations/asset_Pohon_3.res b/asset/models/decorations/asset_Pohon_3.res index 2952c87..f38ed70 100644 Binary files a/asset/models/decorations/asset_Pohon_3.res and b/asset/models/decorations/asset_Pohon_3.res differ diff --git a/asset/models/decorations/asset_Rumah_1.res b/asset/models/decorations/asset_Rumah_1.res index 68163e5..0741466 100644 Binary files a/asset/models/decorations/asset_Rumah_1.res and b/asset/models/decorations/asset_Rumah_1.res differ diff --git a/asset/models/decorations/asset_Rumah_2.res b/asset/models/decorations/asset_Rumah_2.res index 5e404ae..8bab8fb 100644 Binary files a/asset/models/decorations/asset_Rumah_2.res and b/asset/models/decorations/asset_Rumah_2.res differ diff --git a/asset/models/decorations/asset_Rumah_3.res b/asset/models/decorations/asset_Rumah_3.res index 74563ca..7e9309a 100644 Binary files a/asset/models/decorations/asset_Rumah_3.res and b/asset/models/decorations/asset_Rumah_3.res differ diff --git a/asset/models/decorations/asset_Rumah_4.res b/asset/models/decorations/asset_Rumah_4.res index 981bcf8..d5a629d 100644 Binary files a/asset/models/decorations/asset_Rumah_4.res and b/asset/models/decorations/asset_Rumah_4.res differ diff --git a/asset/models/decorations/asset_Rumah_5.res b/asset/models/decorations/asset_Rumah_5.res index c40596c..1bde714 100644 Binary files a/asset/models/decorations/asset_Rumah_5.res and b/asset/models/decorations/asset_Rumah_5.res differ diff --git a/asset/models/decorations/asset_Rumput_1.res b/asset/models/decorations/asset_Rumput_1.res index 21e138c..4adc4b0 100644 Binary files a/asset/models/decorations/asset_Rumput_1.res and b/asset/models/decorations/asset_Rumput_1.res differ diff --git a/asset/models/decorations/asset_Rumput_2.res b/asset/models/decorations/asset_Rumput_2.res index d1ade18..9b7aa2b 100644 Binary files a/asset/models/decorations/asset_Rumput_2.res and b/asset/models/decorations/asset_Rumput_2.res differ diff --git a/asset/models/decorations/asset_Rumput_3.res b/asset/models/decorations/asset_Rumput_3.res index baf127d..e220f5d 100644 Binary files a/asset/models/decorations/asset_Rumput_3.res and b/asset/models/decorations/asset_Rumput_3.res differ diff --git a/asset/models/decorations/asset_Rumput_4.res b/asset/models/decorations/asset_Rumput_4.res index 8daffa1..5efdd0b 100644 Binary files a/asset/models/decorations/asset_Rumput_4.res and b/asset/models/decorations/asset_Rumput_4.res differ diff --git a/asset/models/decorations/asset_Sumur.res b/asset/models/decorations/asset_Sumur.res index c481cdd..12e86f8 100644 Binary files a/asset/models/decorations/asset_Sumur.res and b/asset/models/decorations/asset_Sumur.res differ diff --git a/asset/models/maps/TsunamiMap.res b/asset/models/maps/TsunamiMap.res index 77d2442..62358db 100644 Binary files a/asset/models/maps/TsunamiMap.res and b/asset/models/maps/TsunamiMap.res differ diff --git a/project.godot b/project.godot index 7e3e37c..8aaf7c4 100644 --- a/project.godot +++ b/project.godot @@ -8,81 +8,16 @@ config_version=5 -[addons] - -m_terrain/keymap/mterrain_brush_size_increase=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":93,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_brush_size_decrease=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":91,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_mask_size_increase=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":46,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_mask_size_decrease=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":44,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_mask_rotate_clockwise=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":76,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_mask_rotate_counter_clockwise=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":75,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_mask_rotation_reset=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":59,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_walk_forward=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":87,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_walk_backward=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_walk_left=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":65,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mterrain_walk_right=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":68,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_toggle_mode=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":96,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_toggle_mirror=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":77,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_toggle_mirror_length=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":76,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_validate=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":80,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_select_linked=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":76,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_swap_points=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":84,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_toggle_connection=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":84,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_remove_point=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":4194308,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_disconnect_point=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":66,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_connect_point=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":67,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_tilt_mode=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":82,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_scale_mode=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":75,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_lock_zy=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":88,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_lock_xz=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":89,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_lock_xy=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":90,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_lock_x=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":88,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_lock_y=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":89,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - -m_terrain/keymap/mpath_lock_z=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":90,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) - - [application] config/name="Disaster Game" -<<<<<<< HEAD -run/main_scene="res://scenes/Forest/Forest.tscn" -======= run/main_scene="res://scenes/main_menu.tscn" ->>>>>>> 4c02366fff70e4ab7406cb60d2c2e66a1e7eec42 config/features=PackedStringArray("4.2", "Mobile") config/icon="res://icon.svg" [editor_plugins] -enabled=PackedStringArray("res://addons/m_terrain/plugin.cfg", "res://addons/proton_scatter/plugin.cfg", "res://addons/zylann.hterrain/plugin.cfg") +enabled=PackedStringArray("res://addons/proton_scatter/plugin.cfg") [input]