Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
SequenceWorld3DSlot.cpp
Go to the documentation of this file.
2
3#include <cmath>
4#include <set>
5#include <utility>
6
7namespace monopoly::engine
8{
9 namespace
10 {
11 std::array<float, 3> sequencePoint(const sequence::Matrix3D& matrix,
12 float x, float y, float z) noexcept
13 {
14 const auto& m = matrix.values;
15 const float outX = m[0] * x + m[4] * y + m[8] * z + m[12];
16 const float outY = m[1] * x + m[5] * y + m[9] * z + m[13];
17 const float outZ = m[2] * x + m[6] * y + m[10] * z + m[14];
18 const float outW = m[3] * x + m[7] * y + m[11] * z + m[15];
19 if (outW == 0.0F) return {};
20 return {outX / outW, outY / outW, outZ / outW};
21 }
22 std::array<float, 3> difference(const std::array<float, 3>& a,
23 const std::array<float, 3>& b) noexcept
24 { return {a[0] - b[0], a[1] - b[1], a[2] - b[2]}; }
25 std::array<float, 3> normalized(const std::array<float, 3>& value) noexcept
26 {
27 const float length = std::sqrt(value[0] * value[0] +
28 value[1] * value[1] + value[2] * value[2]);
29 if (length == 0.0F) return {};
30 return {value[0] / length, value[1] / length, value[2] / length};
31 }
32 }
33
35 const sequence::SequenceCamera3DView& camera) noexcept
36 {
37 const auto location = sequencePoint(camera.worldTransform, 0.0F, 0.0F, 0.0F);
38 const auto forwardPoint = sequencePoint(camera.worldTransform, 0.0F, 0.0F, 1.0F);
39 const auto upPoint = sequencePoint(camera.worldTransform, 0.0F, 1.0F, 0.0F);
40 return World3DCamera{location,
42 normalized(difference(upPoint, location)), camera.fieldOfView,
43 camera.nearPlane, camera.farPlane};
44 }
45
46 std::optional<World3DCamera> resolveWorld3DCamera(
47 const sequence::SetCameraCommand& command,
48 const sequence::SequenceRuntime& runtime) noexcept
49 {
50 if (command.cameraNumber == 0)
51 return World3DCamera{command.position, command.forwards, command.up,
52 command.fieldOfView, command.nearPlane, command.farPlane};
53
54 const auto camera = runtime.cameraForLabel(command.cameraNumber);
55 if (!camera) return std::nullopt;
56 return world3DCameraFromSequence(*camera);
57 }
58
59 void SequenceWorld3DSlot::refreshBounds(SequenceWorld3DObject& object) noexcept
60 {
61 object.screenBounds.reset();
62 if (!view_ || !object.asset) return;
63 const auto renderData =
64 object.renderData ? object.renderData : object.asset->renderData;
65 if (!renderData) return;
66 data::MeshBounds bounds = renderData->bounds;
67 if (object.sequenceBounds)
68 {
69 bounds.minimum = object.sequenceBounds->minimum;
70 bounds.maximum = object.sequenceBounds->maximum;
71 }
72 object.screenBounds = world3DMeshScreenRect(
73 bounds, object.worldTransform, *view_);
74 }
75
76 void SequenceWorld3DSlot::refreshAllBounds() noexcept
77 {
78 for (auto& [node, object] : objects_)
79 {
80 (void)node;
81 refreshBounds(object);
82 }
83 }
84
85 std::expected<SequenceWorld3DSyncStats, SequenceWorld3DSlotError>
87 const std::vector<sequence::SequenceMeshRenderItem>& items)
88 {
89 std::set<sequence::SequenceNodeId> incoming;
90 for (const auto& item : items)
91 {
92 if (!incoming.insert(item.node).second)
93 return std::unexpected(SequenceWorld3DSlotError{
95 }
96
97 auto next = objects_;
99 for (auto it = next.begin(); it != next.end();)
100 {
101 if (!incoming.contains(it->first))
102 {
103 it = next.erase(it);
104 ++stats.stopped;
105 }
106 else ++it;
107 }
108
109 for (const auto& item : items)
110 {
111 const auto found = next.find(item.node);
112 if (found == next.end())
113 {
114 auto [inserted, created] = next.emplace(item.node,
115 SequenceWorld3DObject{item.node, item.contentsDataId,
116 item.priority, item.clock, item.worldTransform,
117 item.asset, item.bounds, std::nullopt, item.renderData});
118 (void)created;
119 refreshBounds(inserted->second);
120 ++stats.started;
121 continue;
122 }
123
124 const bool moved =
125 found->second.contentsDataId != item.contentsDataId ||
126 found->second.asset != item.asset ||
127 found->second.sequenceBounds != item.bounds ||
128 found->second.renderData != item.renderData ||
129 found->second.worldTransform.values != item.worldTransform.values;
130 found->second.contentsDataId = item.contentsDataId;
131 found->second.priority = item.priority;
132 found->second.clock = item.clock;
133 found->second.worldTransform = item.worldTransform;
134 found->second.asset = item.asset;
135 found->second.sequenceBounds = item.bounds;
136 found->second.renderData = item.renderData;
137 if (moved)
138 {
139 refreshBounds(found->second);
140 ++stats.moved;
141 }
142 else ++stats.unchanged;
143 }
144
145 objects_ = std::move(next);
146 order_.clear();
147 order_.reserve(items.size());
148 for (const auto& item : items) order_.push_back(item.node);
149 return stats;
150 }
151
152 std::expected<std::size_t, World3DProjectionError>
153 SequenceWorld3DSlot::configureView(World3DRect viewport, World3DCamera camera)
154 {
155 auto next = makeWorld3DProjectionState(viewport, camera);
156 if (!next) return std::unexpected(next.error());
157 view_ = std::move(*next);
158 refreshAllBounds();
159 return objects_.size();
160 }
161
162 void SequenceWorld3DSlot::clearView() noexcept
163 {
164 view_.reset();
165 for (auto& [node, object] : objects_)
166 {
167 (void)node;
168 object.screenBounds.reset();
169 }
170 }
171
172 void SequenceWorld3DSlot::clear() noexcept
173 {
174 objects_.clear();
175 order_.clear();
176 }
177
178 std::size_t SequenceWorld3DSlot::size() const noexcept
179 { return objects_.size(); }
180
181 const SequenceWorld3DObject* SequenceWorld3DSlot::find(
182 sequence::SequenceNodeId node) const noexcept
183 {
184 const auto found = objects_.find(node);
185 return found == objects_.end() ? nullptr : &found->second;
186 }
187
188 std::vector<sequence::SequenceNodeId> SequenceWorld3DSlot::order() const
189 { return order_; }
190
191 std::vector<sequence::SequenceNodeId> SequenceWorld3DSlot::visibleOrder() const
192 {
193 std::vector<sequence::SequenceNodeId> result;
194 result.reserve(order_.size());
195 for (const auto node : order_)
196 {
197 const auto found = objects_.find(node);
198 if (found != objects_.end() && found->second.screenBounds)
199 result.push_back(node);
200 }
201 return result;
202 }
203
204 const std::optional<World3DProjectionState>&
205 SequenceWorld3DSlot::view() const noexcept
206 { return view_; }
207
208 bool SequenceWorld3DSlot::boundsVisible(
209 const sequence::SequenceBounds3D& bounds,
210 const sequence::Matrix3D& worldTransform) const noexcept
211 {
212 if (!view_) return true;
213 const data::MeshBounds meshBounds{bounds.minimum, bounds.maximum};
215 meshBounds, worldTransform, *view_).has_value();
216 }
217}
fonts::Runtime & runtime
unsigned index
int z
std::uint16_t value
Definition Timers.cpp:16
std::expected< SequenceWorld3DSyncStats, SequenceWorld3DSlotError > sync(const std::vector< sequence::SequenceMeshRenderItem > &items)
std::optional< World3DRect > world3DMeshScreenRect(const data::MeshBounds &bounds, const sequence::Matrix3D &worldTransform, const World3DProjectionState &projection) noexcept
std::optional< World3DCamera > resolveWorld3DCamera(const sequence::SetCameraCommand &command, const sequence::SequenceRuntime &runtime) noexcept
std::expected< World3DProjectionState, World3DProjectionError > makeWorld3DProjectionState(World3DRect viewport, World3DCamera camera)
World3DCamera world3DCameraFromSequence(const sequence::SequenceCamera3DView &camera) noexcept
std::uint64_t SequenceNodeId
std::array< float, 3 > maximum
std::array< float, 3 > minimum