-
Notifications
You must be signed in to change notification settings - Fork 1
/
canvas_plane_v2.gd
274 lines (203 loc) · 7.8 KB
/
canvas_plane_v2.gd
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
extends Spatial
class_name CanvasPlaneV2, "icon_canvas_plane.svg"
tool
const canvas_utils_const = preload("canvas_utils.gd")
const function_pointer_receiver_const = preload("function_pointer_receiver.gd")
var _is_dirty: bool = true
export (Vector2) var offset_ratio: Vector2 = Vector2(0.5, 0.5) setget set_offset_ratio
enum BillboardMode {BILLBOARD_DISABLED, BILLBOARD_ENABLED, BILLBOARD_FIXED_Y, BILLBOARD_PARTICLES}
export(BillboardMode) var billboard_mode: int = BillboardMode.BILLBOARD_DISABLED setget set_billboard_mode
export (bool) var interactable: bool = false setget set_interactable
export (bool) var translucent: bool = false setget set_translucent
export (int, LAYERS_2D_PHYSICS) var collision_mask: int = 0
export (int, LAYERS_3D_PHYSICS) var collision_layer: int = 0
var tree_changed: bool = true
var original_canvas_rid: RID = RID()
# Render
var canvas_size: Vector2 = Vector2()
var spatial_root: Spatial = null
var mesh: Mesh = null
var mesh_instance: MeshInstance = null
var material: Material = null
var viewport: Viewport = null
var control_root: Control = null
# Collision
var pointer_receiver: function_pointer_receiver_const = null
var collision_shape: CollisionShape = null
# Interaction
var previous_mouse_position: Vector2 = Vector2()
var mouse_mask: int = 0
"""
func get_spatial_origin_to_canvas_position(p_origin: Vector3) -> Vector2:
var transform_scale: Vector2 = Vector2(
global_transform.basis.get_scale().x, global_transform.basis.get_scale().y
)
var inverse_transform: Vector2 = Vector2(1.0, 1.0) / transform_scale
var point: Vector2 = Vector2(p_origin.x, p_origin.y) * inverse_transform * inverse_transform
var point: Vector2 = Vector2(p_origin.x, p_origin.y) * inverse_transform * inverse_transform
var ratio: Vector2 = (
Vector2(0.5, 0.5)
+ (point / canvas_scale) / ((Vector2(canvas_width, canvas_height) * canvas_scale) * 0.5)
)
ratio.y = 1.0 - ratio.y # Flip the Y-axis
var canvas_position: Vector2 = ratio * Vector2(canvas_width, canvas_height)
return canvas_position
"""
func _update_aabb() -> void:
if mesh and mesh_instance:
if billboard_mode != BillboardMode.BILLBOARD_DISABLED:
var longest_axis_size: float = mesh.get_aabb().get_longest_axis_size()
mesh_instance.set_custom_aabb(AABB(mesh.get_aabb().position, Vector3(longest_axis_size, longest_axis_size, longest_axis_size)))
else:
mesh_instance.set_custom_aabb(AABB())
func _update() -> void:
_update_control_root()
var scaled_canvas_size: Vector2 = canvas_size * canvas_utils_const.UI_PIXELS_TO_METER
var canvas_offset: Vector2 = Vector2((
(scaled_canvas_size.x * 0.5)
- (scaled_canvas_size.x * offset_ratio.x)
),(
-(scaled_canvas_size.y * 0.5)
+ (scaled_canvas_size.y * offset_ratio.y)
))
if mesh:
mesh.set_size(scaled_canvas_size)
if mesh_instance:
mesh_instance.set_translation(Vector3(canvas_offset.x, canvas_offset.y, 0))
_update_aabb()
clear_dirty_flag()
func get_control_root() -> Control:
return control_root
func get_control_viewport() -> Viewport:
return viewport
func set_offset_ratio(p_offset_ratio: Vector2) -> void:
offset_ratio = p_offset_ratio
set_dirty_flag()
func set_interactable(p_interactable: bool) -> void:
interactable = p_interactable
set_dirty_flag()
func set_translucent(p_translucent: bool) -> void:
translucent = p_translucent
if material:
material.flags_transparent = translucent
func set_billboard_mode(p_billboard_mode: int) -> void:
billboard_mode = p_billboard_mode
if material:
material.set_billboard_mode(p_billboard_mode)
set_dirty_flag()
func _setup_canvas_item() -> void:
if control_root.is_connected("resized", self, "_resized") == false:
control_root.connect("resized", self, "_resized")
original_canvas_rid = control_root.get_canvas()
VisualServer.canvas_item_set_parent(control_root.get_canvas_item(), viewport.find_world_2d().get_canvas())
func _set_mesh_material(p_material: Material) -> void:
if mesh:
if mesh is PrimitiveMesh:
mesh.set_material(p_material)
else:
mesh.surface_set_material(0, p_material)
func _find_control_root() -> void:
if tree_changed:
var new_control_root: Control = canvas_utils_const.find_child_control(self)
if new_control_root != control_root:
# Clear up the old control root
if control_root:
if control_root.is_connected("resized", self, "_resized"):
control_root.disconnect("resized", self, "_resized")
VisualServer.canvas_item_set_parent(control_root.get_canvas_item(), original_canvas_rid)
# Assign the new control rool and give
control_root = new_control_root
if control_root:
_setup_canvas_item()
tree_changed = false
func _update_control_root() -> void:
if Engine.is_editor_hint():
_find_control_root()
if control_root:
canvas_size = control_root.rect_size
else:
canvas_size = Vector2()
viewport.size = canvas_size
func set_dirty_flag() -> void:
#print("set_dirty_flag")
if _is_dirty == false:
_is_dirty = true
call_deferred("_update")
func clear_dirty_flag() -> void:
#print("clear_dirty_flag")
_is_dirty = false
func _tree_changed() -> void:
#print("_tree_changed")
tree_changed = true
set_dirty_flag()
func _resized() -> void:
#print("_resized")
set_dirty_flag()
func _exit_tree():
if Engine.is_editor_hint():
if get_tree().is_connected("tree_changed", self, "_tree_changed"):
get_tree().disconnect("tree_changed", self, "_tree_changed")
if control_root:
if control_root.is_connected("resized", self, "_resized"):
control_root.disconnect("resized", self, "_resized")
func _enter_tree():
if control_root and viewport:
call_deferred("_setup_canvas_item")
func _ready() -> void:
spatial_root = Spatial.new()
spatial_root.set_name("SpatialRoot")
add_child(spatial_root)
mesh = QuadMesh.new()
mesh_instance = MeshInstance.new()
mesh_instance.set_mesh(mesh)
mesh_instance.set_scale(Vector3(1.0, -1.0, 1.0))
mesh_instance.set_name("MeshInstance")
mesh_instance.set_skeleton_path(NodePath())
spatial_root.add_child(mesh_instance)
mesh_instance.set_owner(spatial_root)
spatial_root.set_owner(null)
# Collision
pointer_receiver = function_pointer_receiver_const.new()
pointer_receiver.set_name("PointerReceiver")
if pointer_receiver.connect("pointer_pressed", self, "on_pointer_pressed") != OK:
printerr("pointer_pressed could not be connected!")
if pointer_receiver.connect("pointer_release", self, "on_pointer_release") != OK:
printerr("pointer_release could not be connected!")
pointer_receiver.collision_mask = collision_mask
pointer_receiver.collision_layer = collision_layer
spatial_root.add_child(pointer_receiver)
collision_shape = CollisionShape.new()
collision_shape.set_name("CollisionShape")
pointer_receiver.add_child(collision_shape)
viewport = Viewport.new()
viewport.size = Vector2(0, 0)
viewport.hdr = false
viewport.transparent_bg = true
viewport.disable_3d = true
viewport.keep_3d_linear = true
viewport.usage = Viewport.USAGE_2D_NO_SAMPLING
viewport.audio_listener_enable_2d = false
viewport.audio_listener_enable_3d = false
viewport.render_target_update_mode = Viewport.UPDATE_ALWAYS
viewport.set_name("Viewport")
if Engine.is_editor_hint():
VisualServer.viewport_attach_canvas(get_viewport().get_viewport_rid(), viewport.find_world_2d().get_canvas())
else:
_find_control_root()
spatial_root.add_child(viewport)
# Generate the unique material
material = SpatialMaterial.new()
material.flags_unshaded = true
material.flags_transparent = translucent
material.flags_albedo_tex_force_srgb = true
material.set_billboard_mode(billboard_mode)
_update()
_set_mesh_material(material)
# Texture
var texture: ViewportTexture = viewport.get_texture()
var flags: int = Texture.FLAGS_DEFAULT
texture.set_flags(flags)
material.albedo_texture = texture
if Engine.is_editor_hint():
if get_tree().connect("tree_changed", self, "_tree_changed") != OK:
printerr("Could not connect tree_changed")