1/**************************************************************************/
2/* grid_map.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "grid_map.h"
32
33#include "core/core_string_names.h"
34#include "core/io/marshalls.h"
35#include "core/object/message_queue.h"
36#include "scene/3d/light_3d.h"
37#include "scene/resources/mesh_library.h"
38#include "scene/resources/physics_material.h"
39#include "scene/resources/primitive_meshes.h"
40#include "scene/resources/surface_tool.h"
41#include "scene/scene_string_names.h"
42#include "servers/navigation_server_3d.h"
43#include "servers/rendering_server.h"
44
45bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
46 String name = p_name;
47
48 if (name == "data") {
49 Dictionary d = p_value;
50
51 if (d.has("cells")) {
52 Vector<int> cells = d["cells"];
53 int amount = cells.size();
54 const int *r = cells.ptr();
55 ERR_FAIL_COND_V(amount % 3, false); // not even
56 cell_map.clear();
57 for (int i = 0; i < amount / 3; i++) {
58 IndexKey ik;
59 ik.key = decode_uint64((const uint8_t *)&r[i * 3]);
60 Cell cell;
61 cell.cell = decode_uint32((const uint8_t *)&r[i * 3 + 2]);
62 cell_map[ik] = cell;
63 }
64 }
65
66 _recreate_octant_data();
67
68 } else if (name == "baked_meshes") {
69 clear_baked_meshes();
70
71 Array meshes = p_value;
72
73 for (int i = 0; i < meshes.size(); i++) {
74 BakedMesh bm;
75 bm.mesh = meshes[i];
76 ERR_CONTINUE(!bm.mesh.is_valid());
77 bm.instance = RS::get_singleton()->instance_create();
78 RS::get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
79 RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
80 if (is_inside_tree()) {
81 RS::get_singleton()->instance_set_scenario(bm.instance, get_world_3d()->get_scenario());
82 RS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
83 }
84 baked_meshes.push_back(bm);
85 }
86
87 _recreate_octant_data();
88
89 } else {
90 return false;
91 }
92
93 return true;
94}
95
96bool GridMap::_get(const StringName &p_name, Variant &r_ret) const {
97 String name = p_name;
98
99 if (name == "data") {
100 Dictionary d;
101
102 Vector<int> cells;
103 cells.resize(cell_map.size() * 3);
104 {
105 int *w = cells.ptrw();
106 int i = 0;
107 for (const KeyValue<IndexKey, Cell> &E : cell_map) {
108 encode_uint64(E.key.key, (uint8_t *)&w[i * 3]);
109 encode_uint32(E.value.cell, (uint8_t *)&w[i * 3 + 2]);
110 i++;
111 }
112 }
113
114 d["cells"] = cells;
115
116 r_ret = d;
117 } else if (name == "baked_meshes") {
118 Array ret;
119 ret.resize(baked_meshes.size());
120 for (int i = 0; i < baked_meshes.size(); i++) {
121 ret[i] = baked_meshes[i].mesh;
122 }
123 r_ret = ret;
124
125 } else {
126 return false;
127 }
128
129 return true;
130}
131
132void GridMap::_get_property_list(List<PropertyInfo> *p_list) const {
133 if (baked_meshes.size()) {
134 p_list->push_back(PropertyInfo(Variant::ARRAY, "baked_meshes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
135 }
136
137 p_list->push_back(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
138}
139
140void GridMap::set_collision_layer(uint32_t p_layer) {
141 collision_layer = p_layer;
142 _update_physics_bodies_collision_properties();
143}
144
145uint32_t GridMap::get_collision_layer() const {
146 return collision_layer;
147}
148
149void GridMap::set_collision_mask(uint32_t p_mask) {
150 collision_mask = p_mask;
151 _update_physics_bodies_collision_properties();
152}
153
154uint32_t GridMap::get_collision_mask() const {
155 return collision_mask;
156}
157
158void GridMap::set_collision_layer_value(int p_layer_number, bool p_value) {
159 ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
160 ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
161 uint32_t collision_layer_new = get_collision_layer();
162 if (p_value) {
163 collision_layer_new |= 1 << (p_layer_number - 1);
164 } else {
165 collision_layer_new &= ~(1 << (p_layer_number - 1));
166 }
167 set_collision_layer(collision_layer_new);
168}
169
170bool GridMap::get_collision_layer_value(int p_layer_number) const {
171 ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
172 ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
173 return get_collision_layer() & (1 << (p_layer_number - 1));
174}
175
176void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) {
177 ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
178 ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
179 uint32_t mask = get_collision_mask();
180 if (p_value) {
181 mask |= 1 << (p_layer_number - 1);
182 } else {
183 mask &= ~(1 << (p_layer_number - 1));
184 }
185 set_collision_mask(mask);
186}
187
188void GridMap::set_collision_priority(real_t p_priority) {
189 collision_priority = p_priority;
190 _update_physics_bodies_collision_properties();
191}
192
193real_t GridMap::get_collision_priority() const {
194 return collision_priority;
195}
196
197void GridMap::set_physics_material(Ref<PhysicsMaterial> p_material) {
198 physics_material = p_material;
199 _recreate_octant_data();
200}
201
202Ref<PhysicsMaterial> GridMap::get_physics_material() const {
203 return physics_material;
204}
205
206bool GridMap::get_collision_mask_value(int p_layer_number) const {
207 ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
208 ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
209 return get_collision_mask() & (1 << (p_layer_number - 1));
210}
211
212Array GridMap::get_collision_shapes() const {
213 Array shapes;
214 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
215 Octant *g = E.value;
216 RID body = g->static_body;
217 Transform3D body_xform = PhysicsServer3D::get_singleton()->body_get_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM);
218 int nshapes = PhysicsServer3D::get_singleton()->body_get_shape_count(body);
219 for (int i = 0; i < nshapes; i++) {
220 RID shape = PhysicsServer3D::get_singleton()->body_get_shape(body, i);
221 Transform3D xform = PhysicsServer3D::get_singleton()->body_get_shape_transform(body, i);
222 shapes.push_back(body_xform * xform);
223 shapes.push_back(shape);
224 }
225 }
226
227 return shapes;
228}
229
230void GridMap::set_bake_navigation(bool p_bake_navigation) {
231 bake_navigation = p_bake_navigation;
232 _recreate_octant_data();
233}
234
235bool GridMap::is_baking_navigation() {
236 return bake_navigation;
237}
238
239void GridMap::set_navigation_map(RID p_navigation_map) {
240 map_override = p_navigation_map;
241 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
242 Octant &g = *octant_map[E.key];
243 for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
244 if (F.value.region.is_valid()) {
245 NavigationServer3D::get_singleton()->region_set_map(F.value.region, map_override);
246 }
247 }
248 }
249}
250
251RID GridMap::get_navigation_map() const {
252 if (map_override.is_valid()) {
253 return map_override;
254 } else if (is_inside_tree()) {
255 return get_world_3d()->get_navigation_map();
256 }
257 return RID();
258}
259
260void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
261 if (!mesh_library.is_null()) {
262 mesh_library->disconnect_changed(callable_mp(this, &GridMap::_recreate_octant_data));
263 }
264 mesh_library = p_mesh_library;
265 if (!mesh_library.is_null()) {
266 mesh_library->connect_changed(callable_mp(this, &GridMap::_recreate_octant_data));
267 }
268
269 _recreate_octant_data();
270}
271
272Ref<MeshLibrary> GridMap::get_mesh_library() const {
273 return mesh_library;
274}
275
276void GridMap::set_cell_size(const Vector3 &p_size) {
277 ERR_FAIL_COND(p_size.x < 0.001 || p_size.y < 0.001 || p_size.z < 0.001);
278 cell_size = p_size;
279 _recreate_octant_data();
280 emit_signal(SNAME("cell_size_changed"), cell_size);
281}
282
283Vector3 GridMap::get_cell_size() const {
284 return cell_size;
285}
286
287void GridMap::set_octant_size(int p_size) {
288 ERR_FAIL_COND(p_size == 0);
289 octant_size = p_size;
290 _recreate_octant_data();
291}
292
293int GridMap::get_octant_size() const {
294 return octant_size;
295}
296
297void GridMap::set_center_x(bool p_enable) {
298 center_x = p_enable;
299 _recreate_octant_data();
300}
301
302bool GridMap::get_center_x() const {
303 return center_x;
304}
305
306void GridMap::set_center_y(bool p_enable) {
307 center_y = p_enable;
308 _recreate_octant_data();
309}
310
311bool GridMap::get_center_y() const {
312 return center_y;
313}
314
315void GridMap::set_center_z(bool p_enable) {
316 center_z = p_enable;
317 _recreate_octant_data();
318}
319
320bool GridMap::get_center_z() const {
321 return center_z;
322}
323
324void GridMap::set_cell_item(const Vector3i &p_position, int p_item, int p_rot) {
325 if (baked_meshes.size() && !recreating_octants) {
326 //if you set a cell item, baked meshes go good bye
327 clear_baked_meshes();
328 _recreate_octant_data();
329 }
330
331 ERR_FAIL_INDEX(ABS(p_position.x), 1 << 20);
332 ERR_FAIL_INDEX(ABS(p_position.y), 1 << 20);
333 ERR_FAIL_INDEX(ABS(p_position.z), 1 << 20);
334
335 IndexKey key;
336 key.x = p_position.x;
337 key.y = p_position.y;
338 key.z = p_position.z;
339
340 OctantKey ok;
341 ok.x = p_position.x / octant_size;
342 ok.y = p_position.y / octant_size;
343 ok.z = p_position.z / octant_size;
344
345 if (p_item < 0) {
346 //erase
347 if (cell_map.has(key)) {
348 OctantKey octantkey = ok;
349
350 ERR_FAIL_COND(!octant_map.has(octantkey));
351 Octant &g = *octant_map[octantkey];
352 g.cells.erase(key);
353 g.dirty = true;
354 cell_map.erase(key);
355 _queue_octants_dirty();
356 }
357 return;
358 }
359
360 OctantKey octantkey = ok;
361
362 if (!octant_map.has(octantkey)) {
363 //create octant because it does not exist
364 Octant *g = memnew(Octant);
365 g->dirty = true;
366 g->static_body = PhysicsServer3D::get_singleton()->body_create();
367 PhysicsServer3D::get_singleton()->body_set_mode(g->static_body, PhysicsServer3D::BODY_MODE_STATIC);
368 PhysicsServer3D::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id());
369 PhysicsServer3D::get_singleton()->body_set_collision_layer(g->static_body, collision_layer);
370 PhysicsServer3D::get_singleton()->body_set_collision_mask(g->static_body, collision_mask);
371 PhysicsServer3D::get_singleton()->body_set_collision_priority(g->static_body, collision_priority);
372 if (physics_material.is_valid()) {
373 PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_FRICTION, physics_material->get_friction());
374 PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material->get_bounce());
375 }
376 SceneTree *st = SceneTree::get_singleton();
377
378 if (st && st->is_debugging_collisions_hint()) {
379 g->collision_debug = RenderingServer::get_singleton()->mesh_create();
380 g->collision_debug_instance = RenderingServer::get_singleton()->instance_create();
381 RenderingServer::get_singleton()->instance_set_base(g->collision_debug_instance, g->collision_debug);
382 }
383
384 octant_map[octantkey] = g;
385
386 if (is_inside_world()) {
387 _octant_enter_world(octantkey);
388 _octant_transform(octantkey);
389 }
390 }
391
392 Octant &g = *octant_map[octantkey];
393 g.cells.insert(key);
394 g.dirty = true;
395 _queue_octants_dirty();
396
397 Cell c;
398 c.item = p_item;
399 c.rot = p_rot;
400
401 cell_map[key] = c;
402}
403
404int GridMap::get_cell_item(const Vector3i &p_position) const {
405 ERR_FAIL_INDEX_V(ABS(p_position.x), 1 << 20, INVALID_CELL_ITEM);
406 ERR_FAIL_INDEX_V(ABS(p_position.y), 1 << 20, INVALID_CELL_ITEM);
407 ERR_FAIL_INDEX_V(ABS(p_position.z), 1 << 20, INVALID_CELL_ITEM);
408
409 IndexKey key;
410 key.x = p_position.x;
411 key.y = p_position.y;
412 key.z = p_position.z;
413
414 if (!cell_map.has(key)) {
415 return INVALID_CELL_ITEM;
416 }
417 return cell_map[key].item;
418}
419
420int GridMap::get_cell_item_orientation(const Vector3i &p_position) const {
421 ERR_FAIL_INDEX_V(ABS(p_position.x), 1 << 20, -1);
422 ERR_FAIL_INDEX_V(ABS(p_position.y), 1 << 20, -1);
423 ERR_FAIL_INDEX_V(ABS(p_position.z), 1 << 20, -1);
424
425 IndexKey key;
426 key.x = p_position.x;
427 key.y = p_position.y;
428 key.z = p_position.z;
429
430 if (!cell_map.has(key)) {
431 return -1;
432 }
433 return cell_map[key].rot;
434}
435
436static const Basis _ortho_bases[24] = {
437 Basis(1, 0, 0, 0, 1, 0, 0, 0, 1),
438 Basis(0, -1, 0, 1, 0, 0, 0, 0, 1),
439 Basis(-1, 0, 0, 0, -1, 0, 0, 0, 1),
440 Basis(0, 1, 0, -1, 0, 0, 0, 0, 1),
441 Basis(1, 0, 0, 0, 0, -1, 0, 1, 0),
442 Basis(0, 0, 1, 1, 0, 0, 0, 1, 0),
443 Basis(-1, 0, 0, 0, 0, 1, 0, 1, 0),
444 Basis(0, 0, -1, -1, 0, 0, 0, 1, 0),
445 Basis(1, 0, 0, 0, -1, 0, 0, 0, -1),
446 Basis(0, 1, 0, 1, 0, 0, 0, 0, -1),
447 Basis(-1, 0, 0, 0, 1, 0, 0, 0, -1),
448 Basis(0, -1, 0, -1, 0, 0, 0, 0, -1),
449 Basis(1, 0, 0, 0, 0, 1, 0, -1, 0),
450 Basis(0, 0, -1, 1, 0, 0, 0, -1, 0),
451 Basis(-1, 0, 0, 0, 0, -1, 0, -1, 0),
452 Basis(0, 0, 1, -1, 0, 0, 0, -1, 0),
453 Basis(0, 0, 1, 0, 1, 0, -1, 0, 0),
454 Basis(0, -1, 0, 0, 0, 1, -1, 0, 0),
455 Basis(0, 0, -1, 0, -1, 0, -1, 0, 0),
456 Basis(0, 1, 0, 0, 0, -1, -1, 0, 0),
457 Basis(0, 0, 1, 0, -1, 0, 1, 0, 0),
458 Basis(0, 1, 0, 0, 0, 1, 1, 0, 0),
459 Basis(0, 0, -1, 0, 1, 0, 1, 0, 0),
460 Basis(0, -1, 0, 0, 0, -1, 1, 0, 0)
461};
462
463Basis GridMap::get_cell_item_basis(const Vector3i &p_position) const {
464 int orientation = get_cell_item_orientation(p_position);
465
466 if (orientation == -1) {
467 return Basis();
468 }
469
470 return get_basis_with_orthogonal_index(orientation);
471}
472
473Basis GridMap::get_basis_with_orthogonal_index(int p_index) const {
474 ERR_FAIL_INDEX_V(p_index, 24, Basis());
475
476 return _ortho_bases[p_index];
477}
478
479int GridMap::get_orthogonal_index_from_basis(const Basis &p_basis) const {
480 Basis orth = p_basis;
481 for (int i = 0; i < 3; i++) {
482 for (int j = 0; j < 3; j++) {
483 real_t v = orth[i][j];
484 if (v > 0.5) {
485 v = 1.0;
486 } else if (v < -0.5) {
487 v = -1.0;
488 } else {
489 v = 0;
490 }
491
492 orth[i][j] = v;
493 }
494 }
495
496 for (int i = 0; i < 24; i++) {
497 if (_ortho_bases[i] == orth) {
498 return i;
499 }
500 }
501
502 return 0;
503}
504
505Vector3i GridMap::local_to_map(const Vector3 &p_world_position) const {
506 Vector3 map_position = (p_world_position / cell_size).floor();
507 return Vector3i(map_position);
508}
509
510Vector3 GridMap::map_to_local(const Vector3i &p_map_position) const {
511 Vector3 offset = _get_offset();
512 Vector3 local_position(
513 p_map_position.x * cell_size.x + offset.x,
514 p_map_position.y * cell_size.y + offset.y,
515 p_map_position.z * cell_size.z + offset.z);
516 return local_position;
517}
518
519void GridMap::_octant_transform(const OctantKey &p_key) {
520 ERR_FAIL_COND(!octant_map.has(p_key));
521 Octant &g = *octant_map[p_key];
522 PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
523
524 if (g.collision_debug_instance.is_valid()) {
525 RS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
526 }
527
528 // update transform for NavigationServer regions and navigation debugmesh instances
529 for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
530 if (bake_navigation) {
531 if (E.value.region.is_valid()) {
532 NavigationServer3D::get_singleton()->region_set_transform(E.value.region, get_global_transform() * E.value.xform);
533 }
534 if (E.value.navigation_mesh_debug_instance.is_valid()) {
535 RS::get_singleton()->instance_set_transform(E.value.navigation_mesh_debug_instance, get_global_transform() * E.value.xform);
536 }
537 }
538 }
539
540 for (int i = 0; i < g.multimesh_instances.size(); i++) {
541 RS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
542 }
543}
544
545bool GridMap::_octant_update(const OctantKey &p_key) {
546 ERR_FAIL_COND_V(!octant_map.has(p_key), false);
547 Octant &g = *octant_map[p_key];
548 if (!g.dirty) {
549 return false;
550 }
551
552 //erase body shapes
553 PhysicsServer3D::get_singleton()->body_clear_shapes(g.static_body);
554
555 //erase body shapes debug
556 if (g.collision_debug.is_valid()) {
557 RS::get_singleton()->mesh_clear(g.collision_debug);
558 }
559
560 //erase navigation
561 for (KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
562 if (E.value.region.is_valid()) {
563 NavigationServer3D::get_singleton()->free(E.value.region);
564 E.value.region = RID();
565 }
566 if (E.value.navigation_mesh_debug_instance.is_valid()) {
567 RS::get_singleton()->free(E.value.navigation_mesh_debug_instance);
568 E.value.navigation_mesh_debug_instance = RID();
569 }
570 }
571 g.navigation_cell_ids.clear();
572
573 //erase multimeshes
574
575 for (int i = 0; i < g.multimesh_instances.size(); i++) {
576 RS::get_singleton()->free(g.multimesh_instances[i].instance);
577 RS::get_singleton()->free(g.multimesh_instances[i].multimesh);
578 }
579 g.multimesh_instances.clear();
580
581 if (g.cells.size() == 0) {
582 //octant no longer needed
583 _octant_clean_up(p_key);
584 return true;
585 }
586
587 Vector<Vector3> col_debug;
588
589 /*
590 * foreach item in this octant,
591 * set item's multimesh's instance count to number of cells which have this item
592 * and set said multimesh bounding box to one containing all cells which have this item
593 */
594
595 HashMap<int, List<Pair<Transform3D, IndexKey>>> multimesh_items;
596
597 for (const IndexKey &E : g.cells) {
598 ERR_CONTINUE(!cell_map.has(E));
599 const Cell &c = cell_map[E];
600
601 if (!mesh_library.is_valid() || !mesh_library->has_item(c.item)) {
602 continue;
603 }
604
605 Vector3 cellpos = Vector3(E.x, E.y, E.z);
606 Vector3 ofs = _get_offset();
607
608 Transform3D xform;
609
610 xform.basis = _ortho_bases[c.rot];
611 xform.set_origin(cellpos * cell_size + ofs);
612 xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
613 if (baked_meshes.size() == 0) {
614 if (mesh_library->get_item_mesh(c.item).is_valid()) {
615 if (!multimesh_items.has(c.item)) {
616 multimesh_items[c.item] = List<Pair<Transform3D, IndexKey>>();
617 }
618
619 Pair<Transform3D, IndexKey> p;
620 p.first = xform * mesh_library->get_item_mesh_transform(c.item);
621 p.second = E;
622 multimesh_items[c.item].push_back(p);
623 }
624 }
625
626 Vector<MeshLibrary::ShapeData> shapes = mesh_library->get_item_shapes(c.item);
627 // add the item's shape at given xform to octant's static_body
628 for (int i = 0; i < shapes.size(); i++) {
629 // add the item's shape
630 if (!shapes[i].shape.is_valid()) {
631 continue;
632 }
633 PhysicsServer3D::get_singleton()->body_add_shape(g.static_body, shapes[i].shape->get_rid(), xform * shapes[i].local_transform);
634 if (g.collision_debug.is_valid()) {
635 shapes.write[i].shape->add_vertices_to_array(col_debug, xform * shapes[i].local_transform);
636 }
637 }
638
639 // add the item's navigation_mesh at given xform to GridMap's Navigation ancestor
640 Ref<NavigationMesh> navigation_mesh = mesh_library->get_item_navigation_mesh(c.item);
641 if (navigation_mesh.is_valid()) {
642 Octant::NavigationCell nm;
643 nm.xform = xform * mesh_library->get_item_navigation_mesh_transform(c.item);
644 nm.navigation_layers = mesh_library->get_item_navigation_layers(c.item);
645
646 if (bake_navigation) {
647 RID region = NavigationServer3D::get_singleton()->region_create();
648 NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
649 NavigationServer3D::get_singleton()->region_set_navigation_layers(region, nm.navigation_layers);
650 NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, navigation_mesh);
651 NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * nm.xform);
652 if (is_inside_tree()) {
653 if (map_override.is_valid()) {
654 NavigationServer3D::get_singleton()->region_set_map(region, map_override);
655 } else {
656 NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
657 }
658 }
659 nm.region = region;
660
661#ifdef DEBUG_ENABLED
662 // add navigation debugmesh visual instances if debug is enabled
663 SceneTree *st = SceneTree::get_singleton();
664 if (st && st->is_debugging_navigation_hint()) {
665 if (!nm.navigation_mesh_debug_instance.is_valid()) {
666 RID navigation_mesh_debug_rid = navigation_mesh->get_debug_mesh()->get_rid();
667 nm.navigation_mesh_debug_instance = RS::get_singleton()->instance_create();
668 RS::get_singleton()->instance_set_base(nm.navigation_mesh_debug_instance, navigation_mesh_debug_rid);
669 }
670 if (is_inside_tree()) {
671 RS::get_singleton()->instance_set_scenario(nm.navigation_mesh_debug_instance, get_world_3d()->get_scenario());
672 RS::get_singleton()->instance_set_transform(nm.navigation_mesh_debug_instance, get_global_transform() * nm.xform);
673 }
674 }
675#endif // DEBUG_ENABLED
676 }
677 g.navigation_cell_ids[E] = nm;
678 }
679 }
680
681#ifdef DEBUG_ENABLED
682 if (bake_navigation) {
683 _update_octant_navigation_debug_edge_connections_mesh(p_key);
684 }
685#endif // DEBUG_ENABLED
686
687 //update multimeshes, only if not baked
688 if (baked_meshes.size() == 0) {
689 for (const KeyValue<int, List<Pair<Transform3D, IndexKey>>> &E : multimesh_items) {
690 Octant::MultimeshInstance mmi;
691
692 RID mm = RS::get_singleton()->multimesh_create();
693 RS::get_singleton()->multimesh_allocate_data(mm, E.value.size(), RS::MULTIMESH_TRANSFORM_3D);
694 RS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E.key)->get_rid());
695
696 int idx = 0;
697 for (const Pair<Transform3D, IndexKey> &F : E.value) {
698 RS::get_singleton()->multimesh_instance_set_transform(mm, idx, F.first);
699#ifdef TOOLS_ENABLED
700
701 Octant::MultimeshInstance::Item it;
702 it.index = idx;
703 it.transform = F.first;
704 it.key = F.second;
705 mmi.items.push_back(it);
706#endif
707
708 idx++;
709 }
710
711 RID instance = RS::get_singleton()->instance_create();
712 RS::get_singleton()->instance_set_base(instance, mm);
713
714 if (is_inside_tree()) {
715 RS::get_singleton()->instance_set_scenario(instance, get_world_3d()->get_scenario());
716 RS::get_singleton()->instance_set_transform(instance, get_global_transform());
717 }
718
719 mmi.multimesh = mm;
720 mmi.instance = instance;
721
722 g.multimesh_instances.push_back(mmi);
723 }
724 }
725
726 if (col_debug.size()) {
727 Array arr;
728 arr.resize(RS::ARRAY_MAX);
729 arr[RS::ARRAY_VERTEX] = col_debug;
730
731 RS::get_singleton()->mesh_add_surface_from_arrays(g.collision_debug, RS::PRIMITIVE_LINES, arr);
732 SceneTree *st = SceneTree::get_singleton();
733 if (st) {
734 RS::get_singleton()->mesh_surface_set_material(g.collision_debug, 0, st->get_debug_collision_material()->get_rid());
735 }
736 }
737
738 g.dirty = false;
739
740 return false;
741}
742
743void GridMap::_update_physics_bodies_collision_properties() {
744 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
745 PhysicsServer3D::get_singleton()->body_set_collision_layer(E.value->static_body, collision_layer);
746 PhysicsServer3D::get_singleton()->body_set_collision_mask(E.value->static_body, collision_mask);
747 PhysicsServer3D::get_singleton()->body_set_collision_priority(E.value->static_body, collision_priority);
748 }
749}
750
751void GridMap::_octant_enter_world(const OctantKey &p_key) {
752 ERR_FAIL_COND(!octant_map.has(p_key));
753 Octant &g = *octant_map[p_key];
754 PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
755 PhysicsServer3D::get_singleton()->body_set_space(g.static_body, get_world_3d()->get_space());
756
757 if (g.collision_debug_instance.is_valid()) {
758 RS::get_singleton()->instance_set_scenario(g.collision_debug_instance, get_world_3d()->get_scenario());
759 RS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
760 }
761
762 for (int i = 0; i < g.multimesh_instances.size(); i++) {
763 RS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, get_world_3d()->get_scenario());
764 RS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
765 }
766
767 if (bake_navigation && mesh_library.is_valid()) {
768 for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
769 if (cell_map.has(F.key) && F.value.region.is_valid() == false) {
770 Ref<NavigationMesh> navigation_mesh = mesh_library->get_item_navigation_mesh(cell_map[F.key].item);
771 if (navigation_mesh.is_valid()) {
772 RID region = NavigationServer3D::get_singleton()->region_create();
773 NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
774 NavigationServer3D::get_singleton()->region_set_navigation_layers(region, F.value.navigation_layers);
775 NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, navigation_mesh);
776 NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F.value.xform);
777 if (map_override.is_valid()) {
778 NavigationServer3D::get_singleton()->region_set_map(region, map_override);
779 } else {
780 NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
781 }
782
783 F.value.region = region;
784 }
785 }
786 }
787
788#ifdef DEBUG_ENABLED
789 if (bake_navigation) {
790 if (!g.navigation_debug_edge_connections_instance.is_valid()) {
791 g.navigation_debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
792 }
793 if (!g.navigation_debug_edge_connections_mesh.is_valid()) {
794 g.navigation_debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
795 }
796
797 _update_octant_navigation_debug_edge_connections_mesh(p_key);
798 }
799#endif // DEBUG_ENABLED
800 }
801}
802
803void GridMap::_octant_exit_world(const OctantKey &p_key) {
804 ERR_FAIL_NULL(RenderingServer::get_singleton());
805 ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
806 ERR_FAIL_NULL(NavigationServer3D::get_singleton());
807
808 ERR_FAIL_COND(!octant_map.has(p_key));
809 Octant &g = *octant_map[p_key];
810 PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
811 PhysicsServer3D::get_singleton()->body_set_space(g.static_body, RID());
812
813 if (g.collision_debug_instance.is_valid()) {
814 RS::get_singleton()->instance_set_scenario(g.collision_debug_instance, RID());
815 }
816
817 for (int i = 0; i < g.multimesh_instances.size(); i++) {
818 RS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, RID());
819 }
820
821 for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
822 if (F.value.region.is_valid()) {
823 NavigationServer3D::get_singleton()->free(F.value.region);
824 F.value.region = RID();
825 }
826 if (F.value.navigation_mesh_debug_instance.is_valid()) {
827 RS::get_singleton()->free(F.value.navigation_mesh_debug_instance);
828 F.value.navigation_mesh_debug_instance = RID();
829 }
830 }
831
832#ifdef DEBUG_ENABLED
833 if (bake_navigation) {
834 if (g.navigation_debug_edge_connections_instance.is_valid()) {
835 RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_instance);
836 g.navigation_debug_edge_connections_instance = RID();
837 }
838 if (g.navigation_debug_edge_connections_mesh.is_valid()) {
839 RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_mesh->get_rid());
840 }
841 }
842#endif // DEBUG_ENABLED
843}
844
845void GridMap::_octant_clean_up(const OctantKey &p_key) {
846 ERR_FAIL_NULL(RenderingServer::get_singleton());
847 ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
848 ERR_FAIL_NULL(NavigationServer3D::get_singleton());
849
850 ERR_FAIL_COND(!octant_map.has(p_key));
851 Octant &g = *octant_map[p_key];
852
853 if (g.collision_debug.is_valid()) {
854 RS::get_singleton()->free(g.collision_debug);
855 }
856 if (g.collision_debug_instance.is_valid()) {
857 RS::get_singleton()->free(g.collision_debug_instance);
858 }
859
860 PhysicsServer3D::get_singleton()->free(g.static_body);
861
862 // Erase navigation
863 for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
864 if (E.value.region.is_valid()) {
865 NavigationServer3D::get_singleton()->free(E.value.region);
866 }
867 if (E.value.navigation_mesh_debug_instance.is_valid()) {
868 RS::get_singleton()->free(E.value.navigation_mesh_debug_instance);
869 }
870 }
871 g.navigation_cell_ids.clear();
872
873#ifdef DEBUG_ENABLED
874 if (bake_navigation) {
875 if (g.navigation_debug_edge_connections_instance.is_valid()) {
876 RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_instance);
877 g.navigation_debug_edge_connections_instance = RID();
878 }
879 if (g.navigation_debug_edge_connections_mesh.is_valid()) {
880 RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_mesh->get_rid());
881 }
882 }
883#endif // DEBUG_ENABLED
884
885 //erase multimeshes
886
887 for (int i = 0; i < g.multimesh_instances.size(); i++) {
888 RS::get_singleton()->free(g.multimesh_instances[i].instance);
889 RS::get_singleton()->free(g.multimesh_instances[i].multimesh);
890 }
891 g.multimesh_instances.clear();
892}
893
894void GridMap::_notification(int p_what) {
895 switch (p_what) {
896 case NOTIFICATION_ENTER_WORLD: {
897 last_transform = get_global_transform();
898
899 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
900 _octant_enter_world(E.key);
901 }
902
903 for (int i = 0; i < baked_meshes.size(); i++) {
904 RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, get_world_3d()->get_scenario());
905 RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
906 }
907 } break;
908
909 case NOTIFICATION_ENTER_TREE: {
910#ifdef DEBUG_ENABLED
911 if (bake_navigation && NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) {
912 _update_navigation_debug_edge_connections();
913 }
914#endif // DEBUG_ENABLED
915 _update_visibility();
916 } break;
917
918 case NOTIFICATION_TRANSFORM_CHANGED: {
919 Transform3D new_xform = get_global_transform();
920 if (new_xform == last_transform) {
921 break;
922 }
923 //update run
924 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
925 _octant_transform(E.key);
926 }
927
928 last_transform = new_xform;
929
930 for (int i = 0; i < baked_meshes.size(); i++) {
931 RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
932 }
933 } break;
934
935 case NOTIFICATION_EXIT_WORLD: {
936 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
937 _octant_exit_world(E.key);
938 }
939
940 //_queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
941 //_update_octants_callback();
942 //_update_area_instances();
943 for (int i = 0; i < baked_meshes.size(); i++) {
944 RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID());
945 }
946 } break;
947
948 case NOTIFICATION_VISIBILITY_CHANGED: {
949 _update_visibility();
950 } break;
951 }
952}
953
954void GridMap::_update_visibility() {
955 if (!is_inside_tree()) {
956 return;
957 }
958
959 for (KeyValue<OctantKey, Octant *> &e : octant_map) {
960 Octant *octant = e.value;
961 for (int i = 0; i < octant->multimesh_instances.size(); i++) {
962 const Octant::MultimeshInstance &mi = octant->multimesh_instances[i];
963 RS::get_singleton()->instance_set_visible(mi.instance, is_visible_in_tree());
964 }
965 }
966
967 for (int i = 0; i < baked_meshes.size(); i++) {
968 RS::get_singleton()->instance_set_visible(baked_meshes[i].instance, is_visible_in_tree());
969 }
970}
971
972void GridMap::_queue_octants_dirty() {
973 if (awaiting_update) {
974 return;
975 }
976
977 MessageQueue::get_singleton()->push_call(this, "_update_octants_callback");
978 awaiting_update = true;
979}
980
981void GridMap::_recreate_octant_data() {
982 recreating_octants = true;
983 HashMap<IndexKey, Cell, IndexKey> cell_copy = cell_map;
984 _clear_internal();
985 for (const KeyValue<IndexKey, Cell> &E : cell_copy) {
986 set_cell_item(Vector3i(E.key), E.value.item, E.value.rot);
987 }
988 recreating_octants = false;
989}
990
991void GridMap::_clear_internal() {
992 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
993 if (is_inside_world()) {
994 _octant_exit_world(E.key);
995 }
996
997 _octant_clean_up(E.key);
998 memdelete(E.value);
999 }
1000
1001 octant_map.clear();
1002 cell_map.clear();
1003}
1004
1005void GridMap::clear() {
1006 _clear_internal();
1007 clear_baked_meshes();
1008}
1009
1010#ifndef DISABLE_DEPRECATED
1011void GridMap::resource_changed(const Ref<Resource> &p_res) {
1012}
1013#endif
1014
1015void GridMap::_update_octants_callback() {
1016 if (!awaiting_update) {
1017 return;
1018 }
1019
1020 List<OctantKey> to_delete;
1021 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
1022 if (_octant_update(E.key)) {
1023 to_delete.push_back(E.key);
1024 }
1025 }
1026
1027 while (to_delete.front()) {
1028 memdelete(octant_map[to_delete.front()->get()]);
1029 octant_map.erase(to_delete.front()->get());
1030 to_delete.pop_front();
1031 }
1032
1033 _update_visibility();
1034 awaiting_update = false;
1035}
1036
1037void GridMap::_bind_methods() {
1038 ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &GridMap::set_collision_layer);
1039 ClassDB::bind_method(D_METHOD("get_collision_layer"), &GridMap::get_collision_layer);
1040
1041 ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &GridMap::set_collision_mask);
1042 ClassDB::bind_method(D_METHOD("get_collision_mask"), &GridMap::get_collision_mask);
1043
1044 ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &GridMap::set_collision_mask_value);
1045 ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &GridMap::get_collision_mask_value);
1046
1047 ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value);
1048 ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value);
1049
1050 ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &GridMap::set_collision_priority);
1051 ClassDB::bind_method(D_METHOD("get_collision_priority"), &GridMap::get_collision_priority);
1052
1053 ClassDB::bind_method(D_METHOD("set_physics_material", "material"), &GridMap::set_physics_material);
1054 ClassDB::bind_method(D_METHOD("get_physics_material"), &GridMap::get_physics_material);
1055
1056 ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &GridMap::set_bake_navigation);
1057 ClassDB::bind_method(D_METHOD("is_baking_navigation"), &GridMap::is_baking_navigation);
1058
1059 ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &GridMap::set_navigation_map);
1060 ClassDB::bind_method(D_METHOD("get_navigation_map"), &GridMap::get_navigation_map);
1061
1062 ClassDB::bind_method(D_METHOD("set_mesh_library", "mesh_library"), &GridMap::set_mesh_library);
1063 ClassDB::bind_method(D_METHOD("get_mesh_library"), &GridMap::get_mesh_library);
1064
1065 ClassDB::bind_method(D_METHOD("set_cell_size", "size"), &GridMap::set_cell_size);
1066 ClassDB::bind_method(D_METHOD("get_cell_size"), &GridMap::get_cell_size);
1067
1068 ClassDB::bind_method(D_METHOD("set_cell_scale", "scale"), &GridMap::set_cell_scale);
1069 ClassDB::bind_method(D_METHOD("get_cell_scale"), &GridMap::get_cell_scale);
1070
1071 ClassDB::bind_method(D_METHOD("set_octant_size", "size"), &GridMap::set_octant_size);
1072 ClassDB::bind_method(D_METHOD("get_octant_size"), &GridMap::get_octant_size);
1073
1074 ClassDB::bind_method(D_METHOD("set_cell_item", "position", "item", "orientation"), &GridMap::set_cell_item, DEFVAL(0));
1075 ClassDB::bind_method(D_METHOD("get_cell_item", "position"), &GridMap::get_cell_item);
1076 ClassDB::bind_method(D_METHOD("get_cell_item_orientation", "position"), &GridMap::get_cell_item_orientation);
1077 ClassDB::bind_method(D_METHOD("get_cell_item_basis", "position"), &GridMap::get_cell_item_basis);
1078 ClassDB::bind_method(D_METHOD("get_basis_with_orthogonal_index", "index"), &GridMap::get_basis_with_orthogonal_index);
1079 ClassDB::bind_method(D_METHOD("get_orthogonal_index_from_basis", "basis"), &GridMap::get_orthogonal_index_from_basis);
1080
1081 ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &GridMap::local_to_map);
1082 ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &GridMap::map_to_local);
1083
1084 ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback);
1085#ifndef DISABLE_DEPRECATED
1086 ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed);
1087#endif
1088
1089 ClassDB::bind_method(D_METHOD("set_center_x", "enable"), &GridMap::set_center_x);
1090 ClassDB::bind_method(D_METHOD("get_center_x"), &GridMap::get_center_x);
1091 ClassDB::bind_method(D_METHOD("set_center_y", "enable"), &GridMap::set_center_y);
1092 ClassDB::bind_method(D_METHOD("get_center_y"), &GridMap::get_center_y);
1093 ClassDB::bind_method(D_METHOD("set_center_z", "enable"), &GridMap::set_center_z);
1094 ClassDB::bind_method(D_METHOD("get_center_z"), &GridMap::get_center_z);
1095
1096 ClassDB::bind_method(D_METHOD("clear"), &GridMap::clear);
1097
1098 ClassDB::bind_method(D_METHOD("get_used_cells"), &GridMap::get_used_cells);
1099 ClassDB::bind_method(D_METHOD("get_used_cells_by_item", "item"), &GridMap::get_used_cells_by_item);
1100
1101 ClassDB::bind_method(D_METHOD("get_meshes"), &GridMap::get_meshes);
1102 ClassDB::bind_method(D_METHOD("get_bake_meshes"), &GridMap::get_bake_meshes);
1103 ClassDB::bind_method(D_METHOD("get_bake_mesh_instance", "idx"), &GridMap::get_bake_mesh_instance);
1104
1105 ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);
1106 ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
1107
1108 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
1109 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material", "get_physics_material");
1110 ADD_GROUP("Cell", "cell_");
1111 ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size", PROPERTY_HINT_NONE, "suffix:m"), "set_cell_size", "get_cell_size");
1112 ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size");
1113 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_center_x"), "set_center_x", "get_center_x");
1114 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_center_y"), "set_center_y", "get_center_y");
1115 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_center_z"), "set_center_z", "get_center_z");
1116 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_scale"), "set_cell_scale", "get_cell_scale");
1117 ADD_GROUP("Collision", "collision_");
1118 ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
1119 ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
1120 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
1121 ADD_GROUP("Navigation", "");
1122 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation");
1123
1124 BIND_CONSTANT(INVALID_CELL_ITEM);
1125
1126 ADD_SIGNAL(MethodInfo("cell_size_changed", PropertyInfo(Variant::VECTOR3, "cell_size")));
1127 ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed));
1128}
1129
1130void GridMap::set_cell_scale(float p_scale) {
1131 cell_scale = p_scale;
1132 _recreate_octant_data();
1133}
1134
1135float GridMap::get_cell_scale() const {
1136 return cell_scale;
1137}
1138
1139TypedArray<Vector3i> GridMap::get_used_cells() const {
1140 TypedArray<Vector3i> a;
1141 a.resize(cell_map.size());
1142 int i = 0;
1143 for (const KeyValue<IndexKey, Cell> &E : cell_map) {
1144 Vector3i p(E.key.x, E.key.y, E.key.z);
1145 a[i++] = p;
1146 }
1147
1148 return a;
1149}
1150
1151TypedArray<Vector3i> GridMap::get_used_cells_by_item(int p_item) const {
1152 TypedArray<Vector3i> a;
1153 for (const KeyValue<IndexKey, Cell> &E : cell_map) {
1154 if ((int)E.value.item == p_item) {
1155 Vector3i p(E.key.x, E.key.y, E.key.z);
1156 a.push_back(p);
1157 }
1158 }
1159
1160 return a;
1161}
1162
1163Array GridMap::get_meshes() const {
1164 if (mesh_library.is_null()) {
1165 return Array();
1166 }
1167
1168 Vector3 ofs = _get_offset();
1169 Array meshes;
1170
1171 for (const KeyValue<IndexKey, Cell> &E : cell_map) {
1172 int id = E.value.item;
1173 if (!mesh_library->has_item(id)) {
1174 continue;
1175 }
1176 Ref<Mesh> mesh = mesh_library->get_item_mesh(id);
1177 if (mesh.is_null()) {
1178 continue;
1179 }
1180
1181 IndexKey ik = E.key;
1182
1183 Vector3 cellpos = Vector3(ik.x, ik.y, ik.z);
1184
1185 Transform3D xform;
1186
1187 xform.basis = _ortho_bases[E.value.rot];
1188
1189 xform.set_origin(cellpos * cell_size + ofs);
1190 xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
1191
1192 meshes.push_back(xform * mesh_library->get_item_mesh_transform(id));
1193 meshes.push_back(mesh);
1194 }
1195
1196 return meshes;
1197}
1198
1199Vector3 GridMap::_get_offset() const {
1200 return Vector3(
1201 cell_size.x * 0.5 * int(center_x),
1202 cell_size.y * 0.5 * int(center_y),
1203 cell_size.z * 0.5 * int(center_z));
1204}
1205
1206void GridMap::clear_baked_meshes() {
1207 ERR_FAIL_NULL(RenderingServer::get_singleton());
1208 for (int i = 0; i < baked_meshes.size(); i++) {
1209 RS::get_singleton()->free(baked_meshes[i].instance);
1210 }
1211 baked_meshes.clear();
1212
1213 _recreate_octant_data();
1214}
1215
1216void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texel_size) {
1217 if (!mesh_library.is_valid()) {
1218 return;
1219 }
1220
1221 //generate
1222 HashMap<OctantKey, HashMap<Ref<Material>, Ref<SurfaceTool>>, OctantKey> surface_map;
1223
1224 for (KeyValue<IndexKey, Cell> &E : cell_map) {
1225 IndexKey key = E.key;
1226
1227 int item = E.value.item;
1228 if (!mesh_library->has_item(item)) {
1229 continue;
1230 }
1231
1232 Ref<Mesh> mesh = mesh_library->get_item_mesh(item);
1233 if (!mesh.is_valid()) {
1234 continue;
1235 }
1236
1237 Vector3 cellpos = Vector3(key.x, key.y, key.z);
1238 Vector3 ofs = _get_offset();
1239
1240 Transform3D xform;
1241
1242 xform.basis = _ortho_bases[E.value.rot];
1243 xform.set_origin(cellpos * cell_size + ofs);
1244 xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
1245
1246 OctantKey ok;
1247 ok.x = key.x / octant_size;
1248 ok.y = key.y / octant_size;
1249 ok.z = key.z / octant_size;
1250
1251 if (!surface_map.has(ok)) {
1252 surface_map[ok] = HashMap<Ref<Material>, Ref<SurfaceTool>>();
1253 }
1254
1255 HashMap<Ref<Material>, Ref<SurfaceTool>> &mat_map = surface_map[ok];
1256
1257 for (int i = 0; i < mesh->get_surface_count(); i++) {
1258 if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
1259 continue;
1260 }
1261
1262 Ref<Material> surf_mat = mesh->surface_get_material(i);
1263 if (!mat_map.has(surf_mat)) {
1264 Ref<SurfaceTool> st;
1265 st.instantiate();
1266 st->begin(Mesh::PRIMITIVE_TRIANGLES);
1267 st->set_material(surf_mat);
1268 mat_map[surf_mat] = st;
1269 }
1270
1271 mat_map[surf_mat]->append_from(mesh, i, xform);
1272 }
1273 }
1274
1275 for (KeyValue<OctantKey, HashMap<Ref<Material>, Ref<SurfaceTool>>> &E : surface_map) {
1276 Ref<ArrayMesh> mesh;
1277 mesh.instantiate();
1278 for (KeyValue<Ref<Material>, Ref<SurfaceTool>> &F : E.value) {
1279 F.value->commit(mesh);
1280 }
1281
1282 BakedMesh bm;
1283 bm.mesh = mesh;
1284 bm.instance = RS::get_singleton()->instance_create();
1285 RS::get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
1286 RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
1287 if (is_inside_tree()) {
1288 RS::get_singleton()->instance_set_scenario(bm.instance, get_world_3d()->get_scenario());
1289 RS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
1290 }
1291
1292 if (p_gen_lightmap_uv) {
1293 mesh->lightmap_unwrap(get_global_transform(), p_lightmap_uv_texel_size);
1294 }
1295 baked_meshes.push_back(bm);
1296 }
1297
1298 _recreate_octant_data();
1299}
1300
1301Array GridMap::get_bake_meshes() {
1302 if (!baked_meshes.size()) {
1303 make_baked_meshes(true);
1304 }
1305
1306 Array arr;
1307 for (int i = 0; i < baked_meshes.size(); i++) {
1308 arr.push_back(baked_meshes[i].mesh);
1309 arr.push_back(Transform3D());
1310 }
1311
1312 return arr;
1313}
1314
1315RID GridMap::get_bake_mesh_instance(int p_idx) {
1316 ERR_FAIL_INDEX_V(p_idx, baked_meshes.size(), RID());
1317 return baked_meshes[p_idx].instance;
1318}
1319
1320GridMap::GridMap() {
1321 set_notify_transform(true);
1322#ifdef DEBUG_ENABLED
1323 NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed));
1324 NavigationServer3D::get_singleton()->connect("navigation_debug_changed", callable_mp(this, &GridMap::_update_navigation_debug_edge_connections));
1325#endif // DEBUG_ENABLED
1326}
1327
1328#ifdef DEBUG_ENABLED
1329void GridMap::_update_navigation_debug_edge_connections() {
1330 if (bake_navigation) {
1331 for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
1332 _update_octant_navigation_debug_edge_connections_mesh(E.key);
1333 }
1334 }
1335}
1336
1337void GridMap::_navigation_map_changed(RID p_map) {
1338 if (bake_navigation && is_inside_tree() && p_map == get_world_3d()->get_navigation_map()) {
1339 _update_navigation_debug_edge_connections();
1340 }
1341}
1342#endif // DEBUG_ENABLED
1343
1344GridMap::~GridMap() {
1345 clear();
1346#ifdef DEBUG_ENABLED
1347 NavigationServer3D::get_singleton()->disconnect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed));
1348 NavigationServer3D::get_singleton()->disconnect("navigation_debug_changed", callable_mp(this, &GridMap::_update_navigation_debug_edge_connections));
1349#endif // DEBUG_ENABLED
1350}
1351
1352#ifdef DEBUG_ENABLED
1353void GridMap::_update_octant_navigation_debug_edge_connections_mesh(const OctantKey &p_key) {
1354 ERR_FAIL_COND(!octant_map.has(p_key));
1355 Octant &g = *octant_map[p_key];
1356
1357 if (!NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) {
1358 if (g.navigation_debug_edge_connections_instance.is_valid()) {
1359 RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, false);
1360 }
1361 return;
1362 }
1363
1364 if (!is_inside_tree()) {
1365 return;
1366 }
1367
1368 if (!bake_navigation) {
1369 if (g.navigation_debug_edge_connections_instance.is_valid()) {
1370 RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, false);
1371 }
1372 return;
1373 }
1374
1375 if (!g.navigation_debug_edge_connections_instance.is_valid()) {
1376 g.navigation_debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
1377 }
1378
1379 if (!g.navigation_debug_edge_connections_mesh.is_valid()) {
1380 g.navigation_debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
1381 }
1382
1383 g.navigation_debug_edge_connections_mesh->clear_surfaces();
1384
1385 float edge_connection_margin = NavigationServer3D::get_singleton()->map_get_edge_connection_margin(get_world_3d()->get_navigation_map());
1386 float half_edge_connection_margin = edge_connection_margin * 0.5;
1387
1388 Vector<Vector3> vertex_array;
1389
1390 for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) {
1391 if (cell_map.has(F.key) && F.value.region.is_valid()) {
1392 int connections_count = NavigationServer3D::get_singleton()->region_get_connections_count(F.value.region);
1393 if (connections_count == 0) {
1394 continue;
1395 }
1396
1397 for (int i = 0; i < connections_count; i++) {
1398 Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(F.value.region, i);
1399 Vector3 connection_pathway_end = NavigationServer3D::get_singleton()->region_get_connection_pathway_end(F.value.region, i);
1400
1401 Vector3 direction_start_end = connection_pathway_start.direction_to(connection_pathway_end);
1402 Vector3 direction_end_start = connection_pathway_end.direction_to(connection_pathway_start);
1403
1404 Vector3 start_right_dir = direction_start_end.cross(Vector3(0, 1, 0));
1405 Vector3 start_left_dir = -start_right_dir;
1406
1407 Vector3 end_right_dir = direction_end_start.cross(Vector3(0, 1, 0));
1408 Vector3 end_left_dir = -end_right_dir;
1409
1410 Vector3 left_start_pos = connection_pathway_start + (start_left_dir * half_edge_connection_margin);
1411 Vector3 right_start_pos = connection_pathway_start + (start_right_dir * half_edge_connection_margin);
1412 Vector3 left_end_pos = connection_pathway_end + (end_right_dir * half_edge_connection_margin);
1413 Vector3 right_end_pos = connection_pathway_end + (end_left_dir * half_edge_connection_margin);
1414
1415 vertex_array.push_back(right_end_pos);
1416 vertex_array.push_back(left_start_pos);
1417 vertex_array.push_back(right_start_pos);
1418
1419 vertex_array.push_back(left_end_pos);
1420 vertex_array.push_back(right_end_pos);
1421 vertex_array.push_back(right_start_pos);
1422 }
1423 }
1424 }
1425
1426 if (vertex_array.size() == 0) {
1427 return;
1428 }
1429
1430 Ref<StandardMaterial3D> edge_connections_material = NavigationServer3D::get_singleton()->get_debug_navigation_edge_connections_material();
1431
1432 Array mesh_array;
1433 mesh_array.resize(Mesh::ARRAY_MAX);
1434 mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
1435
1436 g.navigation_debug_edge_connections_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mesh_array);
1437 g.navigation_debug_edge_connections_mesh->surface_set_material(0, edge_connections_material);
1438
1439 RS::get_singleton()->instance_set_base(g.navigation_debug_edge_connections_instance, g.navigation_debug_edge_connections_mesh->get_rid());
1440 RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, is_visible_in_tree());
1441 if (is_inside_tree()) {
1442 RS::get_singleton()->instance_set_scenario(g.navigation_debug_edge_connections_instance, get_world_3d()->get_scenario());
1443 }
1444
1445 bool enable_edge_connections = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_connections();
1446 if (!enable_edge_connections) {
1447 RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, false);
1448 }
1449}
1450#endif // DEBUG_ENABLED
1451