diff --git a/editor.scn b/editor.scn index 0abad7a..a04e07e 100644 --- a/editor.scn +++ b/editor.scn @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:600cffba10aeef4586ec866fda388f7a80810e246c4f274f9a2c73216818fdd5 -size 8034 +oid sha256:f440fd5671e8668e3c627d3447cecb4d8b508cdd4590805726edadf663e4c6e7 +size 7923 diff --git a/editor/edit_mode_button_group.res b/editor/edit_mode_button_group.res index 589ebec..9e6a97d 100644 --- a/editor/edit_mode_button_group.res +++ b/editor/edit_mode_button_group.res @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae83902fc3965c6ed4c5a8fdcb1ebadf66fccd27ea585f0b80c71a3707190662 -size 194 +oid sha256:dcc7954349a7ed68391dfbfd0e8369169da156218b5b856dda3005ef0708ad16 +size 202 diff --git a/project.godot b/project.godot index 542c2e5..b065f79 100644 --- a/project.godot +++ b/project.godot @@ -14,6 +14,11 @@ _global_script_classes=[{ "language": &"GDScript", "path": "res://terrain/dynamic_terrain_instance_3d.gd" }, { +"base": "HFlowContainer", +"class": &"ItemSelection", +"language": &"GDScript", +"path": "res://user_interface/button_selection.gd" +}, { "base": "Node3D", "class": &"PlayerController", "language": &"GDScript", @@ -36,6 +41,7 @@ _global_script_classes=[{ }] _global_script_class_icons={ "DynamicTerrainInstance3D": "", +"ItemSelection": "", "PlayerController": "", "Settings": "", "TerrainInstance3D": "", diff --git a/terrain/dynamic_terrain_instance_3d.gd b/terrain/dynamic_terrain_instance_3d.gd index 7b2ba12..07f5d75 100644 --- a/terrain/dynamic_terrain_instance_3d.gd +++ b/terrain/dynamic_terrain_instance_3d.gd @@ -31,11 +31,11 @@ func clear(clear_elevation: float) -> void: _editable_texture.update(_editable_image) ## +## Oscillates the height of terrain toward a value of [member height_scale] (multiplied by +## [code]level[/code]) around the area of [code]point[/code] determined by [code]mask[/code] +## multiplied by [code]mask_scale[/code] at a rate of [code]intensity[/code]. ## -## -func oscillate(point: Vector2i, level: float, - mask: Image, mask_scale: float, intensity: float, delta: float) -> void: - +func oscillate(point: Vector2i, level: float, mask: Image, mask_scale: float, intensity: float) -> void: var mask_size := mask.get_size() var brush_source := _get_brush_area(point, mask_size, mask_scale) @@ -54,17 +54,17 @@ func oscillate(point: Vector2i, level: float, var pixel := _editable_image.get_pixelv(coord) _editable_image.set_pixelv(coord, Color(pixel.r, pixel.g, pixel.b, - lerpf(pixel.a, level, intensity * delta *\ + lerpf(pixel.a, level, intensity *\ mask.get_pixel(int((offset.x + x) * mask_ratio.x), mask_y).a)).clamp()) _editable_texture.update(_editable_image) ## +## Paints the texture of the terrain toward a value of [code]color[/code] multiplied by +## [code]intensity[/code] around the area of [code]point[/code] determined by [code]mask[/code] +## multiplied by [code]mask_scale[/code] at a rate of [code]intensity[/code]. ## -## -func paint(point: Vector2i, color: Color, - mask: Image, mask_scale: float, intensity: float, delta: float) -> void: - +func paint(point: Vector2i, color: Color, mask: Image, mask_scale: float, intensity: float) -> void: var mask_size := mask.get_size() var brush_source := _get_brush_area(point, mask_size, mask_scale) @@ -82,7 +82,7 @@ func paint(point: Vector2i, color: Color, var coord := brush_target.position + Vector2i(x, y) var pixel := _editable_image.get_pixelv(coord) - var mask_intensity_delta := intensity * delta *\ + var mask_intensity_delta := intensity *\ mask.get_pixel(int((offset.x + x) * mask_ratio.x), mask_y).a _editable_image.set_pixelv(coord, Color( @@ -93,7 +93,10 @@ func paint(point: Vector2i, color: Color, _editable_texture.update(_editable_image) ## +## Attempts to resize the terrain geometry and map to be equal to [code]size[/code] (in-engine +## units), with [code]Vector2i.ONE[/code] as the minimum size. ## +## In the process of growing the terrain map, existing edge data will be copied to fill it out. ## func resize(size: Vector2i) -> void: super.resize(size) diff --git a/terrain/paints/terrain_paint.gd b/terrain/paints/terrain_paint.gd index d03f0c8..450acfa 100644 --- a/terrain/paints/terrain_paint.gd +++ b/terrain/paints/terrain_paint.gd @@ -1,13 +1,13 @@ class_name TerrainPaint extends Resource ## -## +## Terrain albedo map data. ## @export var albedo_map: Texture2D = null ## -## +## Terrain normal map data. ## @export var normal_map: Texture2D = null diff --git a/user_interface/button_selection.gd b/user_interface/button_selection.gd new file mode 100644 index 0000000..d94a691 --- /dev/null +++ b/user_interface/button_selection.gd @@ -0,0 +1,75 @@ +@tool +class_name ItemSelection extends HFlowContainer + +## +## An item has been selected via GUI selection or [method select_item]. +## +signal item_selected(index: int) + +var _button_group := ButtonGroup.new() + +## +## Number of items in the selection. +## +var item_count: int: + get: + return _button_group.get_buttons().size() + +func _get_configuration_warnings() -> PackedStringArray: + return PackedStringArray() + +## +## Adds a new item with no text and only [code]icon[/code] as the icon to the selection. +## +func add_icon_item(icon: Texture2D) -> void: + var child_count := get_child_count() + var button := Button.new() + + button.icon = icon + button.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + button.toggle_mode = true + button.button_group = _button_group + button.button_pressed = child_count == 0 + + button.pressed.connect(func () -> void: select_item(child_count)) + add_child(button) + +## +## Returns the icon used by the item at [code]index[/code]. +## +## An assertion is raised if [code]index[/code] is out of bounds from the item count. +## +func get_item_icon(index: int) -> Texture2D: + var buttons := _button_group.get_buttons() + + assert(index < buttons.size(), "index out of range") + + var button := buttons[index] as Button + + return null if (button == null) else button.icon + +## +## Returns the currently selected item index or [code]-1[/code] if no item is selected. +## +func get_selected_item() -> int: + var pressed_button := _button_group.get_pressed_button() + + return -1 if (pressed_button == null) else pressed_button.get_index() + +## +## Selects the item at [code]index[/code], emitting [signal item_selected] at the end. +## +## An assertion is raised if [code]index[/code] is out of bounds from the item count. +## +func select_item(index: int) -> void: + var buttons := _button_group.get_buttons() + + assert(index < buttons.size(), "index out of range") + + var pressed_button := _button_group.get_pressed_button() + + if pressed_button != null: + pressed_button.set_pressed_no_signal(false) + + buttons[index].set_pressed_no_signal(true) + item_selected.emit(index)