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
120
|
#include "scenery.hpp"
#include "anim-atlas.hpp"
#include "compat/assert.hpp"
#include <algorithm>
namespace floormat {
scenery_proto::scenery_proto() noexcept = default;
scenery_proto::scenery_proto(const std::shared_ptr<anim_atlas>& atlas, const scenery& frame) noexcept :
atlas{atlas}, frame{frame}
{}
scenery_proto& scenery_proto::operator=(const scenery_proto&) noexcept = default;
scenery_proto::scenery_proto(const scenery_proto&) noexcept = default;
scenery_proto::operator bool() const noexcept { return atlas != nullptr; }
scenery_ref::scenery_ref(std::shared_ptr<anim_atlas>& atlas, scenery& frame) noexcept : atlas{atlas}, frame{frame} {}
scenery_ref::scenery_ref(const scenery_ref&) noexcept = default;
scenery_ref::scenery_ref(scenery_ref&&) noexcept = default;
scenery_ref& scenery_ref::operator=(const scenery_proto& proto) noexcept
{
atlas = proto.atlas;
frame = proto.frame;
return *this;
}
scenery_ref::operator scenery_proto() const noexcept { return { atlas, frame }; }
scenery_ref::operator bool() const noexcept { return atlas != nullptr; }
scenery::scenery() noexcept : scenery{none_tag_t{}} {}
scenery::scenery(none_tag_t) noexcept : passable{true} {}
scenery::scenery(generic_tag_t, const anim_atlas& atlas, rotation r, frame_t frame,
bool passable, bool blocks_view, bool active, bool interactive) :
frame{frame}, r{r}, type{scenery_type::generic},
passable{passable}, blocks_view{blocks_view}, active{active},
interactive{interactive}
{
fm_assert(r < rotation_COUNT);
fm_assert(frame < atlas.group(r).frames.size());
}
scenery::scenery(door_tag_t, const anim_atlas& atlas, rotation r, bool is_open) :
frame{frame_t(is_open ? 0 : atlas.group(r).frames.size()-1)},
r{r}, type{scenery_type::door},
passable{is_open}, blocks_view{!is_open}, interactive{true}
{
fm_assert(r < rotation_COUNT);
fm_assert(atlas.group(r).frames.size() >= 2);
}
bool scenery::can_activate() const noexcept
{
return interactive;
}
void scenery::update(float dt, const anim_atlas& anim)
{
if (!active)
return;
switch (type)
{
default:
case scenery_type::none:
case scenery_type::generic:
break;
case scenery_type::door:
const auto hz = std::uint8_t(anim.info().fps);
const auto nframes = (int)anim.info().nframes;
fm_debug_assert(anim.info().fps > 0 && anim.info().fps <= 0xff);
delta += dt;
const float frame_time = 1.f/hz;
const auto n = int(delta / frame_time);
delta -= frame_time * n;
fm_debug_assert(delta >= 0);
const std::int8_t dir = closing ? 1 : -1;
const int fr = frame + dir*n;
active = fr > 0 && fr < nframes-1;
passable = fr <= 0;
blocks_view = !passable;
frame = (frame_t)std::clamp(fr, 0, nframes-1);
if (!active)
delta = closing = 0;
break;
}
}
bool scenery::activate(const anim_atlas& atlas)
{
if (active)
return false;
switch (type)
{
default:
case scenery_type::none:
case scenery_type::generic:
break;
case scenery_type::door:
fm_assert(frame == 0 || frame == atlas.info().nframes-1);
closing = frame == 0;
frame += closing ? 1 : -1;
active = true;
return true;
}
return false;
}
#ifdef __GNUG__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
bool scenery::operator==(const scenery&) const noexcept = default;
#ifdef __GNUG__
#pragma GCC diagnostic pop
#endif
} // namespace floormat
|