1/**************************************************************************/
2/* grid_map.h */
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#ifndef GRID_MAP_H
32#define GRID_MAP_H
33
34#include "scene/3d/node_3d.h"
35#include "scene/resources/mesh_library.h"
36#include "scene/resources/multimesh.h"
37
38//heh heh, godotsphir!! this shares no code and the design is completely different with previous projects i've done..
39//should scale better with hardware that supports instancing
40
41class PhysicsMaterial;
42
43class GridMap : public Node3D {
44 GDCLASS(GridMap, Node3D);
45
46 enum {
47 MAP_DIRTY_TRANSFORMS = 1,
48 MAP_DIRTY_INSTANCES = 2,
49 };
50
51 union IndexKey {
52 struct {
53 int16_t x;
54 int16_t y;
55 int16_t z;
56 };
57 uint64_t key = 0;
58
59 static uint32_t hash(const IndexKey &p_key) {
60 return hash_one_uint64(p_key.key);
61 }
62 _FORCE_INLINE_ bool operator<(const IndexKey &p_key) const {
63 return key < p_key.key;
64 }
65 _FORCE_INLINE_ bool operator==(const IndexKey &p_key) const {
66 return key == p_key.key;
67 }
68
69 _FORCE_INLINE_ operator Vector3i() const {
70 return Vector3i(x, y, z);
71 }
72
73 IndexKey(Vector3i p_vector) {
74 x = (int16_t)p_vector.x;
75 y = (int16_t)p_vector.y;
76 z = (int16_t)p_vector.z;
77 }
78 IndexKey() {}
79 };
80
81 /**
82 * @brief A Cell is a single cell in the cube map space; it is defined by its coordinates and the populating Item, identified by int id.
83 */
84 union Cell {
85 struct {
86 unsigned int item : 16;
87 unsigned int rot : 5;
88 unsigned int layer : 8;
89 };
90 uint32_t cell = 0;
91 };
92
93 /**
94 * @brief An Octant is a prism containing Cells, and possibly belonging to an Area.
95 * A GridMap can have multiple Octants.
96 */
97 struct Octant {
98 struct NavigationCell {
99 RID region;
100 Transform3D xform;
101 RID navigation_mesh_debug_instance;
102 uint32_t navigation_layers = 1;
103 };
104
105 struct MultimeshInstance {
106 RID instance;
107 RID multimesh;
108 struct Item {
109 int index = 0;
110 Transform3D transform;
111 IndexKey key;
112 };
113
114 Vector<Item> items; //tools only, for changing visibility
115 };
116
117 Vector<MultimeshInstance> multimesh_instances;
118 HashSet<IndexKey> cells;
119 RID collision_debug;
120 RID collision_debug_instance;
121#ifdef DEBUG_ENABLED
122 RID navigation_debug_edge_connections_instance;
123 Ref<ArrayMesh> navigation_debug_edge_connections_mesh;
124#endif // DEBUG_ENABLED
125
126 bool dirty = false;
127 RID static_body;
128 HashMap<IndexKey, NavigationCell> navigation_cell_ids;
129 };
130
131 union OctantKey {
132 struct {
133 int16_t x;
134 int16_t y;
135 int16_t z;
136 int16_t empty;
137 };
138
139 uint64_t key = 0;
140
141 static uint32_t hash(const OctantKey &p_key) {
142 return hash_one_uint64(p_key.key);
143 }
144 _FORCE_INLINE_ bool operator==(const OctantKey &p_key) const {
145 return key == p_key.key;
146 }
147
148 //OctantKey(const IndexKey& p_k, int p_item) { indexkey=p_k.key; item=p_item; }
149 OctantKey() {}
150 };
151
152 uint32_t collision_layer = 1;
153 uint32_t collision_mask = 1;
154 real_t collision_priority = 1.0;
155 Ref<PhysicsMaterial> physics_material;
156 bool bake_navigation = false;
157 RID map_override;
158 uint32_t navigation_layers = 1;
159
160 Transform3D last_transform;
161
162 bool _in_tree = false;
163 Vector3 cell_size = Vector3(2, 2, 2);
164 int octant_size = 8;
165 bool center_x = true;
166 bool center_y = true;
167 bool center_z = true;
168 float cell_scale = 1.0;
169
170 bool recreating_octants = false;
171
172 Ref<MeshLibrary> mesh_library;
173
174 HashMap<OctantKey, Octant *, OctantKey> octant_map;
175 HashMap<IndexKey, Cell, IndexKey> cell_map;
176
177 void _recreate_octant_data();
178
179 struct BakeLight {
180 RS::LightType type = RS::LightType::LIGHT_DIRECTIONAL;
181 Vector3 pos;
182 Vector3 dir;
183 float param[RS::LIGHT_PARAM_MAX] = {};
184 };
185
186 _FORCE_INLINE_ Vector3 _octant_get_offset(const OctantKey &p_key) const {
187 return Vector3(p_key.x, p_key.y, p_key.z) * cell_size * octant_size;
188 }
189
190 void _update_physics_bodies_collision_properties();
191 void _octant_enter_world(const OctantKey &p_key);
192 void _octant_exit_world(const OctantKey &p_key);
193 bool _octant_update(const OctantKey &p_key);
194 void _octant_clean_up(const OctantKey &p_key);
195 void _octant_transform(const OctantKey &p_key);
196#ifdef DEBUG_ENABLED
197 void _update_octant_navigation_debug_edge_connections_mesh(const OctantKey &p_key);
198 void _navigation_map_changed(RID p_map);
199 void _update_navigation_debug_edge_connections();
200#endif // DEBUG_ENABLED
201 bool awaiting_update = false;
202
203 void _queue_octants_dirty();
204 void _update_octants_callback();
205
206#ifndef DISABLE_DEPRECATED
207 void resource_changed(const Ref<Resource> &p_res);
208#endif
209
210 void _clear_internal();
211
212 Vector3 _get_offset() const;
213
214 struct BakedMesh {
215 Ref<Mesh> mesh;
216 RID instance;
217 };
218
219 Vector<BakedMesh> baked_meshes;
220
221protected:
222 bool _set(const StringName &p_name, const Variant &p_value);
223 bool _get(const StringName &p_name, Variant &r_ret) const;
224 void _get_property_list(List<PropertyInfo> *p_list) const;
225
226 void _notification(int p_what);
227 void _update_visibility();
228 static void _bind_methods();
229
230public:
231 enum {
232 INVALID_CELL_ITEM = -1
233 };
234
235 void set_collision_layer(uint32_t p_layer);
236 uint32_t get_collision_layer() const;
237
238 void set_collision_mask(uint32_t p_mask);
239 uint32_t get_collision_mask() const;
240
241 void set_collision_layer_value(int p_layer_number, bool p_value);
242 bool get_collision_layer_value(int p_layer_number) const;
243
244 void set_collision_mask_value(int p_layer_number, bool p_value);
245 bool get_collision_mask_value(int p_layer_number) const;
246
247 void set_collision_priority(real_t p_priority);
248 real_t get_collision_priority() const;
249
250 void set_physics_material(Ref<PhysicsMaterial> p_material);
251 Ref<PhysicsMaterial> get_physics_material() const;
252
253 Array get_collision_shapes() const;
254
255 void set_bake_navigation(bool p_bake_navigation);
256 bool is_baking_navigation();
257
258 void set_navigation_map(RID p_navigation_map);
259 RID get_navigation_map() const;
260
261 void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
262 Ref<MeshLibrary> get_mesh_library() const;
263
264 void set_cell_size(const Vector3 &p_size);
265 Vector3 get_cell_size() const;
266
267 void set_octant_size(int p_size);
268 int get_octant_size() const;
269
270 void set_center_x(bool p_enable);
271 bool get_center_x() const;
272 void set_center_y(bool p_enable);
273 bool get_center_y() const;
274 void set_center_z(bool p_enable);
275 bool get_center_z() const;
276
277 void set_cell_item(const Vector3i &p_position, int p_item, int p_rot = 0);
278 int get_cell_item(const Vector3i &p_position) const;
279 int get_cell_item_orientation(const Vector3i &p_position) const;
280 Basis get_cell_item_basis(const Vector3i &p_position) const;
281 Basis get_basis_with_orthogonal_index(int p_index) const;
282 int get_orthogonal_index_from_basis(const Basis &p_basis) const;
283
284 Vector3i local_to_map(const Vector3 &p_local_position) const;
285 Vector3 map_to_local(const Vector3i &p_map_position) const;
286
287 void set_cell_scale(float p_scale);
288 float get_cell_scale() const;
289
290 TypedArray<Vector3i> get_used_cells() const;
291 TypedArray<Vector3i> get_used_cells_by_item(int p_item) const;
292
293 Array get_meshes() const;
294
295 void clear_baked_meshes();
296 void make_baked_meshes(bool p_gen_lightmap_uv = false, float p_lightmap_uv_texel_size = 0.1);
297
298 void clear();
299
300 Array get_bake_meshes();
301 RID get_bake_mesh_instance(int p_idx);
302
303 GridMap();
304 ~GridMap();
305};
306
307#endif // GRID_MAP_H
308