Skip to content

Commit

Permalink
Add slope sculpting tool TokisanGames#96
Browse files Browse the repository at this point in the history
  • Loading branch information
tcoxon committed Jan 22, 2024
1 parent a85d40c commit 2c0839e
Show file tree
Hide file tree
Showing 13 changed files with 579 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
extends "res://addons/terrain_3d/editor/components/operation_builder.gd"


const PointPicker: Script = preload("res://addons/terrain_3d/editor/components/point_picker.gd")


func _get_point_picker() -> PointPicker:
return tool_settings.settings["gradient_points"]


func _get_brush_size() -> float:
return tool_settings.get_setting("size")


func _is_drawable() -> bool:
return tool_settings.get_setting("drawable")


func is_picking() -> bool:
return not _get_point_picker().all_points_selected()


func pick(p_global_position: Vector3, p_terrain: Terrain3D) -> void:
if not _get_point_picker().all_points_selected():
_get_point_picker().add_point(p_global_position)


func is_ready() -> bool:
return _get_point_picker().all_points_selected() and not _is_drawable()


func apply_operation(p_editor: Terrain3DEditor, p_global_position: Vector3, p_camera_direction: float) -> void:
var points: PackedVector3Array = _get_point_picker().get_points()
assert(points.size() == 2)
assert(not _is_drawable())

var brush_size: float = _get_brush_size()
assert(brush_size > 0.0)

var start: Vector3 = points[0]
var end: Vector3 = points[1]

p_editor.start_operation(start)

var dir: Vector3 = (end - start).normalized()

var pos: Vector3 = start
while dir.dot(end - pos) > 0.0:
p_editor.operate(pos, p_camera_direction)
pos += dir * brush_size * 0.333

p_editor.stop_operation()

_get_point_picker().clear()

23 changes: 23 additions & 0 deletions project/addons/terrain_3d/editor/components/operation_builder.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
extends RefCounted


const ToolSettings: Script = preload("res://addons/terrain_3d/editor/components/tool_settings.gd")


var tool_settings: ToolSettings


func is_picking() -> bool:
return false


func pick(p_global_position: Vector3, p_terrain: Terrain3D) -> void:
pass


func is_ready() -> bool:
return false


func apply_operation(editor: Terrain3DEditor, p_global_position: Vector3, p_camera_direction: float) -> void:
pass
89 changes: 89 additions & 0 deletions project/addons/terrain_3d/editor/components/point_picker.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
extends HBoxContainer


signal pressed
signal value_changed


const ICON_PICKER: String = "res://addons/terrain_3d/icons/icon_picker.svg"
const ICON_PICKER_CHECKED: String = "res://addons/terrain_3d/icons/icon_picker_checked.svg"
const MAX_POINTS: int = 2


var icon_picker: Texture2D
var icon_picker_checked: Texture2D
var points: PackedVector3Array
var picking_index: int = -1


func _init() -> void:
icon_picker = load(ICON_PICKER)
icon_picker_checked = load(ICON_PICKER_CHECKED)

var label := Label.new()
label.text = "Points:"
add_child(label)

points.resize(MAX_POINTS)

for i in range(MAX_POINTS):
var button := Button.new()
button.icon = icon_picker
button.tooltip_text = "Pick point on the Terrain"
button.set_meta(&"point_index", i)
button.pressed.connect(_on_button_pressed.bind(i))
add_child(button)

_update_buttons()


func _on_button_pressed(button_index: int) -> void:
points[button_index] = Vector3.ZERO
picking_index = button_index
_update_buttons()
pressed.emit()


func _update_buttons() -> void:
for child in get_children():
if child is Button:
_update_button(child)


func _update_button(button: Button) -> void:
var index: int = button.get_meta(&"point_index")

if points[index] != Vector3.ZERO:
button.icon = icon_picker_checked
else:
button.icon = icon_picker


func clear() -> void:
points.fill(Vector3.ZERO)
_update_buttons()
value_changed.emit()


func all_points_selected() -> bool:
return points.count(Vector3.ZERO) == 0


func add_point(p_value: Vector3) -> void:
if points.has(p_value):
return

if picking_index != -1:
points[picking_index] = p_value
picking_index = -1
else:
for i in range(MAX_POINTS):
if points[i] == Vector3.ZERO:
points[i] = p_value
break
_update_buttons()
value_changed.emit()


func get_points() -> PackedVector3Array:
return points
37 changes: 35 additions & 2 deletions project/addons/terrain_3d/editor/components/tool_settings.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ enum SettingType {
DOUBLE_SLIDER,
COLOR_SELECT,
PICKER,
POINT_PICKER,
}

const PointPicker: Script = preload("res://addons/terrain_3d/editor/components/point_picker.gd")
const DEFAULT_BRUSH: String = "circle0.exr"
const BRUSH_PATH: String = "res://addons/terrain_3d/editor/brushes"
const PICKER_ICON: String = "res://addons/terrain_3d/icons/icon_picker.svg"
Expand Down Expand Up @@ -52,6 +54,11 @@ func _ready() -> void:
add_setting(SettingType.SLIDER, "height", 50, list, "m", -500, 500, 0.1, ALLOW_OUT_OF_BOUNDS)
add_setting(SettingType.PICKER, "height picker", Terrain3DEditor.HEIGHT, list)
add_setting(SettingType.DOUBLE_SLIDER, "slope", 0, list, "°", 0, 180, 1)

