MyCurry/src/gamelib/worldgrid.cpp

157 lines
4.8 KiB
C++

/*
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
This file is part of MyCurry.
MyCurry is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
MyCurry is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MyCurry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "worldgrid.hpp"
#include "worldsizenotifiable.hpp"
#include <cassert>
#include <utility>
#include <algorithm>
namespace curry {
WorldGrid::WorldGrid (vec2us parTileSize) :
m_tile_size(parTileSize),
m_world_size(0),
m_layer_count(0)
{
}
const vec2us& WorldGrid::tile_size() const {
return m_tile_size;
}
const vec2us& WorldGrid::world_size() const {
return m_world_size;
}
const TileIndex* WorldGrid::tile (const vec2us& parIndex) const {
const std::size_t index = parIndex.x() + parIndex.y() * m_world_size.x();
assert(m_layer_count);
assert(not m_layers.empty());
assert(index < tile_count());
assert(index * m_layer_count + m_layer_count <= m_layers.size());
return m_layers.data() + index * m_layer_count;
}
void WorldGrid::add_layer (vec2us parWorldSize, const std::vector<TileIndex>& parLayer) {
assert(parLayer.size() == tile_count());
std::vector<TileIndex> new_vec;
new_vec.reserve((m_layer_count + 1) * tile_count());
auto curr_tiles = m_layers.cbegin();
for (auto tile : parLayer) {
std::copy_n(curr_tiles, m_layer_count, std::back_inserter(new_vec));
std::advance(curr_tiles, m_layer_count);
new_vec.push_back(tile);
}
++m_layer_count;
set_world_size(parWorldSize);
std::swap(m_layers, new_vec);
}
void WorldGrid::set_layers (vec2us parWorldSize, const std::vector<std::vector<TileIndex>>& parLayers) {
if (parLayers.empty()) {
unload_layers();
return;
}
assert(not parLayers.empty());
std::vector<TileIndex> new_vec;
new_vec.reserve(parLayers.size() * parLayers.front().size());
for (std::size_t z = 0; z < parLayers.front().size(); ++z) {
for (std::size_t t = 0; t < parLayers.size(); ++t) {
assert(parLayers[t].size() == parLayers.front().size());
new_vec.push_back(parLayers[t][z]);
}
}
m_layer_count = static_cast<uint16_t>(parLayers.size());
std::swap(m_layers, new_vec);
set_world_size(parWorldSize);
}
uint16_t WorldGrid::layer_count() const {
return m_layer_count;
}
std::size_t WorldGrid::tile_count() const {
assert((layer_count() and not m_layers.empty()) or (m_layers.size() % layer_count() == 0));
return (layer_count() ? m_layers.size() / layer_count() : 0);
}
void WorldGrid::unload_layers() {
m_layers.clear();
m_layer_count = 0;
}
void WorldGrid::set_world_size (const vec2us& parSize) {
if (parSize != m_world_size) {
m_world_size = parSize;
for (auto& observer : m_world_size_watchers) {
observer->world_size_changed(m_world_size, world_size_pixel(*this));
}
}
}
auto WorldGrid::register_observer (WorldSizeNotifiable* parWatcher) -> WorldSizeWatcherTicket {
assert(parWatcher);
return m_world_size_watchers.Add(parWatcher);
}
void WorldGrid::unregister_observer (WorldSizeWatcherTicket parTicket) {
m_world_size_watchers.Remove(parTicket);
}
void WorldGrid::set_tile_properties (const std::vector<TileProperty>& parProperties) {
m_tile_properties.resize(parProperties.size());
std::copy(parProperties.begin(), parProperties.end(), m_tile_properties.begin());
}
const TileProperty& WorldGrid::tile_property (const TileIndex* parIndex) const {
assert(parIndex);
assert(static_cast<size_t>(*parIndex) < m_tile_properties.size());
return m_tile_properties[static_cast<size_t>(*parIndex)];
}
vec2i world_size_pixel (const WorldGrid& parWorld) {
return parWorld.tile_size() * parWorld.world_size();
}
vec2us pixel_to_world_tile (const WorldGrid& parWorld, const vec2f& parPos) {
assert(position_is_on_map(parWorld, parPos));
const auto retval = vector_cast<vec2us>(
parPos / vector_cast<vec2f>(parWorld.tile_size())
);
assert(world_tile_to_pixel(parWorld, retval) <= parPos);
return retval;
}
vec2f world_tile_to_pixel (const WorldGrid& parWorld, const vec2us& parTile) {
assert(parTile < parWorld.world_size());
return vector_cast<vec2f>(parTile) * vector_cast<vec2f>(parWorld.tile_size());
}
bool position_is_on_map (const WorldGrid& parWorld, const vec2i& parPos) {
assert(parWorld.tile_size() > vec2us(0));
return parPos >= vec2i(0) and
parPos / vector_cast<vec2i>(parWorld.tile_size()) < parWorld.world_size();
}
} //namespace curry