24#include <welder/vocabulary.hpp>
43 An animation track family for one value type, abstract over the
44 client version; the per-version classes are subclasses.)")
56 =welder::weld_as(
"M2EventTrack"),
59 A timestamp-only event track (every key fires). Abstract over the client version; construct a concrete
60 version with M2EventTrack.ForVersion / for_version.)")
68 =welder::doc(
"An inclusive u32 range: pre-WotLK track interpolation "
69 "ranges, sequence replay bounds.")
71 [[=welder::doc(
"The inclusive lower bound.")]]
74 [[=welder::doc(
"The inclusive upper bound.")]]
75 std::uint32_t maximum = 0;
84 =welder::doc(
"A bounding volume: axis-aligned extent plus sphere radius.")
86 [[=welder::doc(
"The axis-aligned extent.")]]
89 [[=welder::doc(
"The bounding-sphere radius.")]]
95 static_assert(
sizeof(
M2Bounds) == 28);
100 "A global-loop entry: the timestamp a global sequence wraps at.")
102 [[=welder::doc(
"The timestamp the global sequence wraps at.")]]
103 std::uint32_t timestamp = 0;
108 static_assert(
sizeof(
M2Loop) == 4);
112 =welder::doc(
"A quaternion compressed to i16 x, y, z, w (TBC+ bone "
113 "rotations); decompress as (v < 0 ? v + 32768 : v - 32767) / 32767.")
115 [[=welder::doc(
"The compressed x component.")]]
116 std::int16_t x = 32767;
118 [[=welder::doc(
"The compressed y component.")]]
119 std::int16_t y = 32767;
121 [[=welder::doc(
"The compressed z component.")]]
122 std::int16_t z = 32767;
124 [[=welder::doc(
"The compressed w component (identity stores 65535).")]]
134 =welder::doc(
"A model-space box: minimum and maximum corner vectors.")
136 [[=welder::doc(
"The minimum corner.")]]
139 [[=welder::doc(
"The maximum corner.")]]
142 bool operator==(
const M2Box&)
const =
default;
145 static_assert(
sizeof(
M2Box) == 24);
147 template <
typename T>
151 "A spline keyframe: the value plus incoming/outgoing tangents "
152 "(bezier/hermite camera tracks).")
154 [[=welder::doc(
"The keyframe value.")]]
157 [[=welder::doc(
"The incoming tangent.")]]
160 [[=welder::doc(
"The outgoing tangent.")]]
177 template <
typename T, ClientVersion V>
184 "An animation track, pre-WotLK layout: one global timeline with "
185 "per-sequence interpolation ranges.")
187 [[=welder::doc(
"Interpolation: 0 none, 1 linear, 2 bezier, 3 hermite "
188 "(spline types only valid for spline-key tracks).")]]
191 [[=welder::doc(
"The global sequence driving this track; -1: none.")]]
194 [[=welder::doc(
"Per-sequence [first, last] key-index ranges into the "
195 "global timeline.")]]
198 [[=welder::doc(
"The global timeline's keyframe timestamps.")]]
203 =welder::doc(
"The keyframe values, one per timestamp.")]]
213 [[=welder::doc(
"The number of timelines this track carries: one per "
214 "interpolation range, or a single timeline 0 for a "
215 "global-sequence-driven or rangeless track (0 when the "
216 "track is empty).")]]
225 [[=welder::doc(
"The number of keys on one timeline."),
227 "the key count; errors when timeline is out of range")]
230 [[=welder::doc(
"the timeline index")]])
const {
231 return _timelineSlice(timeline).transform([](
auto s) {
237 [[=welder::doc(
"One timeline's keyframe timestamps, as a copy."),
238 =welder::returns(
"the timestamps; errors when timeline is out of range")
241 std::size_t timeline [[=welder::doc(
"the timeline index")]])
const {
242 return _timelineSlice(timeline).transform([
this](
auto s) {
243 const auto window = std::span(
timestamps).subspan(s.first, s.second);
244 return std::vector<std::uint32_t>(window.begin(), window.end());
249 [[=welder::doc(
"One timeline's keyframe values, as a copy."),
250 =welder::returns(
"the values; errors when timeline is out of range")]]
252 std::size_t timeline [[=welder::doc(
"the timeline index")]])
const {
253 return _timelineSlice(timeline).transform([
this](
auto s) {
254 const std::size_t maxFirst = std::min(s.first,
values.size());
255 const std::size_t count = std::min(s.second,
256 values.size() - maxFirst);
257 const auto window = std::span(
values).subspan(maxFirst, count);
258 return std::vector<T>(window.begin(), window.end());
269 std::size_t timeline)
const {
273 "timeline {} out of range ({} timelines)",
276 return std::pair<std::size_t, std::size_t>{0,
timestamps.size()};
278 const std::size_t first = std::min<std::size_t>(
280 const std::size_t end =
281 std::min<std::size_t>(std::size_t{r.
maximum} + 1, timestamps.size());
282 return std::pair<std::size_t, std::size_t>{
284 end < first ? 0 : end - first
289 bool operator==(
const M2Track&)
const =
default;
292 template <
typename T, ClientVersion V>
297 "An animation track, WotLK+ layout: one timestamp/value array per "
298 "sequence; an external sequence keeps its arrays in the .anim file.")
300 [[=welder::doc(
"Interpolation: 0 none, 1 linear, 2 bezier, 3 hermite "
301 "(spline types only valid for spline-key tracks).")]]
304 [[=welder::doc(
"The global sequence driving this track; -1: none.")]]
309 =welder::doc(
"Keyframe timestamps, one array per sequence (an external "
310 "sequence keeps its arrays in the .anim file).")]]
311 std::vector<std::vector<std::uint32_t>>
timestamps;
316 =welder::doc(
"Keyframe values, per sequence, parallel to timestamps.")]]
317 std::vector<std::vector<T>>
values;
323 [[=welder::doc(
"The number of timelines this track carries: one per "
324 "sequence (a global-sequence-driven track stores a "
325 "single timeline; an external sequence's timeline is "
326 "empty until its .anim data is loaded).")]]
330 [[=welder::doc(
"The number of keys on one timeline."),
332 "the key count; errors when timeline is out of range")]
335 [[=welder::doc(
"the timeline index")]])
const {
339 "timeline {} out of range ({} timelines)",
345 [[=welder::doc(
"One timeline's keyframe timestamps, as a copy."),
346 =welder::returns(
"the timestamps; errors when timeline is out of range")
349 std::size_t timeline [[=welder::doc(
"the timeline index")]])
const {
353 "timeline {} out of range ({} timelines)",
359 [[=welder::doc(
"One timeline's keyframe values, as a copy."),
360 =welder::returns(
"the values; errors when timeline is out of range")]]
362 std::size_t timeline [[=welder::doc(
"the timeline index")]])
const {
363 if (timeline >= values.size())
366 "timeline {} out of range ({} timelines)",
367 timeline, values.size()));
368 return values[timeline];
371 bool operator==(
const M2Track&)
const =
default;
376 template <ClientVersion V>
379 template <ClientVersion V>
384 "A timestamp-only event track, pre-WotLK layout (every key fires).")
386 [[=welder::doc(
"Interpolation: 0 none, 1 linear (keys fire, no value to "
390 [[=welder::doc(
"The global sequence driving this track; -1: none.")]]
393 [[=welder::doc(
"Per-sequence [first, last] key-index ranges into the "
394 "global timeline.")]]
397 [[=welder::doc(
"The global timeline's trigger timestamps.")]]
403 [[=welder::doc(
"The number of timelines this track carries: one per "
404 "interpolation range, or a single timeline 0 for a "
405 "global-sequence-driven or rangeless track (0 when the "
406 "track is empty).")]]
409 return timestamps.empty() ? std::size_t{0} : std::size_t{1};
410 return interpolationRanges.size();
414 [[=welder::doc(
"The number of trigger keys on one timeline."),
416 "the key count; errors when timeline is out of range")]
419 [[=welder::doc(
"the timeline index")]])
const {
420 return _timelineSlice(timeline).transform([](
auto s) {
426 [[=welder::doc(
"One timeline's trigger timestamps, as a copy."),
427 =welder::returns(
"the timestamps; errors when timeline is out of range")
430 std::size_t timeline [[=welder::doc(
"the timeline index")]])
const {
431 return _timelineSlice(timeline).transform([
this](
auto s) {
432 const auto window = std::span(timestamps).subspan(s.first, s.second);
433 return std::vector<std::uint32_t>(window.begin(), window.end());
443 std::size_t timeline)
const {
444 if (timeline >= timelineCount())
447 "timeline {} out of range ({} timelines)",
448 timeline, timelineCount()));
449 if (globalSequence != 0xFFFF || interpolationRanges.empty())
450 return std::pair<std::size_t, std::size_t>{0,
timestamps.size()};
451 const M2Range& r = interpolationRanges[timeline];
452 const std::size_t first = std::min<std::size_t>(
454 const std::size_t end =
455 std::min<std::size_t>(std::size_t{r.
maximum} + 1, timestamps.size());
456 return std::pair<std::size_t, std::size_t>{
458 end < first ? 0 : end - first
463 bool operator==(
const M2TrackBase&)
const =
default;
466 template <ClientVersion V>
471 "A timestamp-only event track, WotLK+ layout (every key fires).")
473 [[=welder::doc(
"Interpolation: 0 none, 1 linear (keys fire, no value to "
475 std::uint16_t interpolationType = 0;
477 [[=welder::doc(
"The global sequence driving this track; -1: none.")]]
478 std::uint16_t globalSequence = 0xFFFF;
482 =welder::doc(
"Trigger timestamps, one array per sequence (an external "
483 "sequence keeps its arrays in the .anim file).")]]
484 std::vector<std::vector<std::uint32_t>> timestamps;
489 [[=welder::doc(
"The number of timelines this track carries: one per "
490 "sequence (an external sequence's timeline is empty "
491 "until its .anim data is loaded).")]]
492 std::size_t timelineCount()
const {
return timestamps.size(); }
495 [[=welder::doc(
"The number of trigger keys on one timeline."),
497 "the key count; errors when timeline is out of range")]
500 [[=welder::doc(
"the timeline index")]])
const {
501 if (timeline >= timestamps.size())
504 "timeline {} out of range ({} timelines)",
505 timeline, timestamps.size()));
506 return timestamps[timeline].size();
510 [[=welder::doc(
"One timeline's trigger timestamps, as a copy."),
511 =welder::returns(
"the timestamps; errors when timeline is out of range")
514 std::size_t timeline [[=welder::doc(
"the timeline index")]])
const {
518 "timeline {} out of range ({} timelines)",
531 template <
typename T, ClientVersion V>
537 template <ClientVersion V>
542 template <
typename T>
546 "The header-less 'fake' animation block: sequence-independent u16 "
547 "timestamps plus keys (WotLK+ particle ramps).")
549 [[=welder::doc(
"Sequence-independent keyframe timestamps.")]]
550 std::vector<std::uint16_t> timestamps;
554 =welder::doc(
"The keys, one per timestamp.")]]
560 template <
typename T>
564 "A partial track: normalized fixed16 times plus values (Legion+ EXP2 "
567 [[=welder::doc(
"Normalized fixed16 key times.")]]
568 std::vector<fixed16> times;
572 =welder::doc(
"The values, one per time.")]]
573 std::vector<T> values;
575 bool operator==(
const M2PartTrack&)
const =
default;
Client version identity, the flavor axis that separates a client's CONTENT version from the engine ge...
The error-handling vocabulary: ErrorCode, Error and the Result<T> alias every fallible wowlib operati...
Binding-language identities welder's core does not name.
#define WOWLIB_CS_FAMILY_SURFACE
The C# rod's family-surface opt-in, spellable in every build.
The M2 version vocabulary: the layout pivots record/entity partial specializations key on,...
std::expected< T, Error > Result
Every fallible wowlib operation returns Result<T>; bindings translate the error branch into a target-...
std::unexpected< Error > makeError(ErrorCode code, std::string message, std::uint32_t nativeError=0)
Shorthand for constructing the error branch of a Result.
@ InvalidEntityState
An entity's members disagree (e.g.
The binary-level math and color primitives shared across WoW file formats (wowdev....