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