Start writing the new coordinates classes.

I'm not sure I'm going down the right path, so I'm committing
what I have so far and putting this on hold.
This commit is contained in:
King_DuckZ 2017-01-30 18:40:05 +00:00
parent 67e8ceefa3
commit 0bae01fd3f
4 changed files with 190 additions and 0 deletions

View file

@ -70,6 +70,7 @@ add_executable(${PROJECT_NAME}
src/worldsizenotifiable.cpp src/worldsizenotifiable.cpp
src/worlditems.cpp src/worlditems.cpp
src/moveable.cpp src/moveable.cpp
src/singlecoordinate.cpp
) )
target_include_directories(${PROJECT_NAME} SYSTEM target_include_directories(${PROJECT_NAME} SYSTEM

53
src/coordinates.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "vector.hpp"
#include "singlecoordinate.hpp"
namespace vwr {
template <>
struct VectorWrapperInfo<std::array<::curry::SingleCoordinate, 2>> {
enum { dimensions = 2 };
typedef ::curry::SingleCoordinate scalar_type;
typedef std::array<scalar_type, dimensions> vector_type;
static scalar_type& get_at (size_t parIndex, vector_type& parVector) {
return parVector[parIndex];
}
};
} //namespace vwr
namespace curry {
using vec2c = vwr::Vec<std::array<SingleCoordinate, 2>>;
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

26
src/singlecoordinate.cpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

110
src/singlecoordinate.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "vector.hpp"
#include <cstdint>
#include <cassert>
#include <ciso646>
namespace curry {
namespace implem {
template <uint32_t V, uint32_t R=0, uint32_t I=5, bool=(I>0)>
struct Log2;
template <uint32_t V, uint32_t R, uint32_t I>
struct Log2<V, R, I, true> {
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 <uint32_t V, uint32_t R, uint32_t I>
struct Log2<V, R, I, false> {
enum {
result = R
};
};
template <uint32_t V>
struct NextPow2 {
static_assert(V > 0, "V must be greater than zero");
enum {
result = (1U << Log2<V - 1>::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<MaxTileSize>::result;
static constexpr const auto OffsetMask = implem::NextPow2<MaxTileSize>::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<uint32_t>(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