aboutsummaryrefslogtreecommitdiff
path: root/addons/voxel-core/controls/tiles_viewer/tiles_viewer.gd
blob: 2bea8368e8cf4f45f341269b0bec4dcbd9f030d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
tool
extends TextureRect
# Shows tiles of VoxelSet and allows for the selection of Tile(s)



## Signals
# Emitted when a uv position has been selected
signal selected_uv(uv)
# Emitted when a uv position has been unselected
signal unselected_uv(uv)



## Exported Variables
# Maximum number of uv positions that can be selected at any one time
export(int, -1, 256) var selection_max := 0 setget set_selection_max

# Color to applyed to border of hovered uv position(s)
export var hovered_color := Color(1, 1, 1, 0.6) setget set_hovered_color

# Color to applyed to border of selected uv position(s)
export var selected_color := Color.white setget set_selection_color

# Color to applyed to border of invalid uv position(s)
export var invalid_color := Color.red setget set_invalid_color

# VoxelSet being used
export(Resource) var voxel_set = null setget set_voxel_set



## Private Variables
# Stores last uv position hovered
var _last_uv_hovered := -Vector2.ONE

# Selected uv positions
var _selections := []



## Built-In Virtual Methods
func _gui_input(event : InputEvent):
	if event is InputEventMouse:
		_last_uv_hovered = world_to_uv(event.position)
		if selection_max != 0 and event is InputEventMouseButton:
			if is_valid_uv(_last_uv_hovered) and event.button_index == BUTTON_LEFT and not event.is_pressed():
				if _selections.has(_last_uv_hovered):
					unselect(_last_uv_hovered)
				else:
					select(_last_uv_hovered)
		update()


func _draw():
	if is_instance_valid(voxel_set) and voxel_set.uv_ready():
		texture = voxel_set.tiles
		if selection_max != 0:
			for selection in _selections:
				draw_rect(Rect2(
								selection * voxel_set.tile_size,
								voxel_set.tile_size),
						selected_color, false, 3)
		
		if _last_uv_hovered == -Vector2.ONE:
			hint_tooltip = ""
		else:
			hint_tooltip = str(_last_uv_hovered)
			draw_rect(Rect2(
							_last_uv_hovered * voxel_set.tile_size,
							voxel_set.tile_size),
					hovered_color if is_valid_uv(_last_uv_hovered) else invalid_color,
					false, 3)



## Public Methods
# Sets selection_max, shrinks _selections to new maximum if needed and calls on update by default
func set_selection_max(value : int, update := true) -> void:
	selection_max = clamp(value, -1, 256)
	unselect_shrink()
	if update:
		self.update()


# Sets hovered_color, and calls on update by default
func set_hovered_color(value : Color, update := true) -> void:
	hovered_color = value
	if update:
		self.update()


# Sets selected_color, and calls on update by default
func set_selection_color(value : Color, update := true) -> void:
	selected_color = value
	if update:
		self.update()


# Sets invalid_color, and calls on update by default
func set_invalid_color(value : Color, update := true) -> void:
	invalid_color = value
	if update:
		self.update()


# Sets voxel_set, calls update_mesh if needed and not told otherwise
func set_voxel_set(value : Resource, update := true) -> void:
	if not (typeof(value) == TYPE_NIL or value is VoxelSet):
		printerr("Invalid Resource given expected VoxelSet")
		return
	
	if is_instance_valid(voxel_set):
		if voxel_set.is_connected("requested_refresh", self, "update"):
			voxel_set.disconnect("requested_refresh", self, "update")
	
	voxel_set = value
	if is_instance_valid(voxel_set):
		if not voxel_set.is_connected("requested_refresh", self, "update"):
			voxel_set.connect("requested_refresh", self, "update")
	
	if update:
		self.update()


# Returns true if uv is selected
func has_selected(uv : Vector2) -> bool:
	return _selections.has(uv)


# Returns uv selected at given index
func get_selected(index : int) -> Vector2:
	return _selections[index]


# Returns array of selected faces
func get_selections() -> Array:
	return _selections.duplicate()


# Returns number of faces selected
func get_selected_size() -> int:
	return _selections.size()


# Returns world position as uv position
func world_to_uv(world : Vector2) -> Vector2:
	return (world / voxel_set.tile_size).floor() if is_instance_valid(voxel_set) and voxel_set.uv_ready() else -Vector2.ONE


# Returns true if uv position is valid
func is_valid_uv(uv : Vector2) -> bool:
	if is_instance_valid(voxel_set) and voxel_set.uv_ready():
		var bounds = voxel_set.tiles.get_size() / voxel_set.tile_size
		return uv.x >= 0 and uv.y >= 0 and uv.x < bounds.x and uv.y < bounds.y
	return false


# Returns true if world position is valid uv position
func is_valid_world(world : Vector2) -> bool:
	return is_valid_uv(world_to_uv(world))


# Selects given uv position, and emits selected_uv
func select(uv : Vector2, emit := true) -> void:
	# TODO UV within bounds
	if selection_max != 0:
		unselect_shrink(selection_max - 1)
		_selections.append(uv)
		if emit:
			emit_signal("selected_uv", uv)


# Unselects given uv position, and emits unselected_uv
func unselect(uv : Vector2, emit := true) -> void:
	if _selections.has(uv):
		_selections.erase(uv)
		if emit:
			emit_signal("unselected_uv", uv)


# Unselects all uv position
func unselect_all() -> void:
	while not _selections.empty():
		unselect(_selections.back())


# Unselects all uv position until given size is met
func unselect_shrink(size := selection_max, emit := true) -> void:
	if size >= 0:
		while _selections.size() > size:
			unselect(_selections.back(), emit)



## Private Methods
func _on_TilesViewer_mouse_exited():
	_last_uv_hovered = -Vector2.ONE
	update()