diff --git a/CMakeLists.txt b/CMakeLists.txt index ddae753..cd07e60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ add_executable(${PROJECT_NAME} src/worldsizenotifiable.cpp src/worlditems.cpp src/moveable.cpp + src/singlecoordinate.cpp ) target_include_directories(${PROJECT_NAME} SYSTEM diff --git a/src/coordinates.hpp b/src/coordinates.hpp new file mode 100644 index 0000000..d4d0b7a --- /dev/null +++ b/src/coordinates.hpp @@ -0,0 +1,53 @@ +/* + 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 . +*/ + +#pragma once + +#include "vector.hpp" +#include "singlecoordinate.hpp" + +namespace vwr { + template <> + struct VectorWrapperInfo> { + enum { dimensions = 2 }; + typedef ::curry::SingleCoordinate scalar_type; + typedef std::array vector_type; + static scalar_type& get_at (size_t parIndex, vector_type& parVector) { + return parVector[parIndex]; + } + }; +} //namespace vwr + +namespace curry { + using vec2c = vwr::Vec>; + + inline vec2i to_screen_coordinates (vec2c parVec, const vec2i& parWorldOffset, vec2us parTileSize) { + return vec2i( + parVec.x().screen_coordinate(parWorldOffset.x(), parTileSize.x()), + parVec.y().screen_coordinate(parWorldOffset.y(), parTileSize.y()) + ); + } + + inline vec2us to_tiles (vec2c parVec) { + return vec2us( + parVec.x().tile(), + parVec.y().tile() + ); + } +} //namespace curry diff --git a/src/singlecoordinate.cpp b/src/singlecoordinate.cpp new file mode 100644 index 0000000..781d3dc --- /dev/null +++ b/src/singlecoordinate.cpp @@ -0,0 +1,26 @@ +/* + 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 . +*/ + +#include "singlecoordinate.hpp" +#include "coordinates.hpp" + +namespace curry { + static_assert(implem::Log2<256>::result == 8, "Wrong logarithm result"); + static_assert(implem::Log2<255>::result == 7, "Wrong logarithm result"); +} //namespace curry diff --git a/src/singlecoordinate.hpp b/src/singlecoordinate.hpp new file mode 100644 index 0000000..2ca9460 --- /dev/null +++ b/src/singlecoordinate.hpp @@ -0,0 +1,110 @@ +/* + 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 . +*/ + +#pragma once + +#include "vector.hpp" +#include +#include +#include + +namespace curry { + namespace implem { + template 0)> + struct Log2; + + template + struct Log2 { + static constexpr const uint32_t b[5] = {0x2, 0xc, 0xf0, 0xff00, 0xffff0000}; + static constexpr const uint32_t S[5] = {1, 2, 4, 8, 16}; + enum { + result = Log2<(V & b[I - 1] ? V >> S[I - 1] : V), (V & b[I - 1] ? R | S[I - 1] : R), I - 1>::result + }; + }; + template + struct Log2 { + enum { + result = R + }; + }; + + template + struct NextPow2 { + static_assert(V > 0, "V must be greater than zero"); + enum { + result = (1U << Log2::result) + 1 + }; + }; + } //namespace implem + + class SingleCoordinate { + public: + SingleCoordinate() = default; + SingleCoordinate (const SingleCoordinate&) = default; + explicit SingleCoordinate (uint32_t parTile); + SingleCoordinate (uint32_t parTile, uint32_t parOffset); + ~SingleCoordinate() noexcept = default; + + int32_t screen_coordinate (int32_t parWorldOffset, uint32_t parTileSize) const; + uint32_t tile() const; + + private: + static constexpr const auto MaxTileSize = 128U; + static constexpr const auto OffsetBits = implem::Log2::result; + static constexpr const auto OffsetMask = implem::NextPow2::result - 1; + + uint32_t m_data; + }; + + inline int32_t SingleCoordinate::screen_coordinate (int32_t parWorldOffset, uint32_t parTileSize) const { + assert(parTileSize <= MaxTileSize); + return ((m_data - parWorldOffset) & OffsetMask) + + (static_cast(m_data - parWorldOffset) >> OffsetBits) * parTileSize; + } + + inline uint32_t SingleCoordinate::tile() const { + int beyond_tile; + const int offset = m_data & OffsetMask; + asm( + "xorl %%eax,%%eax\n\t" + "subl %1,%%eax\n\t" + "xorl %%eax,%%eax\n\t" + "adcl %%eax,0\n\t" + "movl %%eax,%0" + :"=r"(beyond_tile) + :"r"(offset) + :"%eax" + ); + assert(0 == beyond_tile or 1 == beyond_tile); + return (m_data >> OffsetBits) + beyond_tile; + } + + SingleCoordinate::SingleCoordinate (uint32_t parTile) : + m_data(parTile << OffsetBits) + { + assert(this->tile() == parTile); + } + + SingleCoordinate::SingleCoordinate (uint32_t parTile, uint32_t parOffset) : + m_data((parTile << OffsetBits) + (parOffset & OffsetMask)) + { + assert((not parOffset and this->tile() == parTile) or (this->tile() == parTile + 1)); + assert((m_data bitand OffsetMask) == parOffset); + } +} //namespace curry