@@ -31,10 +31,10 @@ elseif(CMAKE_BUILD_TYPE STREQUAL Debug) | |||
add_compile_options(-g -Og) | |||
elseif(CMAKE_BUILD_TYPE STREQUAL DebugRelease) | |||
message(STATUS "Build mode: DebugRelease") | |||
add_compile_options(-g -O3) | |||
add_compile_options(-O3 -flto -DNDEBUG -g) | |||
elseif(CMAKE_BUILD_TYPE STREQUAL Release) | |||
message(STATUS "Build mode: Release") | |||
add_compile_options(-O3 -flto) | |||
add_compile_options(-O3 -flto -DNDEBUG) | |||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") | |||
else() | |||
message(FATAL_ERROR "CMAKE_BUILD_TYPE must be Debug or Release.") |
@@ -28,10 +28,25 @@ public: | |||
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]); | |||
} | |||
Tile::ID *getTileData(); | |||
Tile::ID getTileID(RelPos pos); | |||
void setTileID(RelPos pos, Tile::ID id, SDL_Texture *tex); | |||
void setTileData(RelPos pos, Tile::ID id); | |||
Tile::ID *getTileData() { | |||
assert(isActive()); | |||
return (Tile::ID *)data_.get(); | |||
} | |||
Tile::ID getTileID(RelPos pos) { | |||
return getTileData()[pos.y * CHUNK_WIDTH + pos.x]; | |||
} | |||
void setTileID(RelPos pos, Tile::ID id, SDL_Texture *tex) { | |||
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id; | |||
draw_list_.push_back({ pos, tex }); | |||
} | |||
void setTileData(RelPos pos, Tile::ID id) { | |||
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id; | |||
need_render_ = true; | |||
} | |||
void render(const Context &ctx, SDL_Renderer *rnd); | |||
void compress(); |
@@ -31,7 +31,7 @@ public: | |||
WorldPlane &addPlane(const std::string &gen); | |||
WorldPlane &addPlane() { return addPlane(default_world_gen_); } | |||
Tile &getTileByID(Tile::ID id); | |||
Tile &getTileByID(Tile::ID id) { return *tiles_[id]; } | |||
Tile::ID getTileID(const std::string &name); | |||
Tile &getTile(const std::string &name); | |||
Item &getItem(const std::string &name); |
@@ -35,8 +35,10 @@ public: | |||
bool hasChunk(ChunkPos pos); | |||
Chunk &getChunk(ChunkPos pos); | |||
Chunk &slowGetChunk(ChunkPos pos); | |||
void setTileID(TilePos pos, Tile::ID id); | |||
void setTile(TilePos pos, const std::string &name); | |||
Tile::ID getTileID(TilePos pos); | |||
Tile &getTile(TilePos pos); | |||
@@ -68,6 +70,7 @@ public: | |||
private: | |||
std::map<std::pair<int, int>, Chunk> chunks_; | |||
std::vector<Chunk *> active_chunks_; | |||
std::vector<std::pair<ChunkPos, Chunk *>> tick_chunks_; | |||
std::vector<std::unique_ptr<Entity>> entities_; | |||
std::deque<Chunk *> chunk_init_list_; |
@@ -15,25 +15,6 @@ namespace Swan { | |||
uint8_t *Chunk::renderbuf = new uint8_t[CHUNK_WIDTH * TILE_SIZE * CHUNK_HEIGHT * TILE_SIZE * 4]; | |||
Tile::ID *Chunk::getTileData() { | |||
assert(isActive()); | |||
return (Tile::ID *)data_.get(); | |||
} | |||
Tile::ID Chunk::getTileID(RelPos pos) { | |||
return getTileData()[pos.y * CHUNK_WIDTH + pos.x]; | |||
} | |||
void Chunk::setTileID(RelPos pos, Tile::ID id, SDL_Texture *tex) { | |||
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id; | |||
draw_list_.push_back({ pos, tex }); | |||
} | |||
void Chunk::setTileData(RelPos pos, Tile::ID id) { | |||
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id; | |||
need_render_ = true; | |||
} | |||
void Chunk::compress() { | |||
if (isCompressed()) | |||
return; |
@@ -11,7 +11,7 @@ namespace Swan { | |||
static void chunkLine(int l, WorldPlane &plane, ChunkPos &abspos, const Vec2i &dir) { | |||
for (int i = 0; i < l; ++i) { | |||
plane.getChunk(abspos); | |||
plane.slowGetChunk(abspos).keepActive(); | |||
abspos += dir; | |||
} | |||
} | |||
@@ -122,10 +122,6 @@ Tile::ID World::getTileID(const std::string &name) { | |||
return iter->second; | |||
} | |||
Tile &World::getTileByID(Tile::ID id) { | |||
return *tiles_[id]; | |||
} | |||
Tile &World::getTile(const std::string &name) { | |||
Tile::ID id = getTileID(name); | |||
return getTileByID(id); |
@@ -71,35 +71,18 @@ bool WorldPlane::hasChunk(ChunkPos pos) { | |||
// This function will be a bit weird because it's a really fucking hot function. | |||
Chunk &WorldPlane::getChunk(ChunkPos pos) { | |||
// This branch should be really predictable, there should basically never | |||
// be no active chunks | |||
if (active_chunks_.size() != 0) { | |||
// The last chunk should be the most actively used chunk | |||
Chunk *chunk = active_chunks_.back(); | |||
if (chunk->pos_ == pos) { | |||
chunk->keepActive(); | |||
// First, look through all chunks which have been in use this tick | |||
for (auto [chpos, chunk]: tick_chunks_) { | |||
if (chpos == pos) | |||
return *chunk; | |||
} | |||
// Linear search through a small array is probably faster than tree lookup. | |||
// Loop backwards because the hottest chunks should be at the end. | |||
for (ssize_t i = active_chunks_.size() - 2; i >= 0; --i) { | |||
chunk = active_chunks_[i]; | |||
if (chunk->pos_ == pos) { | |||
chunk->keepActive(); | |||
// Ensure that the hot chunk is at the end by bubbling this one up | |||
active_chunks_[i] = active_chunks_[i + 1]; | |||
active_chunks_[i + 1] = chunk; | |||
return *chunk; | |||
} | |||
} | |||
} | |||
// Slow path: Find a chunk in our global chunk map, | |||
// creating a new one if necessary | |||
Chunk &chunk = slowGetChunk(pos); | |||
tick_chunks_.push_back({ pos, &chunk }); | |||
return chunk; | |||
} | |||
Chunk &WorldPlane::slowGetChunk(ChunkPos pos) { | |||
auto iter = chunks_.find(pos); | |||
// Create chunk if that turns out to be necessary | |||
@@ -111,8 +94,8 @@ Chunk &WorldPlane::getChunk(ChunkPos pos) { | |||
active_chunks_.push_back(&chunk); | |||
chunk_init_list_.push_back(&chunk); | |||
// Otherwise, tell it that it should keep itself alive a bit longer | |||
} else { | |||
// Otherwise, it might not be active, so let's activate it | |||
} else if (!iter->second.isActive()) { | |||
iter->second.keepActive(); | |||
active_chunks_.push_back(&iter->second); | |||
chunk_init_list_.push_back(&iter->second); | |||
@@ -137,9 +120,7 @@ void WorldPlane::setTile(TilePos pos, const std::string &name) { | |||
} | |||
Tile::ID WorldPlane::getTileID(TilePos pos) { | |||
Chunk &chunk = getChunk(chunkPos(pos)); | |||
return chunk.getTileID(relPos(pos)); | |||
return getChunk(chunkPos(pos)).getTileID(relPos(pos)); | |||
} | |||
Tile &WorldPlane::getTile(TilePos pos) { | |||
@@ -255,6 +236,11 @@ void WorldPlane::update(float dt) { | |||
} | |||
void WorldPlane::tick(float dt) { | |||
// Any chunk which has been in use since last tick should be kept alive | |||
for (std::pair<ChunkPos, Chunk *> &ch: tick_chunks_) | |||
ch.second->keepActive(); | |||
tick_chunks_.clear(); | |||
for (auto &ent: entities_) | |||
ent->tick(getContext(), dt); | |||