575 lines
21 KiB
GDScript
575 lines
21 KiB
GDScript
# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
|
|
# UI for Terrain3D
|
|
extends Node
|
|
|
|
|
|
# Includes
|
|
const TerrainMenu: Script = preload("res://addons/terrain_3d/menu/terrain_menu.gd")
|
|
const Toolbar: Script = preload("res://addons/terrain_3d/src/toolbar.gd")
|
|
const ToolSettings: Script = preload("res://addons/terrain_3d/src/tool_settings.gd")
|
|
const OperationBuilder: Script = preload("res://addons/terrain_3d/src/operation_builder.gd")
|
|
const GradientOperationBuilder: Script = preload("res://addons/terrain_3d/src/gradient_operation_builder.gd")
|
|
const COLOR_RAISE := Color.WHITE
|
|
const COLOR_LOWER := Color.BLACK
|
|
const COLOR_SMOOTH := Color(0.5, 0, .2)
|
|
const COLOR_LIFT := Color.ORANGE
|
|
const COLOR_FLATTEN := Color.BLUE_VIOLET
|
|
const COLOR_HEIGHT := Color(0., 0.32, .4)
|
|
const COLOR_SLOPE := Color.YELLOW
|
|
const COLOR_PAINT := Color.DARK_GREEN
|
|
const COLOR_SPRAY := Color.PALE_GREEN
|
|
const COLOR_ROUGHNESS := Color.ROYAL_BLUE
|
|
const COLOR_AUTOSHADER := Color.DODGER_BLUE
|
|
const COLOR_HOLES := Color.BLACK
|
|
const COLOR_NAVIGATION := Color(.28, .0, .25)
|
|
const COLOR_INSTANCER := Color.CRIMSON
|
|
const COLOR_PICK_COLOR := Color.WHITE
|
|
const COLOR_PICK_HEIGHT := Color.DARK_RED
|
|
const COLOR_PICK_ROUGH := Color.ROYAL_BLUE
|
|
|
|
const OP_NONE: int = 0x0
|
|
const OP_POSITIVE_ONLY: int = 0x01
|
|
const OP_NEGATIVE_ONLY: int = 0x02
|
|
|
|
const RING1: String = "res://addons/terrain_3d/brushes/ring1.exr"
|
|
var ring_texture : ImageTexture
|
|
@onready var region_texture := ImageTexture.new() :
|
|
set(value):
|
|
var image: Image = Image.create_empty(1, 1, false, Image.FORMAT_R8)
|
|
image.fill(Color.WHITE)
|
|
value.create_from_image(image)
|
|
region_texture = value
|
|
var plugin: EditorPlugin # Actually Terrain3DEditorPlugin, but Godot still has CRC errors
|
|
var toolbar: Toolbar
|
|
var tool_settings: ToolSettings
|
|
var terrain_menu: TerrainMenu
|
|
var setting_has_changed: bool = false
|
|
var visible: bool = false
|
|
var picking: int = Terrain3DEditor.TOOL_MAX
|
|
var picking_callback: Callable
|
|
var brush_data: Dictionary
|
|
var operation_builder: OperationBuilder
|
|
var last_tool: Terrain3DEditor.Tool
|
|
var last_operation: Terrain3DEditor.Operation
|
|
var last_rmb_time: int = 0 # Set in editor.gd
|
|
|
|
# Editor decals, indices; 0 = main brush, 1 = slope point A, 2 = slope point B
|
|
var mat_rid: RID
|
|
var editor_decal_position: Array[Vector2] = [Vector2(), Vector2(), Vector2()]
|
|
var editor_decal_rotation: Array[float] = [float(), float(), float()]
|
|
var editor_decal_size: Array[float] = [float(), float(), float()]
|
|
var editor_decal_color: Array[Color] = [Color(), Color(), Color()]
|
|
var editor_decal_visible: Array[bool] = [bool(), bool(), bool()]
|
|
var editor_brush_texture_rid: RID = RID()
|
|
var editor_decal_timer: Timer
|
|
var editor_decal_fade: float :
|
|
set(value):
|
|
editor_decal_fade = value
|
|
if editor_decal_color.size() > 0:
|
|
editor_decal_color[0].a = value
|
|
if is_shader_valid():
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_color", editor_decal_color)
|
|
if value < 0.001:
|
|
var r_map: PackedInt32Array = plugin.terrain.data.get_region_map()
|
|
RenderingServer.material_set_param(mat_rid, "_region_map", r_map)
|
|
var editor_ring_texture_rid: RID
|
|
|
|
|
|
func _enter_tree() -> void:
|
|
toolbar = Toolbar.new()
|
|
toolbar.hide()
|
|
toolbar.tool_changed.connect(_on_tool_changed)
|
|
|
|
tool_settings = ToolSettings.new()
|
|
tool_settings.setting_changed.connect(_on_setting_changed)
|
|
tool_settings.picking.connect(_on_picking)
|
|
tool_settings.plugin = plugin
|
|
tool_settings.hide()
|
|
|
|
terrain_menu = TerrainMenu.new()
|
|
terrain_menu.plugin = plugin
|
|
terrain_menu.hide()
|
|
|
|
plugin.add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, toolbar)
|
|
plugin.add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_BOTTOM, tool_settings)
|
|
plugin.add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, terrain_menu)
|
|
|
|
_on_tool_changed(Terrain3DEditor.REGION, Terrain3DEditor.ADD)
|
|
|
|
editor_decal_timer = Timer.new()
|
|
editor_decal_timer.wait_time = .5
|
|
editor_decal_timer.one_shot = true
|
|
editor_decal_timer.timeout.connect(func():
|
|
get_tree().create_tween().tween_property(self, "editor_decal_fade", 0.0, 0.15))
|
|
add_child(editor_decal_timer)
|
|
|
|
|
|
func _ready() -> void:
|
|
var img: Image = Image.load_from_file(RING1)
|
|
img.convert(Image.FORMAT_R8)
|
|
ring_texture = ImageTexture.create_from_image(img)
|
|
editor_ring_texture_rid = ring_texture.get_rid()
|
|
|
|
|
|
func _exit_tree() -> void:
|
|
plugin.remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, toolbar)
|
|
plugin.remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_BOTTOM, tool_settings)
|
|
toolbar.queue_free()
|
|
tool_settings.queue_free()
|
|
terrain_menu.queue_free()
|
|
editor_decal_timer.queue_free()
|
|
|
|
|
|
func set_visible(p_visible: bool, p_menu_only: bool = false) -> void:
|
|
terrain_menu.set_visible(p_visible)
|
|
|
|
if p_menu_only:
|
|
toolbar.set_visible(false)
|
|
tool_settings.set_visible(false)
|
|
else:
|
|
visible = p_visible
|
|
toolbar.set_visible(p_visible)
|
|
tool_settings.set_visible(p_visible)
|
|
update_decal()
|
|
|
|
if(plugin.editor):
|
|
if(p_visible):
|
|
await get_tree().create_timer(.01).timeout # Won't work, otherwise
|
|
_on_tool_changed(last_tool, last_operation)
|
|
else:
|
|
plugin.editor.set_tool(Terrain3DEditor.TOOL_MAX)
|
|
plugin.editor.set_operation(Terrain3DEditor.OP_MAX)
|
|
|
|
|
|
func set_menu_visibility(p_list: Control, p_visible: bool) -> void:
|
|
if p_list:
|
|
p_list.get_parent().get_parent().visible = p_visible
|
|
|
|
|
|
func _on_tool_changed(p_tool: Terrain3DEditor.Tool, p_operation: Terrain3DEditor.Operation) -> void:
|
|
clear_picking()
|
|
set_menu_visibility(tool_settings.advanced_list, true)
|
|
set_menu_visibility(tool_settings.scale_list, false)
|
|
set_menu_visibility(tool_settings.rotation_list, false)
|
|
set_menu_visibility(tool_settings.height_list, false)
|
|
set_menu_visibility(tool_settings.color_list, false)
|
|
|
|
# Select which settings to show. Options in tool_settings.gd:_ready
|
|
var to_show: PackedStringArray = []
|
|
|
|
match p_tool:
|
|
Terrain3DEditor.REGION:
|
|
to_show.push_back("instructions")
|
|
to_show.push_back("remove")
|
|
set_menu_visibility(tool_settings.advanced_list, false)
|
|
|
|
Terrain3DEditor.SCULPT:
|
|
to_show.push_back("brush")
|
|
to_show.push_back("size")
|
|
to_show.push_back("strength")
|
|
if p_operation in [Terrain3DEditor.ADD, Terrain3DEditor.SUBTRACT]:
|
|
to_show.push_back("remove")
|
|
elif p_operation == Terrain3DEditor.GRADIENT:
|
|
to_show.push_back("gradient_points")
|
|
to_show.push_back("drawable")
|
|
|
|
Terrain3DEditor.HEIGHT:
|
|
to_show.push_back("brush")
|
|
to_show.push_back("size")
|
|
to_show.push_back("strength")
|
|
to_show.push_back("height")
|
|
to_show.push_back("height_picker")
|
|
|
|
Terrain3DEditor.TEXTURE:
|
|
to_show.push_back("brush")
|
|
to_show.push_back("size")
|
|
to_show.push_back("enable_texture")
|
|
if p_operation == Terrain3DEditor.ADD:
|
|
to_show.push_back("strength")
|
|
to_show.push_back("slope")
|
|
to_show.push_back("enable_angle")
|
|
to_show.push_back("angle")
|
|
to_show.push_back("angle_picker")
|
|
to_show.push_back("dynamic_angle")
|
|
to_show.push_back("enable_scale")
|
|
to_show.push_back("scale")
|
|
to_show.push_back("scale_picker")
|
|
|
|
Terrain3DEditor.COLOR:
|
|
to_show.push_back("brush")
|
|
to_show.push_back("size")
|
|
to_show.push_back("strength")
|
|
to_show.push_back("color")
|
|
to_show.push_back("color_picker")
|
|
to_show.push_back("slope")
|
|
to_show.push_back("texture_filter")
|
|
to_show.push_back("margin")
|
|
to_show.push_back("remove")
|
|
|
|
Terrain3DEditor.ROUGHNESS:
|
|
to_show.push_back("brush")
|
|
to_show.push_back("size")
|
|
to_show.push_back("strength")
|
|
to_show.push_back("roughness")
|
|
to_show.push_back("roughness_picker")
|
|
to_show.push_back("slope")
|
|
to_show.push_back("texture_filter")
|
|
to_show.push_back("margin")
|
|
to_show.push_back("remove")
|
|
|
|
Terrain3DEditor.AUTOSHADER, Terrain3DEditor.HOLES, Terrain3DEditor.NAVIGATION:
|
|
to_show.push_back("brush")
|
|
to_show.push_back("size")
|
|
to_show.push_back("remove")
|
|
|
|
Terrain3DEditor.INSTANCER:
|
|
to_show.push_back("size")
|
|
to_show.push_back("strength")
|
|
to_show.push_back("slope")
|
|
set_menu_visibility(tool_settings.height_list, true)
|
|
to_show.push_back("height_offset")
|
|
to_show.push_back("random_height")
|
|
set_menu_visibility(tool_settings.scale_list, true)
|
|
to_show.push_back("fixed_scale")
|
|
to_show.push_back("random_scale")
|
|
set_menu_visibility(tool_settings.rotation_list, true)
|
|
to_show.push_back("fixed_spin")
|
|
to_show.push_back("random_spin")
|
|
to_show.push_back("fixed_tilt")
|
|
to_show.push_back("random_tilt")
|
|
to_show.push_back("align_to_normal")
|
|
set_menu_visibility(tool_settings.color_list, true)
|
|
to_show.push_back("vertex_color")
|
|
to_show.push_back("random_darken")
|
|
to_show.push_back("random_hue")
|
|
to_show.push_back("remove")
|
|
|
|
_:
|
|
pass
|
|
|
|
# Advanced menu settings
|
|
to_show.push_back("auto_regions")
|
|
to_show.push_back("align_to_view")
|
|
to_show.push_back("show_cursor_while_painting")
|
|
to_show.push_back("gamma")
|
|
to_show.push_back("jitter")
|
|
to_show.push_back("crosshair_threshold")
|
|
tool_settings.show_settings(to_show)
|
|
|
|
operation_builder = null
|
|
if p_operation == Terrain3DEditor.GRADIENT:
|
|
operation_builder = GradientOperationBuilder.new()
|
|
operation_builder.tool_settings = tool_settings
|
|
|
|
if plugin.editor:
|
|
plugin.editor.set_tool(p_tool)
|
|
plugin.editor.set_operation(_modify_operation(p_operation))
|
|
last_tool = p_tool
|
|
last_operation = p_operation
|
|
|
|
_on_setting_changed()
|
|
plugin.update_region_grid()
|
|
|
|
|
|
func _on_setting_changed() -> void:
|
|
if not plugin.asset_dock:
|
|
return
|
|
brush_data = tool_settings.get_settings()
|
|
brush_data["asset_id"] = plugin.asset_dock.get_current_list().get_selected_id()
|
|
plugin.editor.set_brush_data(brush_data)
|
|
plugin.editor.set_operation(_modify_operation(plugin.editor.get_operation()))
|
|
update_decal()
|
|
|
|
|
|
func update_modifiers() -> void:
|
|
toolbar.show_add_buttons(not plugin.modifier_ctrl)
|
|
|
|
if plugin.modifier_shift and not plugin.modifier_ctrl:
|
|
plugin.editor.set_tool(Terrain3DEditor.SCULPT)
|
|
plugin.editor.set_operation(Terrain3DEditor.AVERAGE)
|
|
else:
|
|
plugin.editor.set_tool(last_tool)
|
|
if plugin.modifier_ctrl:
|
|
plugin.editor.set_operation(_modify_operation(last_operation))
|
|
else:
|
|
plugin.editor.set_operation(last_operation)
|
|
|
|
|
|
func _modify_operation(p_operation: Terrain3DEditor.Operation) -> Terrain3DEditor.Operation:
|
|
var remove_checked: bool = false
|
|
if DisplayServer.is_touchscreen_available():
|
|
var removable_tools := [Terrain3DEditor.REGION, Terrain3DEditor.SCULPT, Terrain3DEditor.HEIGHT, Terrain3DEditor.AUTOSHADER,
|
|
Terrain3DEditor.HOLES, Terrain3DEditor.INSTANCER, Terrain3DEditor.NAVIGATION,
|
|
Terrain3DEditor.COLOR, Terrain3DEditor.ROUGHNESS]
|
|
remove_checked = brush_data.get("remove", false) && plugin.editor.get_tool() in removable_tools
|
|
|
|
if plugin.modifier_ctrl or remove_checked:
|
|
return _invert_operation(p_operation, OP_NEGATIVE_ONLY)
|
|
return _invert_operation(p_operation, OP_POSITIVE_ONLY)
|
|
|
|
|
|
func _invert_operation(p_operation: Terrain3DEditor.Operation, flags: int = OP_NONE) -> Terrain3DEditor.Operation:
|
|
if p_operation == Terrain3DEditor.ADD and ! (flags & OP_POSITIVE_ONLY):
|
|
return Terrain3DEditor.SUBTRACT
|
|
elif p_operation == Terrain3DEditor.SUBTRACT and ! (flags & OP_NEGATIVE_ONLY):
|
|
return Terrain3DEditor.ADD
|
|
return p_operation
|
|
|
|
|
|
func update_decal() -> void:
|
|
if not plugin.terrain or brush_data.size() <= 3:
|
|
return
|
|
mat_rid = plugin.terrain.material.get_material_rid()
|
|
editor_decal_timer.start()
|
|
|
|
# If not a state that should show the decal, hide everything and return
|
|
if not visible or \
|
|
plugin._input_mode < 0 or \
|
|
# Wait for cursor to recenter after moving camera before revealing
|
|
# See https://github.com/godotengine/godot/issues/70098
|
|
Time.get_ticks_msec() - last_rmb_time <= 30 or \
|
|
(plugin._input_mode > 0 and not brush_data["show_cursor_while_painting"]):
|
|
hide_decal()
|
|
return
|
|
|
|
reset_decal_arrays()
|
|
editor_decal_position[0] = Vector2(plugin.mouse_global_position.x, plugin.mouse_global_position.z)
|
|
editor_decal_visible[0] = true
|
|
# Set region size, and modify region map for none background mode.
|
|
var r_map: PackedInt32Array = plugin.terrain.data.get_region_map()
|
|
if plugin.editor.get_tool() == Terrain3DEditor.REGION:
|
|
var r_size: float = float(plugin.terrain.get_region_size()) * plugin.terrain.get_vertex_spacing()
|
|
var map_size: int = plugin.terrain.data.REGION_MAP_SIZE
|
|
var half_r_size: float = r_size * 0.5
|
|
var pos: Vector2 = (Vector2(plugin.mouse_global_position.x, plugin.mouse_global_position.z) +
|
|
Vector2(half_r_size, half_r_size)).snappedf(r_size) - Vector2(half_r_size, half_r_size)
|
|
editor_brush_texture_rid = region_texture.get_rid()
|
|
editor_decal_position[0] = pos
|
|
editor_decal_size[0] = r_size
|
|
editor_decal_rotation[0] = 0.0
|
|
|
|
var loc: Vector2i = plugin.terrain.data.get_region_location(plugin.mouse_global_position)
|
|
loc += Vector2i(map_size / 2, map_size / 2)
|
|
if !(loc.x < 0 or loc.x > map_size - 1 or loc.y < 0 or loc.y > map_size - 1):
|
|
var index: int = clampi(loc.y * map_size + loc.x, 0, map_size * map_size - 1)
|
|
if plugin.terrain.material.get_world_background() == Terrain3DMaterial.WorldBackground.NONE:
|
|
if r_map[index] == 0 and plugin.editor.get_operation() == Terrain3DEditor.ADD:
|
|
r_map[index] = -index - 1
|
|
else:
|
|
r_map[index] = r_map[index]
|
|
|
|
match plugin.editor.get_operation():
|
|
Terrain3DEditor.ADD:
|
|
if r_map[index] <= 0:
|
|
editor_decal_color[0] = Color.WHITE
|
|
editor_decal_color[0].a = 0.25
|
|
else:
|
|
hide_decal()
|
|
|
|
Terrain3DEditor.SUBTRACT:
|
|
if r_map[index] > 0:
|
|
editor_decal_color[0] = Color.WHITE * .15
|
|
editor_decal_color[0].a = 0.75
|
|
else:
|
|
hide_decal()
|
|
else:
|
|
hide_decal()
|
|
# Set texture and color
|
|
elif picking != Terrain3DEditor.TOOL_MAX:
|
|
editor_brush_texture_rid = ring_texture.get_rid()
|
|
editor_decal_size[0] = 10. * plugin.terrain.get_vertex_spacing()
|
|
match picking:
|
|
Terrain3DEditor.HEIGHT:
|
|
editor_decal_color[0] = COLOR_PICK_HEIGHT
|
|
Terrain3DEditor.COLOR:
|
|
editor_decal_color[0] = COLOR_PICK_COLOR
|
|
Terrain3DEditor.ROUGHNESS:
|
|
editor_decal_color[0] = COLOR_PICK_ROUGH
|
|
editor_decal_color[0].a = 1.0
|
|
else:
|
|
editor_brush_texture_rid = brush_data["brush"][1].get_rid()
|
|
editor_decal_size[0] = maxf(brush_data["size"], .5)
|
|
if brush_data["align_to_view"]:
|
|
var cam: Camera3D = plugin.terrain.get_camera();
|
|
if (cam):
|
|
editor_decal_rotation[0] = cam.rotation.y
|
|
else:
|
|
editor_decal_rotation[0] = 0.
|
|
match plugin.editor.get_tool():
|
|
Terrain3DEditor.SCULPT:
|
|
match plugin.editor.get_operation():
|
|
Terrain3DEditor.ADD:
|
|
if plugin.modifier_alt:
|
|
editor_decal_color[0] = COLOR_LIFT
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5)
|
|
else:
|
|
editor_decal_color[0] = COLOR_RAISE
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .25, .5)
|
|
Terrain3DEditor.SUBTRACT:
|
|
if plugin.modifier_alt:
|
|
editor_decal_color[0] = COLOR_FLATTEN
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .25, .5) + .1
|
|
else:
|
|
editor_decal_color[0] = COLOR_LOWER
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .25
|
|
Terrain3DEditor.AVERAGE:
|
|
editor_decal_color[0] = COLOR_SMOOTH
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .25
|
|
Terrain3DEditor.GRADIENT:
|
|
editor_decal_color[0] = COLOR_SLOPE
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .2, .4)
|
|
Terrain3DEditor.HEIGHT:
|
|
editor_decal_color[0] = COLOR_HEIGHT
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .25
|
|
Terrain3DEditor.TEXTURE:
|
|
match plugin.editor.get_operation():
|
|
Terrain3DEditor.REPLACE:
|
|
editor_decal_color[0] = COLOR_PAINT
|
|
editor_decal_color[0].a = .6
|
|
Terrain3DEditor.SUBTRACT:
|
|
editor_decal_color[0] = COLOR_PAINT
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .1
|
|
Terrain3DEditor.ADD:
|
|
editor_decal_color[0] = COLOR_SPRAY
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .15, .4)
|
|
Terrain3DEditor.COLOR:
|
|
editor_decal_color[0] = brush_data["color"].srgb_to_linear()
|
|
editor_decal_color[0].a *= clamp(brush_data["strength"], .2, .5)
|
|
Terrain3DEditor.ROUGHNESS:
|
|
editor_decal_color[0] = COLOR_ROUGHNESS
|
|
editor_decal_color[0].a = clamp(brush_data["strength"], .2, .5) + .1
|
|
Terrain3DEditor.AUTOSHADER:
|
|
editor_decal_color[0] = COLOR_AUTOSHADER
|
|
editor_decal_color[0].a = .6
|
|
Terrain3DEditor.HOLES:
|
|
editor_decal_color[0] = COLOR_HOLES
|
|
editor_decal_color[0].a = .75
|
|
Terrain3DEditor.NAVIGATION:
|
|
editor_decal_color[0] = COLOR_NAVIGATION
|
|
editor_decal_color[0].a = .80
|
|
Terrain3DEditor.INSTANCER:
|
|
editor_brush_texture_rid = ring_texture.get_rid()
|
|
editor_decal_color[0] = COLOR_INSTANCER
|
|
editor_decal_color[0].a = .75
|
|
|
|
editor_decal_visible[1] = false
|
|
editor_decal_visible[2] = false
|
|
|
|
if plugin.editor.get_operation() == Terrain3DEditor.GRADIENT:
|
|
var point1: Vector3 = brush_data["gradient_points"][0]
|
|
if point1 != Vector3.ZERO:
|
|
editor_decal_color[1] = COLOR_SLOPE
|
|
editor_decal_size[1] = 10. * plugin.terrain.get_vertex_spacing()
|
|
editor_decal_visible[1] = true
|
|
editor_decal_position[1] = Vector2(point1.x, point1.z)
|
|
var point2: Vector3 = brush_data["gradient_points"][1]
|
|
if point2 != Vector3.ZERO:
|
|
editor_decal_color[2] = COLOR_SLOPE
|
|
editor_decal_size[2] = 10. * plugin.terrain.get_vertex_spacing()
|
|
editor_decal_visible[2] = true
|
|
editor_decal_position[2] = Vector2(point2.x, point2.z)
|
|
|
|
if RenderingServer.get_current_rendering_method().contains("gl_compatibility"):
|
|
for i in editor_decal_color.size():
|
|
editor_decal_color[i].a = maxf(0.1, editor_decal_color[i].a - .25)
|
|
|
|
editor_decal_fade = editor_decal_color[0].a
|
|
# Update Shader params
|
|
if is_shader_valid():
|
|
RenderingServer.material_set_param(mat_rid, "_editor_brush_texture", editor_brush_texture_rid)
|
|
RenderingServer.material_set_param(mat_rid, "_editor_ring_texture", editor_ring_texture_rid)
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_position", editor_decal_position)
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_rotation", editor_decal_rotation)
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_size", editor_decal_size)
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_color", editor_decal_color)
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_visible", editor_decal_visible)
|
|
RenderingServer.material_set_param(mat_rid, "_editor_crosshair_threshold", brush_data["crosshair_threshold"] + 0.1)
|
|
RenderingServer.material_set_param(mat_rid, "_region_map", r_map)
|
|
|
|
|
|
func is_shader_valid() -> bool:
|
|
# As long as the compiled shader contains at least 1 uniform, we can use it to check
|
|
# if the shader compilation has failed, as this will then return an empty dictionary.
|
|
if not plugin.terrain:
|
|
return false
|
|
var params = RenderingServer.get_shader_parameter_list(plugin.terrain.material.get_shader_rid())
|
|
if params.is_empty():
|
|
return false
|
|
else:
|
|
return true
|
|
|
|
|
|
func hide_decal() -> void:
|
|
editor_decal_visible = [false, false, false]
|
|
if is_shader_valid():
|
|
var r_map: PackedInt32Array = plugin.terrain.data.get_region_map()
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_visible", editor_decal_visible)
|
|
RenderingServer.material_set_param(mat_rid, "_region_map", r_map)
|
|
|
|
|
|
# These array sizes are reset to 0 when closing scenes for some unknown reason, so check and reset
|
|
func reset_decal_arrays() -> void:
|
|
if editor_decal_color.size() < 3:
|
|
editor_decal_position = [Vector2(), Vector2(), Vector2()]
|
|
editor_decal_rotation = [float(), float(), float()]
|
|
editor_decal_size = [float(), float(), float()]
|
|
editor_decal_color = [Color(), Color(), Color()]
|
|
editor_decal_visible = [false, false, false]
|
|
editor_brush_texture_rid = RID()
|
|
|
|
|
|
func set_decal_rotation(p_rot: float) -> void:
|
|
editor_decal_rotation[0] = p_rot
|
|
if is_shader_valid():
|
|
RenderingServer.material_set_param(mat_rid, "_editor_decal_rotation", editor_decal_rotation)
|
|
|
|
|
|
func _on_picking(p_type: int, p_callback: Callable) -> void:
|
|
picking = p_type
|
|
picking_callback = p_callback
|
|
update_decal()
|
|
|
|
|
|
func clear_picking() -> void:
|
|
picking = Terrain3DEditor.TOOL_MAX
|
|
|
|
|
|
func is_picking() -> bool:
|
|
if picking != Terrain3DEditor.TOOL_MAX:
|
|
return true
|
|
|
|
if operation_builder and operation_builder.is_picking():
|
|
return true
|
|
|
|
return false
|
|
|
|
|
|
func pick(p_global_position: Vector3) -> void:
|
|
if picking != Terrain3DEditor.TOOL_MAX:
|
|
var color: Color
|
|
match picking:
|
|
Terrain3DEditor.HEIGHT, Terrain3DEditor.SCULPT:
|
|
color = Color(plugin.terrain.data.get_height(p_global_position), 0., 0., 1.)
|
|
Terrain3DEditor.ROUGHNESS:
|
|
color = plugin.terrain.data.get_pixel(Terrain3DRegion.TYPE_COLOR, p_global_position)
|
|
Terrain3DEditor.COLOR:
|
|
color = plugin.terrain.data.get_color(p_global_position)
|
|
Terrain3DEditor.ANGLE:
|
|
color = Color(plugin.terrain.data.get_control_angle(p_global_position), 0., 0., 1.)
|
|
Terrain3DEditor.SCALE:
|
|
color = Color(plugin.terrain.data.get_control_scale(p_global_position), 0., 0., 1.)
|
|
_:
|
|
push_error("Unsupported picking type: ", picking)
|
|
return
|
|
if picking_callback.is_valid():
|
|
picking_callback.call(picking, color, p_global_position)
|
|
picking_callback = Callable()
|
|
picking = Terrain3DEditor.TOOL_MAX
|
|
|
|
elif operation_builder and operation_builder.is_picking():
|
|
operation_builder.pick(p_global_position, plugin.terrain)
|
|
|
|
|
|
func set_button_editor_icon(p_button: Button, p_icon_name: String) -> void:
|
|
p_button.icon = EditorInterface.get_base_control().get_theme_icon(p_icon_name, "EditorIcons")
|