Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions project/addons/terrain_3d/menu/menu_ui.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
# This is the start of the new UI for Terrain3D with all tools integrated.

@tool
extends Control


var terrain: Terrain3D
var show_pending: bool = true


func _ready() -> void:
%Close.pressed.connect(_on_close)
%TextureStartBtn.pressed.connect(_on_texture_start)
if not show_pending:
%Baking.queue_free()
%TexturePacking.queue_free()
%Import.queue_free()
%Export.queue_free()


func _on_close() -> void:
queue_free()


func _on_texture_start() -> void:
var process_arr: Array
var msg: String
%TextureStatus.visible = true
%TextureStatus.add_theme_color_override("font_color", Color.WHITE)

if %SrcID1.value != %DestID1.value:
process_arr.push_back([%SrcID1.value, %DestID1.value] as Array[int])
msg += "Changing texture ID %d to %d.\n" % [ %SrcID1.value, %DestID1.value ]
if %SrcID2.value != %DestID2.value:
process_arr.push_back([%SrcID2.value, %DestID2.value] as Array[int])
msg += "Changing texture ID %d to %d.\n" % [ %SrcID2.value, %DestID2.value ]
if %SrcID3.value != %DestID3.value:
process_arr.push_back([%SrcID3.value, %DestID3.value] as Array[int])
msg += "Changing texture ID %d to %d.\n" % [ %SrcID3.value, %DestID3.value ]
if process_arr.is_empty():
msg = "No changes specified. Nothing to do."
print(msg)
%TextureStatus.text = msg + "\n"
%TextureStatus.add_theme_color_override("font_color", Color.RED)
return

msg += "Starting..."
print(msg)
%TextureStatus.text = msg + "\n"
await RenderingServer.frame_post_draw

# Mask to clear base_id and over_id bits
var clear_mask: int = ~(0x1F << 27 | 0x1F << 22)
var util := Terrain3DUtil.new()

for region: Terrain3DRegion in terrain.data.get_regions_all().values():
var map: Image = region.control_map
var modified: bool = false
for x: int in map.get_width():
for y: int in map.get_height():
var control: int = util.as_uint(map.get_pixel(x, y).r)
var base_id: int = util.get_base(control)
var over_id: int = util.get_overlay(control)
for tuple: Array[int] in process_arr:
if base_id == tuple[0]:
base_id = tuple[1]
modified = true
if over_id == tuple[0]:
over_id = tuple[1]
modified = true

if modified:
# Preserve bits 1-22, clear bits 23-32, set new base_id and over_id
control = (control & clear_mask) | ((base_id & 0x1F) << 27) | ((over_id & 0x1F) << 22)
map.set_pixel(x, y, Color(util.as_float(control), 0., 0., 1.))

msg = "Processed region: %.0v" % [ region.get_location() ]
if modified:
region.set_modified(true)
msg += ", modified"
%TextureStatus.text += msg + "\n"
print(msg)
%Scroll.scroll_vertical += 50
await RenderingServer.frame_post_draw

terrain.data.update_maps(Terrain3DRegion.TYPE_CONTROL)
%TextureStatus.text += "Finished."
print("Finished.")
%Scroll.scroll_vertical += 50
%TextureStatus.add_theme_color_override("font_color", Color.GREEN)

1 change: 1 addition & 0 deletions project/addons/terrain_3d/menu/menu_ui.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://pkievxeb101w
212 changes: 212 additions & 0 deletions project/addons/terrain_3d/menu/menu_ui.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
[gd_scene load_steps=4 format=3 uid="uid://b5wxp6lton0et"]

[ext_resource type="Theme" uid="uid://bb2773v41h8r" path="res://addons/terrain_3d/menu/terrain3d_theme.tres" id="1_xbcvl"]
[ext_resource type="Script" uid="uid://pkievxeb101w" path="res://addons/terrain_3d/menu/menu_ui.gd" id="2_xbcvl"]

