1 // Copyright 2013-2018 the openage authors. See copying.md for legal info.
2 
3 #pragma once
4 
5 #include <functional>
6 #include <memory>
7 #include <stddef.h>
8 #include <set>
9 #include <unordered_map>
10 #include <vector>
11 
12 #include "../assetmanager.h"
13 #include "../coord/chunk.h"
14 #include "../coord/phys.h"
15 #include "../coord/pixel.h"
16 #include "../coord/tile.h"
17 #include "../texture.h"
18 #include "../util/misc.h"
19 
20 namespace openage {
21 
22 class Engine;
23 class RenderOptions;
24 class TerrainChunk;
25 class TerrainObject;
26 
27 /**
28  * type that for terrain ids.
29  * it's signed so that -1 can indicate a missing tile.
30  * TODO: get rid of the signedness.
31  */
32 using terrain_t = int;
33 
34 /**
35  * hashing for chunk coordinates.
36  *
37  * this allows storage of chunk coords as keys in an unordered map.
38  */
39 struct coord_chunk_hash {
operatorcoord_chunk_hash40 	size_t operator ()(const coord::chunk &input) const {
41 		constexpr int half_size_t_bits = sizeof(size_t) * 4;
42 
43 		return ((size_t)input.ne << half_size_t_bits) | input.se;
44 	}
45 };
46 
47 
48 /**
49  * describes the properties of one terrain tile.
50  *
51  * this includes the terrain_id (ice, water, grass, ...)
52  * and the list of objects which have a bounding box overlapping the tile
53  */
54 class TileContent {
55 public:
56 	TileContent();
57 	~TileContent();
58 	terrain_t terrain_id;
59 	std::vector<TerrainObject *> obj;
60 };
61 
62 
63 /**
64  * coordinate offsets for getting tile neighbors by their id.
65  */
66 constexpr coord::tile_delta const neigh_offsets[] = {
67 	{ 1, -1},
68 	{ 1,  0},
69 	{ 1,  1},
70 	{ 0,  1},
71 	{-1,  1},
72 	{-1,  0},
73 	{-1, -1},
74 	{ 0, -1}
75 };
76 
77 
78 /**
79  * describes the state of a terrain tile.
80  */
81 enum class tile_state {
82 	missing,    //!< tile is not created yet
83 	existing,   //!< tile is already existing
84 	creatable,  //!< tile does not exist but can be created
85 	invalid,    //!< tile does not exist and can not be created
86 };
87 
88 
89 /**
90  * storage for influences by neighbor tiles.
91  */
92 struct influence {
93 	uint8_t direction;    //!< bitmask for influence directions, bit 0 = neighbor 0, etc.
94 	int priority;         //!< the blending priority for this influence
95 	terrain_t terrain_id; //!< the terrain id of the influence
96 };
97 
98 /**
99  * influences for one tile.
100  * as a tile has 8 adjacent and diagonal neighbors,
101  * the maximum number of influences is 8.
102  */
103 struct influence_group {
104 	int count;
105 	terrain_t terrain_ids[8];
106 	struct influence data[8];
107 };
108 
109 /**
110  * one influence on another tile.
111  */
112 struct neighbor_tile {
113 	terrain_t terrain_id;
114 	tile_state state;
115 	int priority;
116 };
117 
118 /**
119  * storage data for a single terrain tile.
120  */
121 struct tile_data {
122 	terrain_t terrain_id;
123 	coord::tile pos{0, 0};
124 	int subtexture_id;
125 	Texture *tex;
126 	int priority;
127 	int mask_id;
128 	int blend_mode;
129 	Texture *mask_tex;
130 	tile_state state;
131 };
132 
133 /**
134  * collection of drawing data for a single tile.
135  * because of influences, a maximum of 8+1 draws
136  * could be requested.
137  */
138 struct tile_draw_data {
139 	ssize_t count;
140 	struct tile_data data[9];
141 };
142 
143 /**
144  * the complete render instruction collection for the terrain.
145  * this is passed to the renderer and will be drawn on screen.
146  */
147 struct terrain_render_data {
148 	std::vector<struct tile_draw_data> tiles;
149 	std::set<TerrainObject *, util::less<TerrainObject *>> objects;
150 };
151 
152 /**
153  * specification for all available
154  * tile types and blending data
155  */
156 struct terrain_meta {
157 	size_t terrain_id_count;
158 	size_t blendmode_count;
159 
160 	std::vector<Texture *> textures;
161 	std::vector<Texture *> blending_masks;
162 
163 	std::unique_ptr<int[]> terrain_id_priority_map;
164 	std::unique_ptr<int[]> terrain_id_blendmode_map;
165 
166 	std::unique_ptr<influence[]> influences_buf;
167 };
168 
169 /**
170  * the terrain class is the main top-management interface
171  * for dealing with cost-benefit analysis to maximize company profits.
172  *
173  * actually this is just the entrypoint and container for the terrain chunks.
174  */
175 class Terrain {
176 public:
177 	Terrain(terrain_meta *meta, bool is_infinite);
178 	~Terrain();
179 
180 	bool infinite; //!< chunks are automagically created as soon as they are referenced
181 
182 	// TODO: finite terrain limits
183 	// TODO: non-square shaped terrain bounds
184 
185 	/**
186 	 * returns a list of all referenced chunks
187 	 */
188 	std::vector<coord::chunk> used_chunks() const;
189 
190 	/**
191 	 * fill the terrain with given terrain_id values.
192 	 * @returns whether the data filled on the terrain was cut because of
193 	 * the terrains size limit.
194 	 */
195 	bool fill(const int *data, const coord::tile_delta &size);
196 
197 	/**
198 	 * Attach a chunk to the terrain, to a given position.
199 	 *
200 	 * @param new_chunk The chunk to be attached
201 	 * @param position The chunk position where the chunk will be placed
202 	 * @param manually_created Was this chunk created manually? If true, it will not be free'd automatically
203 	 */
204 	void attach_chunk(TerrainChunk *new_chunk, const coord::chunk &position, bool manual=true);
205 
206 	/**
207 	 * get a terrain chunk by a given chunk position.
208 	 *
209 	 * @return the chunk if exists, nullptr else
210 	 */
211 	TerrainChunk *get_chunk(const coord::chunk &position);
212 
213 	/**
214 	 * get a terrain chunk by a given tile position.
215 	 *
216 	 * @return the chunk it exists, nullptr else
217 	 */
218 	TerrainChunk *get_chunk(const coord::tile &position);
219 
220 	/**
221 	 * get or create a terrain chunk for a given chunk position.
222 	 *
223 	 * @return the (maybe newly created) chunk
224 	 */
225 	TerrainChunk *get_create_chunk(const coord::chunk &position);
226 
227 	/**
228 	 * get or create a terrain chunk for a given tile position.
229 	 *
230 	 * @return the (maybe newly created) chunk
231 	 */
232 	TerrainChunk *get_create_chunk(const coord::tile &position);
233 
234 	/**
235 	 * return tile data for the given position.
236 	 *
237 	 * the only reason the chunks exist, is because of this data.
238 	 */
239 	TileContent *get_data(const coord::tile &position);
240 
241 	/**
242 	 * an object which contains the given point, null otherwise
243 	 */
244 	TerrainObject *obj_at_point(const coord::phys3 &point);
245 
246 	/**
247 	 * get the neighbor chunks of a given chunk.
248 	 *
249 	 *
250 	 * chunk neighbor ids:
251 	 *       0   / <- ne
252 	 *     7   1
253 	 *   6   @   2
254 	 *     5   3
255 	 *       4   \ <- se
256 	 *
257 	 *     ne se
258 	 *     0:  1 -1
259 	 *     1:  1  0
260 	 *     2:  1  1
261 	 *     3:  0  1
262 	 *     4: -1  1
263 	 *     5: -1  0
264 	 *     6: -1 -1
265 	 *     7:  0 -1
266 	 *
267 	 * @param position: the position of the center chunk.
268 	 */
269 	struct chunk_neighbors get_chunk_neighbors(const coord::chunk &position);
270 
271 	/**
272 	 * return the subtexture offset id for a given tile position.
273 	 * the maximum offset is determined by the atlas size.
274 	 *
275 	 * this function returns always the right value, so that neighbor tiles
276 	 * of the same terrain (like grass-grass) are matching (without blendomatic).
277 	 * -> e.g. grass only map.
278 	 */
279 	unsigned get_subtexture_id(const coord::tile &pos, unsigned atlas_size);
280 
281 	/**
282 	 * checks the creation state and premissions of a given tile position.
283 	 */
284 	tile_state check_tile(const coord::tile &position);
285 
286 	/**
287 	 * checks whether the given tile position is allowed to exist on this terrain.
288 	 */
289 	// TODO: rename to is_tile_position_valid
290 	bool check_tile_position(const coord::tile &position);
291 
292 	/**
293 	 * validate whether the given terrain id is available.
294 	 */
295 	bool validate_terrain(terrain_t terrain_id);
296 
297 	/**
298 	 * validate whether the given mask id is available.
299 	 */
300 	bool validate_mask(ssize_t mask_id);
301 
302 	/**
303 	 * return the blending priority for a given terrain id.
304 	 */
305 	int priority(terrain_t terrain_id);
306 
307 	/**
308 	 * return the blending mode/blendomatic mask set for a given terrain id.
309 	 */
310 	int blendmode(terrain_t terrain_id);
311 
312 	/**
313 	 * get the terrain texture for a given terrain id.
314 	 */
315 	Texture *texture(terrain_t terrain_id);
316 
317 	/**
318 	 * get the blendomatic mask with the given mask id.
319 	 */
320 	Texture *blending_mask(ssize_t mask_id);
321 
322 	/**
323 	 * return the blending mode id for two given neighbor ids.
324 	 */
325 	int get_blending_mode(terrain_t base_id, terrain_t neighbor_id);
326 
327 	/**
328 	 * draw the currently visible terrain area on screen.
329 	 * @param engine: the engine where the terrain should be drawn to.
330 	 */
331 	void draw(Engine *engine, RenderOptions *settings);
332 
333 	/**
334 	 * create the drawing instruction data.
335 	 *
336 	 * created draw data according to the given tile boundaries.
337 	 *
338 	 *
339 	 * @param ab: upper left tile
340 	 * @param cd: upper right tile
341 	 * @param ef: lower right tile
342 	 * @param gh: lower left tile
343 	 *
344 	 * @returns a drawing instruction struct that contains all information for rendering
345 	 */
346 	struct terrain_render_data create_draw_advice(const coord::tile &ab,
347 	                                              const coord::tile &cd,
348 	                                              const coord::tile &ef,
349 	                                              const coord::tile &gh,
350 	                                              bool blending_enabled);
351 
352 	/**
353 	 * create rendering and blending information for a single tile on the terrain.
354 	 */
355 	struct tile_draw_data create_tile_advice(coord::tile position, bool blending_enabled);
356 
357 	/**
358 	 * gather neighbors of a given base tile.
359 	 *
360 	 * @param basepos: the base position, around which the neighbors will be fetched
361 	 * @param neigh_tiles: the destination buffer where the neighbors will be stored
362 	 * @param influences_by_terrain_id: influence buffer that is reset in the same step
363 	 */
364 	void get_neighbors(coord::tile basepos,
365 	                   struct neighbor_tile *neigh_tiles,
366 	                   struct influence *influences_by_terrain_id);
367 
368 	/**
369 	 * look at neighbor tiles around the base_tile, and store the influence bits.
370 	 *
371 	 * @param base_tile: the base tile for which influences are calculated
372 	 * @param neigh_tiles: the neigbors of base_tile
373 	 * @param influences_by_terrain_id: influences will be stored to this buffer, as bitmasks
374 	 * @returns an influence group that describes the maximum 8 possible influences on the base_tile
375 	 */
376 	struct influence_group calculate_influences(struct tile_data *base_tile,
377 	                                            struct neighbor_tile *neigh_tiles,
378 	                                            struct influence *influences_by_terrain_id);
379 
380 	/**
381 	 * calculate blending masks for a given tile position.
382 	 *
383 	 * @param position: the base tile position, for which the masks are calculated
384 	 * @param tile_data: the buffer where the created drawing layers will be stored in
385 	 * @param influences: the buffer where calculated influences were stored to
386 	 *
387 	 * @see calculate_influences
388 	 */
389 	void calculate_masks(coord::tile position,
390 	                     struct tile_draw_data *tile_data,
391 	                     struct influence_group *influences);
392 
393 private:
394 
395 	/**
396 	 * terrain meta data
397 	 */
398 	terrain_meta *meta;
399 
400 	/**
401 	 * maps chunk coordinates to chunks.
402 	 */
403 	std::unordered_map<coord::chunk, TerrainChunk *, coord_chunk_hash> chunks;
404 
405 };
406 
407 } // namespace openage
408