1 /*************************************************************************/
2 /*  tile_map.h                                                           */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
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 #ifndef TILE_MAP_H
31 #define TILE_MAP_H
32 
33 #include "scene/2d/navigation2d.h"
34 #include "scene/2d/node_2d.h"
35 #include "scene/resources/tile_set.h"
36 #include "self_list.h"
37 #include "vset.h"
38 
39 class TileMap : public Node2D {
40 
41 	OBJ_TYPE(TileMap, Node2D);
42 
43 public:
44 	enum Mode {
45 		MODE_SQUARE,
46 		MODE_ISOMETRIC,
47 		MODE_CUSTOM
48 	};
49 
50 	enum HalfOffset {
51 		HALF_OFFSET_X,
52 		HALF_OFFSET_Y,
53 		HALF_OFFSET_DISABLED,
54 	};
55 
56 	enum TileOrigin {
57 		TILE_ORIGIN_TOP_LEFT,
58 		TILE_ORIGIN_CENTER,
59 		TILE_ORIGIN_BOTTOM_LEFT
60 	};
61 
62 private:
63 	Ref<TileSet> tile_set;
64 	Size2i cell_size;
65 	int quadrant_size;
66 	bool center_x, center_y;
67 	Mode mode;
68 	Matrix32 custom_transform;
69 	HalfOffset half_offset;
70 	bool use_kinematic;
71 	Navigation2D *navigation;
72 
73 	union PosKey {
74 
75 		struct {
76 			int16_t x;
77 			int16_t y;
78 		};
79 		uint32_t key;
80 
81 		//using a more precise comparison so the regions can be sorted later
82 		bool operator<(const PosKey &p_k) const { return (y == p_k.y) ? x < p_k.x : y < p_k.y; }
83 
PosKey(int16_t p_x,int16_t p_y)84 		PosKey(int16_t p_x, int16_t p_y) {
85 			x = p_x;
86 			y = p_y;
87 		}
PosKey()88 		PosKey() {
89 			x = 0;
90 			y = 0;
91 		}
92 	};
93 
94 	union Cell {
95 
96 		struct {
97 			int32_t id : 24;
98 			bool flip_h : 1;
99 			bool flip_v : 1;
100 			bool transpose : 1;
101 		};
102 
103 		uint32_t _u32t;
Cell()104 		Cell() { _u32t = 0; }
105 	};
106 
107 	Map<PosKey, Cell> tile_map;
108 	struct Quadrant {
109 
110 		Vector2 pos;
111 		List<RID> canvas_items;
112 		Vector<RID> bodies;
113 
114 		SelfList<Quadrant> dirty_list;
115 
116 		struct NavPoly {
117 			int id;
118 			Matrix32 xform;
119 		};
120 
121 		struct Occluder {
122 			RID id;
123 			Matrix32 xform;
124 		};
125 
126 		Map<PosKey, NavPoly> navpoly_ids;
127 		Map<PosKey, Occluder> occluder_instances;
128 
129 		VSet<PosKey> cells;
130 
131 		void operator=(const Quadrant &q) {
132 			pos = q.pos;
133 			canvas_items = q.canvas_items;
134 			bodies = q.bodies;
135 			cells = q.cells;
136 			navpoly_ids = q.navpoly_ids;
137 			occluder_instances = q.occluder_instances;
138 		}
QuadrantQuadrant139 		Quadrant(const Quadrant &q) :
140 				dirty_list(this) {
141 			pos = q.pos;
142 			canvas_items = q.canvas_items;
143 			bodies = q.bodies;
144 			cells = q.cells;
145 			occluder_instances = q.occluder_instances;
146 			navpoly_ids = q.navpoly_ids;
147 		}
QuadrantQuadrant148 		Quadrant() :
149 				dirty_list(this) {}
150 	};
151 
152 	Map<PosKey, Quadrant> quadrant_map;
153 
154 	SelfList<Quadrant>::List dirty_quadrant_list;
155 
156 	bool pending_update;
157 
158 	Rect2 rect_cache;
159 	bool rect_cache_dirty;
160 	Rect2 used_size_cache;
161 	bool used_size_cache_dirty;
162 	bool quadrant_order_dirty;
163 	bool y_sort_mode;
164 	float fp_adjust;
165 	float friction;
166 	float bounce;
167 	uint32_t collision_layer;
168 	uint32_t collision_mask;
169 
170 	TileOrigin tile_origin;
171 
172 	int occluder_light_mask;
173 
174 	void _fix_cell_transform(Matrix32 &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc);
175 
176 	Map<PosKey, Quadrant>::Element *_create_quadrant(const PosKey &p_qk);
177 	void _erase_quadrant(Map<PosKey, Quadrant>::Element *Q);
178 	void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q);
179 	void _recreate_quadrants();
180 	void _clear_quadrants();
181 	void _update_dirty_quadrants();
182 	void _update_quadrant_space(const RID &p_space);
183 	void _update_quadrant_transform();
184 	void _recompute_rect_cache();
185 
186 	void _update_all_items_material_state();
187 	_FORCE_INLINE_ void _update_item_material_state(const RID &p_canvas_item);
188 
189 	_FORCE_INLINE_ int _get_quadrant_size() const;
190 
191 	void _set_tile_data(const DVector<int> &p_data);
192 	DVector<int> _get_tile_data() const;
193 
_set_old_cell_size(int p_size)194 	void _set_old_cell_size(int p_size) { set_cell_size(Size2(p_size, p_size)); }
_get_old_cell_size()195 	int _get_old_cell_size() const { return cell_size.x; }
196 
197 	_FORCE_INLINE_ Vector2 _map_to_world(int p_x, int p_y, bool p_ignore_ofs = false) const;
198 
199 protected:
200 	void _notification(int p_what);
201 	static void _bind_methods();
202 
203 public:
204 	enum {
205 		INVALID_CELL = -1
206 	};
207 
208 	void set_tileset(const Ref<TileSet> &p_tileset);
209 	Ref<TileSet> get_tileset() const;
210 
211 	void set_cell_size(Size2 p_size);
212 	Size2 get_cell_size() const;
213 
214 	void set_quadrant_size(int p_size);
215 	int get_quadrant_size() const;
216 
217 	void set_center_x(bool p_enable);
218 	bool get_center_x() const;
219 	void set_center_y(bool p_enable);
220 	bool get_center_y() const;
221 
222 	void set_cell(int p_x, int p_y, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false);
223 	int get_cell(int p_x, int p_y) const;
224 	bool is_cell_x_flipped(int p_x, int p_y) const;
225 	bool is_cell_y_flipped(int p_x, int p_y) const;
226 	bool is_cell_transposed(int p_x, int p_y) const;
227 
228 	void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false);
229 	int get_cellv(const Vector2 &p_pos) const;
230 
231 	Rect2 get_item_rect() const;
232 
233 	void set_collision_layer(uint32_t p_layer);
234 	uint32_t get_collision_layer() const;
235 
236 	void set_collision_mask(uint32_t p_mask);
237 	uint32_t get_collision_mask() const;
238 
239 	void set_collision_layer_bit(int p_bit, bool p_value);
240 	bool get_collision_layer_bit(int p_bit) const;
241 
242 	void set_collision_mask_bit(int p_bit, bool p_value);
243 	bool get_collision_mask_bit(int p_bit) const;
244 
245 	void set_collision_use_kinematic(bool p_use_kinematic);
246 	bool get_collision_use_kinematic() const;
247 
248 	void set_collision_friction(float p_friction);
249 	float get_collision_friction() const;
250 
251 	void set_collision_bounce(float p_bounce);
252 	float get_collision_bounce() const;
253 
254 	void set_mode(Mode p_mode);
255 	Mode get_mode() const;
256 
257 	void set_half_offset(HalfOffset p_half_offset);
258 	HalfOffset get_half_offset() const;
259 
260 	void set_tile_origin(TileOrigin p_tile_origin);
261 	TileOrigin get_tile_origin() const;
262 
263 	void set_custom_transform(const Matrix32 &p_xform);
264 	Matrix32 get_custom_transform() const;
265 
266 	Matrix32 get_cell_transform() const;
267 	Vector2 get_cell_draw_offset() const;
268 
269 	Vector2 map_to_world(const Vector2 &p_pos, bool p_ignore_ofs = false) const;
270 	Vector2 world_to_map(const Vector2 &p_pos) const;
271 
272 	void set_y_sort_mode(bool p_enable);
273 	bool is_y_sort_mode_enabled() const;
274 
275 	Array get_used_cells() const;
276 	Array get_used_cells_by_id(int p_id) const;
277 	Rect2 get_used_rect(); // Not const because of cache
278 
279 	void set_occluder_light_mask(int p_mask);
280 	int get_occluder_light_mask() const;
281 
282 	virtual void set_light_mask(int p_light_mask);
283 
284 	virtual void set_material(const Ref<CanvasItemMaterial> &p_material);
285 
286 	virtual void set_use_parent_material(bool p_use_parent_material);
287 
288 	void clear();
289 
290 	TileMap();
291 	~TileMap();
292 };
293 
294 VARIANT_ENUM_CAST(TileMap::Mode);
295 VARIANT_ENUM_CAST(TileMap::HalfOffset);
296 VARIANT_ENUM_CAST(TileMap::TileOrigin);
297 
298 #endif // TILE_MAP_H
299