Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
SequenceTransforms.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5#include <type_traits>
6
7namespace monopoly::sequence
8{
9 namespace
10 {
11 Matrix2D scale2D(float x, float y) noexcept
12 { auto m = identity2D(); m.values[0] = x; m.values[4] = y; return m; }
13 Matrix3D scale3D(float x, float y, float z) noexcept
14 { auto m = identity3D(); m.values[0] = x; m.values[5] = y; m.values[10] = z; return m; }
15 Matrix2D rotate2D(float angle) noexcept
16 {
17 auto m = identity2D();
18 m.values[0] = m.values[4] = std::cos(angle);
19 m.values[1] = std::sin(angle);
20 m.values[3] = -m.values[1];
21 return m;
22 }
23 Matrix3D rotateX(float angle) noexcept
24 {
25 auto m = identity3D();
26 m.values[5] = m.values[10] = std::cos(angle);
27 m.values[6] = std::sin(angle); m.values[9] = -m.values[6];
28 return m;
29 }
30 Matrix3D rotateY(float angle) noexcept
31 {
32 auto m = identity3D();
33 m.values[0] = m.values[10] = std::cos(angle);
34 m.values[2] = -std::sin(angle); m.values[8] = -m.values[2];
35 return m;
36 }
37 Matrix3D rotateZ(float angle) noexcept
38 {
39 auto m = identity3D();
40 m.values[0] = m.values[5] = std::cos(angle);
41 m.values[1] = std::sin(angle); m.values[4] = -m.values[1];
42 return m;
43 }
44 Matrix2D osrt(const data::Sequence2DOriginScaleRotateOffsetAttribute& value) noexcept
45 {
46 auto result = translate2D(-value.originX, -value.originY);
47 if (value.scaleX != 1.0F || value.scaleY != 1.0F)
48 result = multiply(result, scale2D(value.scaleX, value.scaleY));
49 if (value.rotate != 0.0F) result = multiply(result, rotate2D(value.rotate));
50 if (value.offsetX != 0 || value.offsetY != 0)
51 result = multiply(result, translate2D(value.offsetX, value.offsetY));
52 return result;
53 }
54 Matrix3D osrt(const data::Sequence3DOriginScaleRotateOffsetAttribute& value) noexcept
55 {
56 auto result = translate3D(-value.originX, -value.originY, -value.originZ);
57 if (value.scaleX != 1.0F || value.scaleY != 1.0F || value.scaleZ != 1.0F)
58 result = multiply(result, scale3D(value.scaleX, value.scaleY, value.scaleZ));
59 if (value.roll != 0.0F) result = multiply(result, rotateZ(value.roll));
60 if (value.pitch != 0.0F) result = multiply(result, rotateX(value.pitch));
61 if (value.yaw != 0.0F) result = multiply(result, rotateY(value.yaw));
62 if (value.offsetX != 0.0F || value.offsetY != 0.0F || value.offsetZ != 0.0F)
63 result = multiply(result, translate3D(value.offsetX, value.offsetY, value.offsetZ));
64 return result;
65 }
66 bool is2D(const data::LegacySequenceAttribute& attribute) noexcept
67 {
68 return std::holds_alternative<data::Sequence2DOffsetAttribute>(attribute) ||
69 std::holds_alternative<data::Sequence2DMatrixAttribute>(attribute) ||
70 std::holds_alternative<data::Sequence2DOriginScaleRotateOffsetAttribute>(attribute);
71 }
72 bool is3D(const data::LegacySequenceAttribute& attribute) noexcept
73 {
74 return std::holds_alternative<data::Sequence3DOffsetAttribute>(attribute) ||
75 std::holds_alternative<data::Sequence3DMatrixAttribute>(attribute) ||
76 std::holds_alternative<data::Sequence3DOriginScaleRotateOffsetAttribute>(attribute);
77 }
79 {
80 return is2D(attribute) ||
81 std::holds_alternative<data::Sequence2DBoundingBoxAttribute>(attribute);
82 }
84 {
85 return is3D(attribute) ||
86 std::holds_alternative<data::Sequence3DBoundingBoxAttribute>(attribute) ||
87 std::holds_alternative<data::Sequence3DBoundingSphereAttribute>(attribute) ||
88 std::holds_alternative<data::Sequence3DMeshChoiceAttribute>(attribute);
89 }
90 float interpolate(float proportion, float first, float second) noexcept
91 { return (1.0F - proportion) * first + proportion * second; }
92 std::int32_t interpolate(float proportion, std::int32_t first,
93 std::int32_t second) noexcept
94 { return static_cast<std::int32_t>(interpolate(proportion,
95 static_cast<float>(first), static_cast<float>(second))); }
96 }
97
99 { Matrix2D value; value.values[0] = value.values[4] = value.values[8] = 1.0F; return value; }
101 { Matrix3D value; value.values[0] = value.values[5] = value.values[10] = value.values[15] = 1.0F; return value; }
102
103 Matrix2D multiply(const Matrix2D& left, const Matrix2D& right) noexcept
104 {
105 Matrix2D result;
106 for (std::size_t row = 0; row < 3; ++row)
107 for (std::size_t column = 0; column < 3; ++column)
108 for (std::size_t k = 0; k < 3; ++k)
109 result.values[row * 3 + column] +=
110 left.values[row * 3 + k] * right.values[k * 3 + column];
111 return result;
112 }
113 Matrix3D multiply(const Matrix3D& left, const Matrix3D& right) noexcept
114 {
115 Matrix3D result;
116 for (std::size_t row = 0; row < 4; ++row)
117 for (std::size_t column = 0; column < 4; ++column)
118 for (std::size_t k = 0; k < 4; ++k)
119 result.values[row * 4 + column] +=
120 left.values[row * 4 + k] * right.values[k * 4 + column];
121 return result;
122 }
123 Matrix2D translate2D(std::int32_t x, std::int32_t y) noexcept
124 { auto value = identity2D(); value.values[6] = static_cast<float>(x); value.values[7] = static_cast<float>(y); return value; }
125 Matrix3D translate3D(float x, float y, float z) noexcept
126 { auto value = identity3D(); value.values[12] = x; value.values[13] = y; value.values[14] = z; return value; }
127
128 SequenceTransform moveXYTransform(std::int32_t x, std::int32_t y) noexcept
129 {
130 if (x == 0 && y == 0) return std::monostate{};
131 return translate2D(x, y);
132 }
133
135 std::int32_t x, std::int32_t y,
136 float scale, float rotate) noexcept
137 {
138 auto result = rotate2D(rotate);
139 result = multiply(result, scale2D(scale, scale));
140 result = multiply(result, translate2D(x, y));
141 return result;
142 }
143
144 Matrix3D moveRySTxzTransform(float yaw, float scale,
145 float x, float z) noexcept
146 {
147 auto result = scale3D(scale, scale, scale);
148 if (yaw != 0.0F) result = multiply(result, rotateY(yaw));
149 if (x != 0.0F || z != 0.0F)
150 result = multiply(result, translate3D(x, 0.0F, z));
151 return result;
152 }
153
155 const data::LegacySequenceRecord& record,
156 const data::LegacySequenceAttributes& attributes,
157 std::uint8_t parentDimensionality) noexcept
158 {
159 std::uint8_t dimensionality{};
160 if (std::holds_alternative<data::SequenceTweekerData>(record.data) ||
161 std::holds_alternative<data::SequencePreloaderData>(record.data))
162 dimensionality = 0;
163 else if (std::holds_alternative<data::SequenceBitmapData>(record.data) ||
164 std::holds_alternative<data::SequenceVideoData>(record.data)) dimensionality = 2;
165 else if (std::holds_alternative<data::SequenceModelData>(record.data) ||
166 std::holds_alternative<data::SequenceMeshData>(record.data)) dimensionality = 3;
167 else
168 {
169 dimensionality = parentDimensionality;
170 const auto prefixSize = std::min(attributes.values.size(),
171 attributes.firstChildAttributeIndex.value_or(attributes.values.size()));
172 for (std::size_t index = 0; index < prefixSize; ++index)
173 {
174 const auto& attribute = attributes.values[index];
175 if (const auto* explicitValue =
176 std::get_if<data::SequenceDimensionalityAttribute>(&attribute))
177 { dimensionality = explicitValue->value; break; }
178 if (hints2D(attribute)) { dimensionality = 2; break; }
179 if (hints3D(attribute)) { dimensionality = 3; break; }
180 }
181 }
182
183 SequenceTransform local = dimensionality == 2 ? SequenceTransform(identity2D()) :
184 dimensionality == 3 ? SequenceTransform(identity3D()) : SequenceTransform(std::monostate{});
185 bool positioned{};
186 for (const auto& attribute : attributes.values)
187 {
188 if (dimensionality == 2)
189 {
190 if (const auto* value = std::get_if<data::Sequence2DOffsetAttribute>(&attribute))
191 { local = translate2D(value->x, value->y); positioned = true; break; }
192 if (const auto* value = std::get_if<data::Sequence2DMatrixAttribute>(&attribute))
193 { local = Matrix2D{value->values}; positioned = true; break; }
194 if (const auto* value = std::get_if<data::Sequence2DOriginScaleRotateOffsetAttribute>(&attribute))
195 { local = osrt(*value); positioned = true; break; }
196 }
197 else if (dimensionality == 3)
198 {
199 if (const auto* value = std::get_if<data::Sequence3DOffsetAttribute>(&attribute))
200 { local = translate3D(value->x, value->y, value->z); positioned = true; break; }
201 if (const auto* value = std::get_if<data::Sequence3DMatrixAttribute>(&attribute))
202 { local = Matrix3D{value->values}; positioned = true; break; }
203 if (const auto* value = std::get_if<data::Sequence3DOriginScaleRotateOffsetAttribute>(&attribute))
204 { local = osrt(*value); positioned = true; break; }
205 }
206 }
207 return {dimensionality, std::move(local), positioned};
208 }
209
211 std::uint8_t dimensionality, const SequenceTransform& parentWorld,
212 std::uint8_t parentDimensionality) noexcept
213 {
214 if (dimensionality == 2)
215 {
216 const auto& own = std::get<Matrix2D>(local);
217 if (parentDimensionality == 2)
218 return multiply(own, std::get<Matrix2D>(parentWorld));
219 return own;
220 }
221 if (dimensionality == 3)
222 {
223 const auto& own = std::get<Matrix3D>(local);
224 if (parentDimensionality == 3)
225 return multiply(own, std::get<Matrix3D>(parentWorld));
226 return own;
227 }
228 return std::monostate{};
229 }
230
232 const data::LegacySequenceAttributes& attributes) noexcept
233 {
235 for (const auto& attribute : attributes.values)
236 {
237 if (std::holds_alternative<data::SequenceDimensionalityAttribute>(attribute) ||
238 std::holds_alternative<data::SequenceFileNameAttribute>(attribute) ||
239 std::holds_alternative<data::SequenceUnsupportedAttribute>(attribute))
240 continue;
241 if (!keys.first) keys.first = &attribute;
242 else if (attribute.index() == keys.first->index())
243 {
244 keys.second = &attribute;
245 break;
246 }
247 }
248 return keys;
249 }
250
251 std::expected<EvaluatedTweekerTransform, TweekerTransformError>
253 std::uint8_t interpolationType, std::int32_t clock,
254 std::int32_t endTime, std::uint8_t parentDimensionality) noexcept
255 {
256 if (interpolationType > 2)
257 return std::unexpected(TweekerTransformError::InvalidInterpolation);
258 if (interpolationType == 0)
259 return EvaluatedTweekerTransform{true, true,
262 SequenceTransform(std::monostate{})};
263
264 const auto [first, second] = selectTweekerKeys(attributes);
265 if (!first || (!is2D(*first) && !is3D(*first)))
267 if ((is2D(*first) && parentDimensionality != 2) ||
268 (is3D(*first) && parentDimensionality != 3))
269 return std::unexpected(TweekerTransformError::DimensionalityMismatch);
270
271 const bool linear = interpolationType == 2 && second &&
272 endTime < 1'234'567'890;
273 const float proportion = linear ? static_cast<float>(clock) /
274 static_cast<float>(endTime) : 0.0F;
275 return std::visit([&](const auto& initial)
276 -> std::expected<EvaluatedTweekerTransform, TweekerTransformError>
277 {
278 using Attribute = std::remove_cvref_t<decltype(initial)>;
279 if constexpr (std::is_same_v<Attribute, data::Sequence2DOffsetAttribute>)
280 {
281 auto value = initial;
282 if (linear)
283 {
284 const auto& final = std::get<Attribute>(*second);
285 value.x = interpolate(proportion, value.x, final.x);
286 value.y = interpolate(proportion, value.y, final.y);
287 }
288 return EvaluatedTweekerTransform{true, false, translate2D(value.x, value.y)};
289 }
290 else if constexpr (std::is_same_v<Attribute, data::Sequence2DMatrixAttribute>)
291 {
293 if (linear)
294 {
295 const auto& final = std::get<Attribute>(*second);
296 for (std::size_t i = 0; i < value.values.size(); ++i)
297 value.values[i] = interpolate(proportion, value.values[i], final.values[i]);
298 }
299 return EvaluatedTweekerTransform{true, false, value};
300 }
301 else if constexpr (std::is_same_v<Attribute, data::Sequence2DOriginScaleRotateOffsetAttribute>)
302 {
303 auto value = initial;
304 if (linear)
305 {
306 const auto& final = std::get<Attribute>(*second);
307 value.offsetX = interpolate(proportion, value.offsetX, final.offsetX);
308 value.offsetY = interpolate(proportion, value.offsetY, final.offsetY);
309 value.originX = interpolate(proportion, value.originX, final.originX);
310 value.originY = interpolate(proportion, value.originY, final.originY);
311 value.scaleX = interpolate(proportion, value.scaleX, final.scaleX);
312 value.scaleY = interpolate(proportion, value.scaleY, final.scaleY);
313 value.rotate = interpolate(proportion, value.rotate, final.rotate);
314 }
315 return EvaluatedTweekerTransform{true, false, osrt(value)};
316 }
317 else if constexpr (std::is_same_v<Attribute, data::Sequence3DOffsetAttribute>)
318 {
319 auto value = initial;
320 if (linear)
321 {
322 const auto& final = std::get<Attribute>(*second);
323 value.x = interpolate(proportion, value.x, final.x);
324 value.y = interpolate(proportion, value.y, final.y);
325 value.z = interpolate(proportion, value.z, final.z);
326 }
327 return EvaluatedTweekerTransform{true, false, translate3D(value.x, value.y, value.z)};
328 }
329 else if constexpr (std::is_same_v<Attribute, data::Sequence3DMatrixAttribute>)
330 {
332 if (linear)
333 {
334 const auto& final = std::get<Attribute>(*second);
335 for (std::size_t i = 0; i < value.values.size(); ++i)
336 value.values[i] = interpolate(proportion, value.values[i], final.values[i]);
337 }
338 return EvaluatedTweekerTransform{true, false, value};
339 }
340 else if constexpr (std::is_same_v<Attribute, data::Sequence3DOriginScaleRotateOffsetAttribute>)
341 {
342 auto value = initial;
343 if (linear)
344 {
345 const auto& final = std::get<Attribute>(*second);
346 value.offsetX = interpolate(proportion, value.offsetX, final.offsetX);
347 value.offsetY = interpolate(proportion, value.offsetY, final.offsetY);
348 value.offsetZ = interpolate(proportion, value.offsetZ, final.offsetZ);
349 value.originX = interpolate(proportion, value.originX, final.originX);
350 value.originY = interpolate(proportion, value.originY, final.originY);
351 value.originZ = interpolate(proportion, value.originZ, final.originZ);
352 value.roll = interpolate(proportion, value.roll, final.roll);
353 value.pitch = interpolate(proportion, value.pitch, final.pitch);
354 value.yaw = interpolate(proportion, value.yaw, final.yaw);
355 value.scaleX = interpolate(proportion, value.scaleX, final.scaleX);
356 value.scaleY = interpolate(proportion, value.scaleY, final.scaleY);
357 value.scaleZ = interpolate(proportion, value.scaleZ, final.scaleZ);
358 }
359 return EvaluatedTweekerTransform{true, false, osrt(value)};
360 }
361 else return EvaluatedTweekerTransform{};
362 }, *first);
363 }
364}
std::atomic< float > left
std::atomic< float > right
unsigned index
data::DataTag first
float yaw
int z
std::uint16_t value
Definition Timers.cpp:16
std::variant< SequenceDimensionalityAttribute, Sequence2DOffsetAttribute, Sequence2DMatrixAttribute, Sequence2DOriginScaleRotateOffsetAttribute, Sequence3DOffsetAttribute, Sequence3DMatrixAttribute, Sequence3DOriginScaleRotateOffsetAttribute, Sequence2DBoundingBoxAttribute, Sequence3DBoundingBoxAttribute, Sequence3DBoundingSphereAttribute, Sequence3DMeshChoiceAttribute, SequenceLabelAttribute, SequenceSoundPitchAttribute, SequenceSoundVolumeAttribute, SequenceSoundPanningAttribute, SequenceCameraFieldOfViewAttribute, SequenceFileNameAttribute, SequenceUnsupportedAttribute > LegacySequenceAttribute
std::expected< EvaluatedTweekerTransform, TweekerTransformError > evaluateTweekerTransform(const data::LegacySequenceAttributes &attributes, std::uint8_t interpolationType, std::int32_t clock, std::int32_t endTime, std::uint8_t parentDimensionality) noexcept
Matrix3D moveRySTxzTransform(float yaw, float scale, float x, float z) noexcept
Matrix2D identity2D() noexcept
Matrix2D translate2D(std::int32_t x, std::int32_t y) noexcept
std::variant< std::monostate, Matrix2D, Matrix3D > SequenceTransform
Matrix3D translate3D(float x, float y, float z) noexcept
TweekerKeys selectTweekerKeys(const data::LegacySequenceAttributes &attributes) noexcept
Matrix2D moveXYSRTransform(std::int32_t x, std::int32_t y, float scale, float rotate) noexcept
SequenceTransform composeSequenceWorld(const SequenceTransform &local, std::uint8_t dimensionality, const SequenceTransform &parentWorld, std::uint8_t parentDimensionality) noexcept
Matrix3D identity3D() noexcept
SequenceTransform moveXYTransform(std::int32_t x, std::int32_t y) noexcept
InitialSequenceTransform initialSequenceTransform(const data::LegacySequenceRecord &record, const data::LegacySequenceAttributes &attributes, std::uint8_t parentDimensionality) noexcept
Matrix2D multiply(const Matrix2D &left, const Matrix2D &right) noexcept
std::array< float, 16 > values
const data::LegacySequenceAttribute * first