add_setting(SettingType.POINT_PICKER, "gradient_points", Terrain3DEditor.HEIGHT, list)
add_setting(SettingType.CHECKBOX, "drawable", false, list)

settings["drawable"].toggled.connect(_on_drawable_toggled)

var spacer: Control = Control.new()
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
Expand Down Expand Up @@ -176,7 +183,7 @@ func _on_pick(p_type: Terrain3DEditor.Tool) -> void:
emit_signal("picking", p_type, _on_picked)


func _on_picked(p_type: Terrain3DEditor.Tool, p_color: Color) -> void:
func _on_picked(p_type: Terrain3DEditor.Tool, p_color: Color, p_global_position: Vector3) -> void:
match p_type:
Terrain3DEditor.HEIGHT:
settings["height"].value = p_color.r
Expand All @@ -188,6 +195,20 @@ func _on_picked(p_type: Terrain3DEditor.Tool, p_color: Color) -> void:
_on_setting_changed()


func _on_point_pick(p_type: Terrain3DEditor.Tool, p_name: String) -> void:
assert(p_type == Terrain3DEditor.HEIGHT)
emit_signal("picking", p_type, _on_point_picked.bind(p_name))


func _on_point_picked(p_type: Terrain3DEditor.Tool, p_color: Color, p_global_position: Vector3, p_name: String) -> void:
assert(p_type == Terrain3DEditor.HEIGHT)

var point: Vector3 = p_global_position
point.y = p_color.r
settings[p_name].add_point(point)
_on_setting_changed()


func add_setting(p_type: SettingType, p_name: StringName, p_value: Variant, p_parent: Control,
p_suffix: String = "", p_min_value: float = 0.0, p_max_value: float = 0.0, p_step: float = 1.0,
p_flags: int = NONE) -> void:
Expand Down Expand Up @@ -266,7 +287,12 @@ func add_setting(p_type: SettingType, p_name: StringName, p_value: Variant, p_pa
control.icon = load(PICKER_ICON)
control.tooltip_text = "Pick value from the Terrain"
control.connect("pressed", _on_pick.bind(p_value))


SettingType.POINT_PICKER:
control = PointPicker.new()
control.connect("pressed", _on_point_pick.bind(p_value, p_name))
control.connect("value_changed", _on_setting_changed)

container.add_child(control, true)
p_parent.add_child(container, true)

Expand All @@ -288,6 +314,8 @@ func get_setting(p_setting: String) -> Variant:
value = object.is_pressed()
elif object is ColorPickerButton:
value = object.color
elif object is PointPicker:
value = object.get_points()
return value


Expand Down Expand Up @@ -319,6 +347,11 @@ func _on_setting_changed(p_data: Variant = null) -> void:
emit_signal("setting_changed")


func _on_drawable_toggled(p_button_pressed: bool) -> void:
if not p_button_pressed:
settings["gradient_points"].clear()


func _get_brush_preview_material() -> ShaderMaterial:
if !brush_preview_material:
brush_preview_material = ShaderMaterial.new()
Expand Down
2 changes: 2 additions & 0 deletions project/addons/terrain_3d/editor/components/toolbar.gd
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const ICON_HEIGHT_SUB: String = "res://addons/terrain_3d/icons/icon_height_sub.s
const ICON_HEIGHT_MUL: String = "res://addons/terrain_3d/icons/icon_height_mul.svg"
const ICON_HEIGHT_DIV: String = "res://addons/terrain_3d/icons/icon_height_div.svg"
const ICON_HEIGHT_FLAT: String = "res://addons/terrain_3d/icons/icon_height_flat.svg"
const ICON_HEIGHT_SLOPE: String = "res://addons/terrain_3d/icons/icon_height_slope.svg"
const ICON_HEIGHT_SMOOTH: String = "res://addons/terrain_3d/icons/icon_height_smooth.svg"
const ICON_PAINT_TEXTURE: String = "res://addons/terrain_3d/icons/icon_brush.svg"
const ICON_SPRAY_TEXTURE: String = "res://addons/terrain_3d/icons/icon_spray.svg"
Expand Down Expand Up @@ -37,6 +38,7 @@ func _ready() -> void:
add_tool_button(Terrain3DEditor.HEIGHT, Terrain3DEditor.MULTIPLY, "Expand (Away from 0)", load(ICON_HEIGHT_MUL), tool_group)
add_tool_button(Terrain3DEditor.HEIGHT, Terrain3DEditor.DIVIDE, "Reduce (Towards 0)", load(ICON_HEIGHT_DIV), tool_group)
add_tool_button(Terrain3DEditor.HEIGHT, Terrain3DEditor.REPLACE, "Flatten", load(ICON_HEIGHT_FLAT), tool_group)
add_tool_button(Terrain3DEditor.HEIGHT, Terrain3DEditor.GRADIENT, "Slope", load(ICON_HEIGHT_SLOPE), tool_group)
add_tool_button(Terrain3DEditor.HEIGHT, Terrain3DEditor.AVERAGE, "Smooth", load(ICON_HEIGHT_SMOOTH), tool_group)
add_child(HSeparator.new())
add_tool_button(Terrain3DEditor.TEXTURE, Terrain3DEditor.REPLACE, "Paint Base Texture", load(ICON_PAINT_TEXTURE), tool_group)
Expand Down
Loading

0 comments on commit 2c0839e

Please sign in to comment.