forked from Ares-Developers/YRpp
-
Notifications
You must be signed in to change notification settings - Fork 30
/
Dir.h
119 lines (96 loc) · 3.07 KB
/
Dir.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#pragma once
#include <bit>
enum class DirType : unsigned char;
// North -> 0x0000
// South -> 0x8000
// ...
// Just a very simple BAM
struct DirStruct
{
public:
constexpr explicit DirStruct() noexcept : Raw { 0 } { }
constexpr explicit DirStruct(int raw) noexcept : Raw { static_cast<unsigned short>(raw) } { }
constexpr explicit DirStruct(double rad) noexcept { SetRadian<65536>(rad); }
constexpr explicit DirStruct(const DirType dir) noexcept { SetDir(dir); }
constexpr explicit DirStruct(const noinit_t&) noexcept { }
constexpr bool operator==(const DirStruct& another) const
{
return Raw == another.Raw;
}
constexpr bool operator!=(const DirStruct& another) const
{
return Raw != another.Raw;
}
constexpr void SetDir(DirType dir)
{
Raw = static_cast<unsigned short>(static_cast<unsigned char>(dir) * 256);
}
constexpr DirType GetDir() const
{
return static_cast<DirType>(Raw / 256);
}
// If you want to divide it into 32 facings, as 32 has 5 bits
// then you should type <5> here.
// So does the others.
template<size_t Bits>
constexpr size_t GetValue(size_t offset = 0) const
{
return TranslateFixedPoint<16, Bits>(Raw, offset);
}
template<size_t Bits>
constexpr void SetValue(size_t value, size_t offset = 0)
{
Raw = static_cast<unsigned short>(TranslateFixedPoint<Bits, 16>(value, offset));
}
template<size_t Count>
constexpr size_t GetFacing(size_t offset = 0) const
{
static_assert(std::has_single_bit(Count));
constexpr size_t Bits = std::bit_width(Count - 1);
return GetValue<Bits>(offset);
}
template<size_t Count>
constexpr void SetFacing(size_t value, size_t offset = 0)
{
static_assert(std::has_single_bit(Count));
constexpr size_t Bits = std::bit_width(Count - 1);
SetValue<Bits>(value, offset);
}
template<size_t FacingCount>
constexpr double GetRadian() const
{
static_assert(std::has_single_bit(FacingCount));
constexpr size_t Bits = std::bit_width(FacingCount - 1);
size_t value = GetValue<Bits>();
int dir = static_cast<int>(value) - FacingCount / 4; // LRotate 90 degrees
return dir * (-Math::TwoPi / FacingCount);
}
template<size_t FacingCount>
constexpr void SetRadian(double rad)
{
static_assert(std::has_single_bit(FacingCount));
constexpr size_t Bits = std::bit_width(FacingCount - 1);
constexpr size_t Max = (1 << Bits) - 1;
int dir = static_cast<int>(rad / (-Math::TwoPi / FacingCount));
size_t value = dir + FacingCount / 4; // RRotate 90 degrees
SetValue<Bits>(value & Max);
}
private:
template<size_t BitsFrom, size_t BitsTo>
constexpr static size_t TranslateFixedPoint(size_t value, size_t offset = 0)
{
constexpr size_t MaskIn = ((1u << BitsFrom) - 1);
constexpr size_t MaskOut = ((1u << BitsTo) - 1);
if constexpr (BitsFrom > BitsTo)
return (((((value & MaskIn) >> (BitsFrom - BitsTo - 1)) + 1) >> 1) + offset) & MaskOut;
else if constexpr (BitsFrom < BitsTo)
return (((value - offset) & MaskIn) << (BitsTo - BitsFrom)) & MaskOut;
else
return value & MaskOut;
}
public:
unsigned short Raw;
private:
unsigned short Padding;
};
static_assert(sizeof(DirStruct) == 4);