From 2219c4c8bd621388af6f8841e9a18edfce4549c4 Mon Sep 17 00:00:00 2001 From: sams Date: Fri, 14 Nov 2014 23:43:35 -0600 Subject: [PATCH] Added a cache for tile blending calculations. --- copying.md | 2 +- cpp/coord/tile.h | 14 ++++++-- cpp/game_main.cpp | 2 +- cpp/pathfinding/path.h | 15 --------- cpp/terrain/terrain.cpp | 60 ++++++++++++++++++++++++++++------ cpp/terrain/terrain.h | 14 +++++++- cpp/terrain/terrain_chunk.cpp | 7 ++++ cpp/terrain/terrain_chunk.h | 5 +++ cpp/terrain/terrain_object.cpp | 2 +- 9 files changed, 90 insertions(+), 31 deletions(-) diff --git a/copying.md b/copying.md index 14565c7b0b..b54e309ed4 100644 --- a/copying.md +++ b/copying.md @@ -38,7 +38,7 @@ _the openage authors_ are: | James Hagborg | blucoat | jameshagborg@gmail.com | | Prashanth Jonnala | jprashanth | prashanth.neo@gmail.com | | Jonathan Remnant | Jon0 | jono4728@gmail.com | -| Sam Schetterer | schets | samschet@gmail.com | +| Sam Schetterer | sams, schets | samschet@gmail.com | If you're a first-time commiter, add yourself to the above list. This is not just for legal reasons, but also to keep an overview of all those nicknames. diff --git a/cpp/coord/tile.h b/cpp/coord/tile.h index 72b87644d0..0ee23cd89b 100644 --- a/cpp/coord/tile.h +++ b/cpp/coord/tile.h @@ -2,9 +2,10 @@ #ifndef OPENAGE_COORD_TILE_H_ #define OPENAGE_COORD_TILE_H_ +#include +#include "../util/misc.h" #include "decl.h" - #include "phys2.h" #define MEMBERS ne, se @@ -48,5 +49,14 @@ struct tile_delta { #undef RELATIVE_TYPE #undef ABSOLUTE_TYPE #undef SCALAR_TYPE - +namespace std{ +template<> +struct hash{ + size_t operator ()(const openage::coord::tile& pos) const{ + size_t nehash = hash{}(pos.ne); + size_t sehash = hash{}(pos.se); + return openage::util::rol(nehash) ^ sehash; + } +}; +} //namespace std #endif diff --git a/cpp/game_main.cpp b/cpp/game_main.cpp index 6df2c7b1aa..86ab6cdcd4 100644 --- a/cpp/game_main.cpp +++ b/cpp/game_main.cpp @@ -357,7 +357,7 @@ bool GameMain::on_input(SDL_Event *e) { mousepos_tile.se); TerrainChunk *chunk = terrain->get_create_chunk(mousepos_tile); - chunk->get_data(mousepos_tile)->terrain_id = editor_current_terrain; + chunk->set_id(mousepos_tile, editor_current_terrain); } else if (clicking_active and e->button.button == SDL_BUTTON_RIGHT and !construct_mode and selected_unit) { TerrainChunk *chunk = terrain->get_chunk(mousepos_tile); diff --git a/cpp/pathfinding/path.h b/cpp/pathfinding/path.h index c98b1c4521..62269e9a2b 100644 --- a/cpp/pathfinding/path.h +++ b/cpp/pathfinding/path.h @@ -212,21 +212,6 @@ struct hash { return openage::util::rol(nehash) ^ sehash; } }; - -/** - * Hash function for tiles - * - * TODO: relocate to coord/ - */ -template <> -struct hash { - size_t operator ()(const openage::coord::tile &tile) const { - size_t nehash = std::hash {}(tile.ne); - size_t sehash = std::hash {}(tile.se); - return openage::util::rol(nehash) ^ sehash; - } -}; - /** * Hash function for phys3 coordinates. * diff --git a/cpp/terrain/terrain.cpp b/cpp/terrain/terrain.cpp index 7f077d63e0..dd6a67461e 100644 --- a/cpp/terrain/terrain.cpp +++ b/cpp/terrain/terrain.cpp @@ -118,7 +118,7 @@ bool Terrain::fill(const int *data, coord::tile_delta size) { } int terrain_id = data[pos.ne * size.ne + pos.se]; TerrainChunk *chunk = this->get_create_chunk(pos); - chunk->get_data(pos)->terrain_id = terrain_id; + chunk->set_id(pos, terrain_id); } } return was_cut; @@ -127,6 +127,11 @@ bool Terrain::fill(const int *data, coord::tile_delta size) { void Terrain::attach_chunk(TerrainChunk *new_chunk, coord::chunk position, bool manually_created) { + + //TODO only modify the relevant tile coordinates + this->blend_cache.clear(); + this->unblend_cache.clear(); + new_chunk->set_terrain(this); new_chunk->manually_created = manually_created; log::dbg("inserting new chunk at (%02d,%02d)", position.ne, position.se); @@ -179,6 +184,13 @@ TerrainChunk *Terrain::get_create_chunk(coord::tile position) { return this->get_create_chunk(position.to_chunk()); } +void Terrain::set_id(coord::tile position, int id){ + this->remove_cache_pos(position); + if(auto* content = this->get_data(position)){ + content->terrain_id = id; + } +} + TileContent *Terrain::get_data(coord::tile position) { TerrainChunk *c = this->get_chunk(position.to_chunk()); if (c == nullptr) { @@ -311,6 +323,18 @@ bool Terrain::check_tile_position(coord::tile pos) { } +void Terrain::remove_cache_pos(coord::tile pos) { + auto rm_tile = [this](coord::tile tpos){ + this->blend_cache.erase(tpos); + this->unblend_cache.erase(tpos); + }; + + rm_tile(pos); + for(auto offset : neigh_offsets){ + rm_tile(pos + offset); + } +} + void Terrain::draw(Engine *engine) { // TODO: move this draw invokation to a render manager. // it can reorder the draw instructions and minimize texture switching. @@ -414,13 +438,31 @@ struct terrain_render_data Terrain::create_draw_advice(coord::tile ab, size_t tiles_count = std::abs(cf.ne - gb.ne) * std::abs(cf.se - gb.se); tiles->reserve(tiles_count); + std::unordered_map* cache; + if(this->blending_enabled){ + cache = &blend_cache; + } + else{ + cache = &unblend_cache; + } // sweep the whole rhombus area for (coord::tile tilepos = gb; tilepos.ne <= (ssize_t) cf.ne; tilepos.ne++) { for (tilepos.se = gb.se; tilepos.se <= (ssize_t) cf.se; tilepos.se++) { // get the terrain tile drawing data - auto tile = this->create_tile_advice(tilepos); - tiles->push_back(tile); + auto check = [cache, tilepos, this](){ + auto tile_iter = cache->find(tilepos); + if(tile_iter != cache->end()){ + return tile_iter->second; + } + else{ + auto pair = cache->emplace(tilepos, + this->create_tile_advice(tilepos)); + return pair.first->second; + } + }; + + tiles->push_back(check()); // get the object standing on the tile // TODO: make the terrain independent of objects standing on it. @@ -491,7 +533,6 @@ struct tile_draw_data Terrain::create_tile_advice(coord::tile position) { // create the draw_masks from the calculated influences this->calculate_masks(position, &tile, &influence_group); } - return tile; } @@ -509,7 +550,6 @@ void Terrain::get_neighbors(coord::tile basepos, // calculate the pos of the neighbor tile coord::tile neigh_pos = basepos + neigh_offsets[neigh_id]; - // get the neighbor data TileContent *neigh_content = this->get_data(neigh_pos); // chunk for neighbor or single tile is not existant @@ -649,11 +689,11 @@ void Terrain::calculate_masks(coord::tile position, int adjacent_mask_id = -1; /* neighbor ids: - 0 - 7 1 => 8 neighbors that can have influence on - 6 @ 2 the mask id selection. - 5 3 - 4 + 0 + 7 1 => 8 neighbors that can have influence on + 6 @ 2 the mask id selection. + 5 3 + 4 */ // filter adjacent and diagonal influences neighbor_id: 76543210 diff --git a/cpp/terrain/terrain.h b/cpp/terrain/terrain.h index a229439e8a..26c68d2235 100644 --- a/cpp/terrain/terrain.h +++ b/cpp/terrain/terrain.h @@ -162,12 +162,17 @@ class Terrain { bool is_infinite); ~Terrain(); - bool blending_enabled; //!< is terrain blending active. increases memory accesses by factor ~8 + bool blending_enabled; //!< is terrain blending active. bool infinite; //!< chunks are automagically created as soon as they are referenced coord::tile limit_positive, limit_negative; //!< for non-infinite terrains, this is the size limit. //TODO: non-square shaped terrain bounds + /** + * Sets the id for the given tile and notifies the engine + */ + void set_id(coord::tile pos, int id); + /** * fill the terrain with given terrain_id values. * @returns whether the data filled on the terrain was cut because of @@ -325,6 +330,11 @@ class Terrain { */ struct tile_draw_data create_tile_advice(coord::tile position); + /** + * Informs the terrain that the given tile has been modified + */ + void remove_cache_pos(coord::tile pos); + /** * gather neighbors of a given base tile. * @@ -363,6 +373,8 @@ class Terrain { * maps chunk coordinates to chunks. */ std::unordered_map chunks; + std::unordered_map blend_cache; + std::unordered_map unblend_cache; Texture **textures; Texture **blending_masks; diff --git a/cpp/terrain/terrain_chunk.cpp b/cpp/terrain/terrain_chunk.cpp index df1b00d415..c6ebc0e324 100644 --- a/cpp/terrain/terrain_chunk.cpp +++ b/cpp/terrain/terrain_chunk.cpp @@ -42,6 +42,13 @@ TerrainChunk::~TerrainChunk() { delete[] this->data; } +void TerrainChunk::set_id(coord::tile pos, int id){ + this->terrain->remove_cache_pos(pos); + if(auto* content = this->get_data(pos)){ + content->terrain_id = id; + } +} + TileContent *TerrainChunk::get_data(coord::tile pos) { return this->get_data(this->tile_position_neigh(pos)); } diff --git a/cpp/terrain/terrain_chunk.h b/cpp/terrain/terrain_chunk.h index 7a9628fe68..6faa7c1d36 100644 --- a/cpp/terrain/terrain_chunk.h +++ b/cpp/terrain/terrain_chunk.h @@ -72,6 +72,11 @@ class TerrainChunk { * the 8 neighbors this chunk has. */ chunk_neighbors neighbors; + + /** + * Sets the id for the given tile and notifies the engine + */ + void set_id(coord::tile pos, int id); /** * draws the terrain chunk on screen. diff --git a/cpp/terrain/terrain_object.cpp b/cpp/terrain/terrain_object.cpp index 66f43d7f51..e1aff860b7 100644 --- a/cpp/terrain/terrain_object.cpp +++ b/cpp/terrain/terrain_object.cpp @@ -100,6 +100,7 @@ void TerrainObject::set_ground(int id, int additional) { size_t tile_pos = chunk->tile_position_neigh(temp_pos); chunk->get_data(tile_pos)->terrain_id = id; + terrain->remove_cache_pos(temp_pos); temp_pos.se++; } temp_pos.se = this->pos.start.se - additional; @@ -203,7 +204,6 @@ tile_range SquareObject::get_range(const coord::phys3 &pos) const { // TODO temporary hacky solution until openage::coord has been properly fixed. coord::phys2 draw_pos = result.start.to_phys2(); - draw_pos.ne += ((this->size.ne - 1) * coord::settings::phys_per_tile) / 2; draw_pos.se += ((this->size.se - 1) * coord::settings::phys_per_tile) / 2;