[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_uxh0t"]

[node name="MenuUI" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_xbcvl")
script = ExtResource("2_xbcvl")

[node name="Scroll" type="ScrollContainer" parent="."]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="Tabs" type="TabContainer" parent="Scroll"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
current_tab = 0
clip_tabs = false

[node name="TextureIDs" type="MarginContainer" parent="Scroll/Tabs"]
unique_name_in_owner = true
layout_mode = 2
metadata/_tab_index = 0

[node name="VBox" type="VBoxContainer" parent="Scroll/Tabs/TextureIDs"]
layout_mode = 2
size_flags_horizontal = 0

[node name="Header" type="Label" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 36
text = "Change Texture IDs"

[node name="SubHeader" type="Label" parent="Scroll/Tabs/TextureIDs/VBox"]
visible = false
layout_mode = 2
text = "This tool changes texture data on the currently selected terrain."

[node name="HSeparator" type="HSeparator" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2

[node name="Instructions" type="Label" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2
text = "This tool will look at every pixel in every region and all Base or Overlay IDs that match the source ID will be changed to the destination ID.

There is no undo, however you can reload your project without saving. Data is not written until you save.

1. Specify the source and destination texture IDs 0-31 from your Asset list.
2. Enter up to 2 more pairs if desired. Swap IDs in 3 steps with any unused ID (use 32 if all textures are used).
e.g. To swap 0 and 1, set 0 -> 32, 1 -> 0, 32 -> 1.
3. Click Process.
4. Close this panel and Save."

[node name="HSeparator2" type="HSeparator" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2
theme_override_constants/separation = 30
theme_override_styles/separator = SubResource("StyleBoxEmpty_uxh0t")

[node name="HBox1" type="HBoxContainer" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2

[node name="SrcLbl" type="Label" parent="Scroll/Tabs/TextureIDs/VBox/HBox1"]
layout_mode = 2
text = "1. Source ID: "

[node name="SrcID1" type="SpinBox" parent="Scroll/Tabs/TextureIDs/VBox/HBox1"]
unique_name_in_owner = true
layout_mode = 2
max_value = 32.0

[node name="VSeparator" type="VSeparator" parent="Scroll/Tabs/TextureIDs/VBox/HBox1"]
layout_mode = 2
theme_override_constants/separation = 20
theme_override_styles/separator = SubResource("StyleBoxEmpty_uxh0t")

[node name="DestLbl" type="Label" parent="Scroll/Tabs/TextureIDs/VBox/HBox1"]
layout_mode = 2
text = "Destination ID: "

[node name="DestID1" type="SpinBox" parent="Scroll/Tabs/TextureIDs/VBox/HBox1"]
unique_name_in_owner = true
layout_mode = 2
max_value = 32.0

[node name="HBox2" type="HBoxContainer" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2

[node name="SrcLbl" type="Label" parent="Scroll/Tabs/TextureIDs/VBox/HBox2"]
layout_mode = 2
text = "2. Source ID: "

[node name="SrcID2" type="SpinBox" parent="Scroll/Tabs/TextureIDs/VBox/HBox2"]
unique_name_in_owner = true
layout_mode = 2
max_value = 32.0

[node name="VSeparator" type="VSeparator" parent="Scroll/Tabs/TextureIDs/VBox/HBox2"]
layout_mode = 2
theme_override_constants/separation = 20
theme_override_styles/separator = SubResource("StyleBoxEmpty_uxh0t")

[node name="DestLbl" type="Label" parent="Scroll/Tabs/TextureIDs/VBox/HBox2"]
layout_mode = 2
text = "Destination ID: "

[node name="DestID2" type="SpinBox" parent="Scroll/Tabs/TextureIDs/VBox/HBox2"]
unique_name_in_owner = true
layout_mode = 2
max_value = 32.0

[node name="HBox3" type="HBoxContainer" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2

[node name="SrcLbl" type="Label" parent="Scroll/Tabs/TextureIDs/VBox/HBox3"]
layout_mode = 2
text = "3. Source ID: "

[node name="SrcID3" type="SpinBox" parent="Scroll/Tabs/TextureIDs/VBox/HBox3"]
unique_name_in_owner = true
layout_mode = 2
max_value = 32.0

[node name="VSeparator" type="VSeparator" parent="Scroll/Tabs/TextureIDs/VBox/HBox3"]
layout_mode = 2
theme_override_constants/separation = 20
theme_override_styles/separator = SubResource("StyleBoxEmpty_uxh0t")

[node name="DestLbl" type="Label" parent="Scroll/Tabs/TextureIDs/VBox/HBox3"]
layout_mode = 2
text = "Destination ID: "

[node name="DestID3" type="SpinBox" parent="Scroll/Tabs/TextureIDs/VBox/HBox3"]
unique_name_in_owner = true
layout_mode = 2
max_value = 32.0

[node name="HSeparator3" type="HSeparator" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2
theme_override_constants/separation = 30
theme_override_styles/separator = SubResource("StyleBoxEmpty_uxh0t")

[node name="TextureStartBtn" type="Button" parent="Scroll/Tabs/TextureIDs/VBox"]
unique_name_in_owner = true
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
size_flags_horizontal = 0
text = "Process"

[node name="HSeparator4" type="HSeparator" parent="Scroll/Tabs/TextureIDs/VBox"]
layout_mode = 2
theme_override_constants/separation = 30
theme_override_styles/separator = SubResource("StyleBoxEmpty_uxh0t")

[node name="TextureStatus" type="Label" parent="Scroll/Tabs/TextureIDs/VBox"]
unique_name_in_owner = true
visible = false
layout_mode = 2
text = "Finished"

[node name="Baking" type="MarginContainer" parent="Scroll/Tabs"]
unique_name_in_owner = true
visible = false
layout_mode = 2
metadata/_tab_index = 1

[node name="Texture Packing" type="MarginContainer" parent="Scroll/Tabs"]
unique_name_in_owner = true
visible = false
layout_mode = 2
metadata/_tab_index = 2

[node name="Import" type="MarginContainer" parent="Scroll/Tabs"]
unique_name_in_owner = true
visible = false
layout_mode = 2
metadata/_tab_index = 3

[node name="Export" type="MarginContainer" parent="Scroll/Tabs"]
unique_name_in_owner = true
visible = false
layout_mode = 2
metadata/_tab_index = 4

[node name="Margin" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -50.0
offset_bottom = 31.0
grow_horizontal = 0
theme_override_constants/margin_left = 0
theme_override_constants/margin_bottom = 0

[node name="Close" type="Button" parent="Margin"]
unique_name_in_owner = true
layout_mode = 2
text = "Close"
Loading