24 const std::string &ease) {
28 if (!(delay >= 0.f) || !std::isfinite(delay))
31 if (loops == 0 || loops < -1)
36 }
catch (
const Exception &) {
48 if (!(dampingRatio >= 0.f) || !std::isfinite(dampingRatio))
55void MotionRuntime::recycleFloat(FloatSlot &slot) {
60 const auto index =
static_cast<std::uint32_t
>(&slot - floats_.data());
61 freeFloats_.push_back(
index);
64void MotionRuntime::recycleVec2(Vec2Slot &slot) {
69 const auto index =
static_cast<std::uint32_t
>(&slot - vec2s_.data());
70 freeVec2s_.push_back(
index);
73void MotionRuntime::recycleVec3(Vec3Slot &slot) {
78 const auto index =
static_cast<std::uint32_t
>(&slot - vec3s_.data());
79 freeVec3s_.push_back(
index);
82void MotionRuntime::recycleColor(ColorSlot &slot) {
87 const auto index =
static_cast<std::uint32_t
>(&slot - colors_.data());
88 freeColors_.push_back(
index);
91void MotionRuntime::recycleQuat(QuatSlot &slot) {
96 const auto index =
static_cast<std::uint32_t
>(&slot - quats_.data());
97 freeQuats_.push_back(
index);
101 floats_.reserve(
count);
102 freeFloats_.reserve(
count);
103 while (floats_.size() <
count) {
105 slot.phase = Phase::Inactive;
107 floats_.push_back(std::move(slot));
108 freeFloats_.push_back(
static_cast<std::uint32_t
>(floats_.size() - 1));
113 vec2s_.reserve(
count);
114 freeVec2s_.reserve(
count);
115 while (vec2s_.size() <
count) {
117 slot.phase = Phase::Inactive;
119 vec2s_.push_back(std::move(slot));
120 freeVec2s_.push_back(
static_cast<std::uint32_t
>(vec2s_.size() - 1));
125 vec3s_.reserve(
count);
126 freeVec3s_.reserve(
count);
127 while (vec3s_.size() <
count) {
129 slot.phase = Phase::Inactive;
131 vec3s_.push_back(std::move(slot));
132 freeVec3s_.push_back(
static_cast<std::uint32_t
>(vec3s_.size() - 1));
137 colors_.reserve(
count);
138 freeColors_.reserve(
count);
139 while (colors_.size() <
count) {
141 slot.phase = Phase::Inactive;
143 colors_.push_back(std::move(slot));
144 freeColors_.push_back(
static_cast<std::uint32_t
>(colors_.size() - 1));
149 quats_.reserve(
count);
150 freeQuats_.reserve(
count);
151 while (quats_.size() <
count) {
153 slot.phase = Phase::Inactive;
155 quats_.push_back(std::move(slot));
156 freeQuats_.push_back(
static_cast<std::uint32_t
>(quats_.size() - 1));
162eve::Result<void> MotionRuntime::applyFloat(FloatSlot &slot,
float linearT,
bool fireUpdate) {
165 const float a = slot.reverse ? slot.to : slot.from;
166 const float b = slot.reverse ? slot.from : slot.to;
167 slot.current = lerpFloat(
a,
b, eased);
169 const float strength = slot.reverse ? -slot.to : slot.to;
173 slot.current = slot.from +
strength * wave;
176 auto written = slot.sink->write(slot.current);
178 if (slot.cancelOnError) {
179 slot.phase = Phase::Cancelled;
180 if (slot.onCancel) slot.onCancel();
181 bumpGeneration(slot.generation);
187 if (fireUpdate && slot.onUpdate) slot.onUpdate(slot.current);
192eve::Result<void> MotionRuntime::applyVec2(Vec2Slot &slot,
float linearT,
bool fireUpdate) {
195 const MotionVec2
a = slot.reverse ? slot.to : slot.from;
196 const MotionVec2
b = slot.reverse ? slot.from : slot.to;
197 slot.current = lerpVec2(
a,
b, eased);
199 const float sx = slot.reverse ? -slot.to.x : slot.to.x;
200 const float sy = slot.reverse ? -slot.to.y : slot.to.y;
208 slot.current = MotionVec2{slot.from.x +
sx *
wx, slot.from.y +
sy *
wy};
211 auto written = slot.sink->write(slot.current);
213 if (slot.cancelOnError) {
214 slot.phase = Phase::Cancelled;
215 if (slot.onCancel) slot.onCancel();
216 bumpGeneration(slot.generation);
222 if (fireUpdate && slot.onUpdate) slot.onUpdate(slot.current);
227eve::Result<void> MotionRuntime::applyVec3(Vec3Slot &slot,
float linearT,
bool fireUpdate) {
230 const MotionVec3
a = slot.reverse ? slot.to : slot.from;
231 const MotionVec3
b = slot.reverse ? slot.from : slot.to;
232 slot.current = lerpVec3(
a,
b, eased);
234 const float sx = slot.reverse ? -slot.to.x : slot.to.x;
235 const float sy = slot.reverse ? -slot.to.y : slot.to.y;
236 const float sz = slot.reverse ? -slot.to.z : slot.to.z;
238 float wx = wave,
wy = wave,
wz = wave;
244 slot.current = MotionVec3{slot.from.x +
sx *
wx, slot.from.y +
sy *
wy, slot.from.z +
sz *
wz};
247 auto written = slot.sink->write(slot.current);
249 if (slot.cancelOnError) {
250 slot.phase = Phase::Cancelled;
251 if (slot.onCancel) slot.onCancel();
252 bumpGeneration(slot.generation);
258 if (fireUpdate && slot.onUpdate) slot.onUpdate(slot.current);
264 auto applied = applyFloat(slot, 1.f,
true);
266 if (slot.phase != Phase::Running)
return applied;
269 if (slot.loops >= 0 && slot.played >= slot.loops) {
270 slot.phase = Phase::Completed;
271 if (slot.onComplete) slot.onComplete();
272 bumpGeneration(slot.generation);
278 return applyFloat(slot, 0.f,
true);
282 auto applied = applyVec2(slot, 1.f,
true);
284 if (slot.phase != Phase::Running)
return applied;
287 if (slot.loops >= 0 && slot.played >= slot.loops) {
288 slot.phase = Phase::Completed;
289 if (slot.onComplete) slot.onComplete();
290 bumpGeneration(slot.generation);
296 return applyVec2(slot, 0.f,
true);
300 auto applied = applyVec3(slot, 1.f,
true);
302 if (slot.phase != Phase::Running)
return applied;
305 if (slot.loops >= 0 && slot.played >= slot.loops) {
306 slot.phase = Phase::Completed;
307 if (slot.onComplete) slot.onComplete();
308 bumpGeneration(slot.generation);
314 return applyVec3(slot, 0.f,
true);
318 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return okNoOp();
320 if (slot.phase == Phase::Delayed) {
321 slot.delayLeft -= dt;
322 if (slot.delayLeft > 0.f)
return okApplied();
323 dt = -slot.delayLeft;
324 slot.delayLeft = 0.f;
325 slot.phase = Phase::Running;
326 auto started = applyFloat(slot, 0.f,
true);
331 if (slot.duration <= 0.f)
return finishFloat(slot);
334 while (slot.phase == Phase::Running && slot.elapsed >= slot.duration) {
335 const float over = slot.elapsed - slot.duration;
336 auto finished = finishFloat(slot);
337 if (!finished)
return finished;
338 if (slot.phase != Phase::Running)
break;
341 if (slot.phase == Phase::Running)
return applyFloat(slot, slot.elapsed / slot.duration,
true);
346 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return okNoOp();
348 if (slot.phase == Phase::Delayed) {
349 slot.delayLeft -= dt;
350 if (slot.delayLeft > 0.f)
return okApplied();
351 dt = -slot.delayLeft;
352 slot.delayLeft = 0.f;
353 slot.phase = Phase::Running;
354 auto started = applyVec2(slot, 0.f,
true);
359 if (slot.duration <= 0.f)
return finishVec2(slot);
362 while (slot.phase == Phase::Running && slot.elapsed >= slot.duration) {
363 const float over = slot.elapsed - slot.duration;
364 auto finished = finishVec2(slot);
365 if (!finished)
return finished;
366 if (slot.phase != Phase::Running)
break;
369 if (slot.phase == Phase::Running)
return applyVec2(slot, slot.elapsed / slot.duration,
true);
374 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return okNoOp();
376 if (slot.phase == Phase::Delayed) {
377 slot.delayLeft -= dt;
378 if (slot.delayLeft > 0.f)
return okApplied();
379 dt = -slot.delayLeft;
380 slot.delayLeft = 0.f;
381 slot.phase = Phase::Running;
382 auto started = applyVec3(slot, 0.f,
true);
387 if (slot.duration <= 0.f)
return finishVec3(slot);
390 while (slot.phase == Phase::Running && slot.elapsed >= slot.duration) {
391 const float over = slot.elapsed - slot.duration;
392 auto finished = finishVec3(slot);
393 if (!finished)
return finished;
394 if (slot.phase != Phase::Running)
break;
397 if (slot.phase == Phase::Running)
return applyVec3(slot, slot.elapsed / slot.duration,
true);
401const MotionRuntime::FloatSlot *MotionRuntime::resolveFloat(MotionHandle
handle)
const {
402 if (
handle.isNull() ||
handle.index >= floats_.size())
return nullptr;
403 const auto &slot = floats_[
handle.index];
404 if (slot.generation !=
handle.generation)
return nullptr;
405 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return nullptr;
409const MotionRuntime::Vec2Slot *MotionRuntime::resolveVec2(MotionHandle
handle)
const {
410 if (
handle.isNull() ||
handle.index >= vec2s_.size())
return nullptr;
411 const auto &slot = vec2s_[
handle.index];
412 if (slot.generation !=
handle.generation)
return nullptr;
413 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return nullptr;
417const MotionRuntime::Vec3Slot *MotionRuntime::resolveVec3(MotionHandle
handle)
const {
418 if (
handle.isNull() ||
handle.index >= vec3s_.size())
return nullptr;
419 const auto &slot = vec3s_[
handle.index];
420 if (slot.generation !=
handle.generation)
return nullptr;
421 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return nullptr;
426 slot.phase = slot.delayLeft > 0.f ? Phase::Delayed : Phase::Running;
429 slot.reverse =
false;
430 slot.current = slot.from;
432 std::uint32_t
index = 0;
433 if (!freeFloats_.empty()) {
434 index = freeFloats_.back();
435 freeFloats_.pop_back();
436 const std::uint32_t gen = floats_[
index].generation == 0 ? 1u : floats_[
index].generation;
437 floats_[
index] = std::move(slot);
438 floats_[
index].generation = gen;
440 index =
static_cast<std::uint32_t
>(floats_.size());
441 floats_.push_back(std::move(slot));
457 slot.phase = slot.delayLeft > 0.f ? Phase::Delayed : Phase::Running;
460 slot.reverse =
false;
461 slot.current = slot.from;
463 std::uint32_t
index = 0;
464 if (!freeVec2s_.empty()) {
465 index = freeVec2s_.back();
466 freeVec2s_.pop_back();
467 const std::uint32_t gen = vec2s_[
index].generation == 0 ? 1u : vec2s_[
index].generation;
468 vec2s_[
index] = std::move(slot);
469 vec2s_[
index].generation = gen;
471 index =
static_cast<std::uint32_t
>(vec2s_.size());
472 vec2s_.push_back(std::move(slot));
488 slot.phase = slot.delayLeft > 0.f ? Phase::Delayed : Phase::Running;
491 slot.reverse =
false;
492 slot.current = slot.from;
494 std::uint32_t
index = 0;
495 if (!freeVec3s_.empty()) {
496 index = freeVec3s_.back();
497 freeVec3s_.pop_back();
498 const std::uint32_t gen = vec3s_[
index].generation == 0 ? 1u : vec3s_[
index].generation;
499 vec3s_[
index] = std::move(slot);
500 vec3s_[
index].generation = gen;
502 index =
static_cast<std::uint32_t
>(vec3s_.size());
503 vec3s_.push_back(std::move(slot));
521 auto styleOk = validateStyle(
desc.style,
desc.frequency,
desc.dampingRatio);
525 slot.from =
desc.from;
527 slot.duration =
desc.duration;
528 slot.delayLeft =
desc.delay;
529 slot.loops =
desc.loops;
530 slot.loopMode =
desc.loopMode;
531 slot.ease =
desc.ease.empty() ?
"linear" :
desc.ease;
532 slot.sink =
desc.sink;
533 slot.onUpdate =
desc.onUpdate;
534 slot.onComplete =
desc.onComplete;
535 slot.onCancel =
desc.onCancel;
536 slot.cancelOnError =
desc.cancelOnError;
537 slot.style =
desc.style;
538 slot.frequency =
desc.frequency;
539 slot.dampingRatio =
desc.dampingRatio;
540 slot.seed =
desc.seed;
541 return occupyFloat(std::move(slot));
547 auto styleOk = validateStyle(
desc.style,
desc.frequency,
desc.dampingRatio);
551 slot.from =
desc.from;
553 slot.duration =
desc.duration;
554 slot.delayLeft =
desc.delay;
555 slot.loops =
desc.loops;
556 slot.loopMode =
desc.loopMode;
557 slot.ease =
desc.ease.empty() ?
"linear" :
desc.ease;
558 slot.sink =
desc.sink;
559 slot.onUpdate =
desc.onUpdate;
560 slot.onComplete =
desc.onComplete;
561 slot.onCancel =
desc.onCancel;
562 slot.cancelOnError =
desc.cancelOnError;
563 slot.style =
desc.style;
564 slot.frequency =
desc.frequency;
565 slot.dampingRatio =
desc.dampingRatio;
566 slot.seed =
desc.seed;
567 return occupyVec2(std::move(slot));
573 auto styleOk = validateStyle(
desc.style,
desc.frequency,
desc.dampingRatio);
577 slot.from =
desc.from;
579 slot.duration =
desc.duration;
580 slot.delayLeft =
desc.delay;
581 slot.loops =
desc.loops;
582 slot.loopMode =
desc.loopMode;
583 slot.ease =
desc.ease.empty() ?
"linear" :
desc.ease;
584 slot.sink =
desc.sink;
585 slot.onUpdate =
desc.onUpdate;
586 slot.onComplete =
desc.onComplete;
587 slot.onCancel =
desc.onCancel;
588 slot.cancelOnError =
desc.cancelOnError;
589 slot.style =
desc.style;
590 slot.frequency =
desc.frequency;
591 slot.dampingRatio =
desc.dampingRatio;
592 slot.seed =
desc.seed;
593 return occupyVec3(std::move(slot));
602 const auto *slot = resolveFloat(
handle);
608 const auto *slot = resolveVec2(
handle);
614 const auto *slot = resolveVec3(
handle);
620 if (
auto *slot =
const_cast<FloatSlot *
>(resolveFloat(
handle))) {
621 slot->loops = slot->played + 1;
622 slot->phase = Phase::Running;
623 slot->elapsed = slot->duration;
624 return finishFloat(*slot);
626 if (
auto *slot =
const_cast<Vec2Slot *
>(resolveVec2(
handle))) {
627 slot->loops = slot->played + 1;
628 slot->phase = Phase::Running;
629 slot->elapsed = slot->duration;
630 return finishVec2(*slot);
632 if (
auto *slot =
const_cast<Vec3Slot *
>(resolveVec3(
handle))) {
633 slot->loops = slot->played + 1;
634 slot->phase = Phase::Running;
635 slot->elapsed = slot->duration;
636 return finishVec3(*slot);
638 if (
auto *slot =
const_cast<ColorSlot *
>(resolveColor(
handle))) {
639 slot->loops = slot->played + 1;
640 slot->phase = Phase::Running;
641 slot->elapsed = slot->duration;
642 return finishColor(*slot);
644 if (
auto *slot =
const_cast<QuatSlot *
>(resolveQuat(
handle))) {
645 slot->loops = slot->played + 1;
646 slot->phase = Phase::Running;
647 slot->elapsed = slot->duration;
648 return finishQuat(*slot);
654 if (
auto *slot =
const_cast<FloatSlot *
>(resolveFloat(
handle))) {
655 slot->phase = Phase::Cancelled;
656 if (slot->onCancel) slot->onCancel();
657 bumpGeneration(slot->generation);
661 if (
auto *slot =
const_cast<Vec2Slot *
>(resolveVec2(
handle))) {
662 slot->phase = Phase::Cancelled;
663 if (slot->onCancel) slot->onCancel();
664 bumpGeneration(slot->generation);
668 if (
auto *slot =
const_cast<Vec3Slot *
>(resolveVec3(
handle))) {
669 slot->phase = Phase::Cancelled;
670 if (slot->onCancel) slot->onCancel();
671 bumpGeneration(slot->generation);
675 if (
auto *slot =
const_cast<ColorSlot *
>(resolveColor(
handle))) {
676 slot->phase = Phase::Cancelled;
677 if (slot->onCancel) slot->onCancel();
678 bumpGeneration(slot->generation);
682 if (
auto *slot =
const_cast<QuatSlot *
>(resolveQuat(
handle))) {
683 slot->phase = Phase::Cancelled;
684 if (slot->onCancel) slot->onCancel();
685 bumpGeneration(slot->generation);
694 for (
const auto &
s : floats_)
695 if (
s.phase == Phase::Delayed ||
s.phase == Phase::Running) ++
n;
696 for (
const auto &
s : vec2s_)
697 if (
s.phase == Phase::Delayed ||
s.phase == Phase::Running) ++
n;
698 for (
const auto &
s : vec3s_)
699 if (
s.phase == Phase::Delayed ||
s.phase == Phase::Running) ++
n;
700 for (
const auto &
s : colors_)
701 if (
s.phase == Phase::Delayed ||
s.phase == Phase::Running) ++
n;
702 for (
const auto &
s : quats_)
703 if (
s.phase == Phase::Delayed ||
s.phase == Phase::Running) ++
n;
710 const float dt = std::move(seconds).takeValue();
712 for (
auto &slot : floats_) {
713 auto r = stepFloat(slot, dt);
716 for (
auto &slot : vec2s_) {
717 auto r = stepVec2(slot, dt);
720 for (
auto &slot : vec3s_) {
721 auto r = stepVec3(slot, dt);
724 for (
auto &slot : colors_) {
725 auto r = stepColor(slot, dt);
728 for (
auto &slot : quats_) {
729 auto r = stepQuat(slot, dt);
733 lastTick_ =
step.tick;
739eve::Result<void> MotionRuntime::applyColor(ColorSlot &slot,
float linearT,
bool fireUpdate) {
741 const MotionColor a = slot.reverse ? slot.to : slot.from;
742 const MotionColor b = slot.reverse ? slot.from : slot.to;
745 auto written = slot.sink->write(slot.current);
747 if (slot.cancelOnError) {
748 slot.phase = Phase::Cancelled;
749 if (slot.onCancel) slot.onCancel();
750 bumpGeneration(slot.generation);
756 if (fireUpdate && slot.onUpdate) slot.onUpdate(slot.current);
760eve::Result<void> MotionRuntime::applyQuat(QuatSlot &slot,
float linearT,
bool fireUpdate) {
762 const MotionQuat
a = slot.reverse ? slot.to : slot.from;
763 const MotionQuat
b = slot.reverse ? slot.from : slot.to;
766 auto written = slot.sink->write(slot.current);
768 if (slot.cancelOnError) {
769 slot.phase = Phase::Cancelled;
770 if (slot.onCancel) slot.onCancel();
771 bumpGeneration(slot.generation);
777 if (fireUpdate && slot.onUpdate) slot.onUpdate(slot.current);
782 auto applied = applyColor(slot, 1.f,
true);
784 if (slot.phase != Phase::Running)
return applied;
787 if (slot.loops >= 0 && slot.played >= slot.loops) {
788 slot.phase = Phase::Completed;
789 if (slot.onComplete) slot.onComplete();
790 bumpGeneration(slot.generation);
796 return applyColor(slot, 0.f,
true);
800 auto applied = applyQuat(slot, 1.f,
true);
802 if (slot.phase != Phase::Running)
return applied;
805 if (slot.loops >= 0 && slot.played >= slot.loops) {
806 slot.phase = Phase::Completed;
807 if (slot.onComplete) slot.onComplete();
808 bumpGeneration(slot.generation);
814 return applyQuat(slot, 0.f,
true);
818 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return okNoOp();
820 if (slot.phase == Phase::Delayed) {
821 slot.delayLeft -= dt;
822 if (slot.delayLeft > 0.f)
return okApplied();
823 dt = -slot.delayLeft;
824 slot.delayLeft = 0.f;
825 slot.phase = Phase::Running;
826 auto started = applyColor(slot, 0.f,
true);
831 if (slot.duration <= 0.f)
return finishColor(slot);
834 while (slot.phase == Phase::Running && slot.elapsed >= slot.duration) {
835 const float over = slot.elapsed - slot.duration;
836 auto finished = finishColor(slot);
837 if (!finished)
return finished;
838 if (slot.phase != Phase::Running)
break;
841 if (slot.phase == Phase::Running)
return applyColor(slot, slot.elapsed / slot.duration,
true);
846 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return okNoOp();
848 if (slot.phase == Phase::Delayed) {
849 slot.delayLeft -= dt;
850 if (slot.delayLeft > 0.f)
return okApplied();
851 dt = -slot.delayLeft;
852 slot.delayLeft = 0.f;
853 slot.phase = Phase::Running;
854 auto started = applyQuat(slot, 0.f,
true);
859 if (slot.duration <= 0.f)
return finishQuat(slot);
862 while (slot.phase == Phase::Running && slot.elapsed >= slot.duration) {
863 const float over = slot.elapsed - slot.duration;
864 auto finished = finishQuat(slot);
865 if (!finished)
return finished;
866 if (slot.phase != Phase::Running)
break;
869 if (slot.phase == Phase::Running)
return applyQuat(slot, slot.elapsed / slot.duration,
true);
873const MotionRuntime::ColorSlot *MotionRuntime::resolveColor(MotionHandle
handle)
const {
874 if (
handle.isNull() ||
handle.index >= colors_.size())
return nullptr;
875 const auto &slot = colors_[
handle.index];
876 if (slot.generation !=
handle.generation)
return nullptr;
877 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return nullptr;
881const MotionRuntime::QuatSlot *MotionRuntime::resolveQuat(MotionHandle
handle)
const {
882 if (
handle.isNull() ||
handle.index >= quats_.size())
return nullptr;
883 const auto &slot = quats_[
handle.index];
884 if (slot.generation !=
handle.generation)
return nullptr;
885 if (slot.phase != Phase::Delayed && slot.phase != Phase::Running)
return nullptr;
890 slot.phase = slot.delayLeft > 0.f ? Phase::Delayed : Phase::Running;
893 slot.reverse =
false;
894 slot.current = slot.from;
896 std::uint32_t
index = 0;
897 if (!freeColors_.empty()) {
898 index = freeColors_.back();
899 freeColors_.pop_back();
900 const std::uint32_t gen = colors_[
index].generation == 0 ? 1u : colors_[
index].generation;
901 colors_[
index] = std::move(slot);
902 colors_[
index].generation = gen;
904 index =
static_cast<std::uint32_t
>(colors_.size());
905 colors_.push_back(std::move(slot));
921 slot.phase = slot.delayLeft > 0.f ? Phase::Delayed : Phase::Running;
924 slot.reverse =
false;
925 slot.current = slot.from;
927 std::uint32_t
index = 0;
928 if (!freeQuats_.empty()) {
929 index = freeQuats_.back();
930 freeQuats_.pop_back();
931 const std::uint32_t gen = quats_[
index].generation == 0 ? 1u : quats_[
index].generation;
932 quats_[
index] = std::move(slot);
933 quats_[
index].generation = gen;
935 index =
static_cast<std::uint32_t
>(quats_.size());
936 quats_.push_back(std::move(slot));
956 slot.from =
desc.from;
958 slot.duration =
desc.duration;
959 slot.delayLeft =
desc.delay;
960 slot.loops =
desc.loops;
961 slot.loopMode =
desc.loopMode;
962 slot.ease =
desc.ease.empty() ?
"linear" :
desc.ease;
963 slot.sink =
desc.sink;
964 slot.onUpdate =
desc.onUpdate;
965 slot.onComplete =
desc.onComplete;
966 slot.onCancel =
desc.onCancel;
967 slot.cancelOnError =
desc.cancelOnError;
968 return occupyColor(std::move(slot));
976 slot.from =
desc.from;
978 slot.duration =
desc.duration;
979 slot.delayLeft =
desc.delay;
980 slot.loops =
desc.loops;
981 slot.loopMode =
desc.loopMode;
982 slot.ease =
desc.ease.empty() ?
"linear" :
desc.ease;
983 slot.sink =
desc.sink;
984 slot.onUpdate =
desc.onUpdate;
985 slot.onComplete =
desc.onComplete;
986 slot.onCancel =
desc.onCancel;
987 slot.cancelOnError =
desc.cancelOnError;
988 return occupyQuat(std::move(slot));
992 const auto *slot = resolveColor(
handle);
998 const auto *slot = resolveQuat(
handle);
Stable, structured diagnostics shared by engine modules.
Dense motion storage advanced by Animation::advance(SimulationStep).
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
void ensureVec2Capacity(std::size_t count)
eve::Result< MotionQuat > quatValue(MotionHandle handle) const
bool isActive(MotionHandle handle) const noexcept
void ensureQuatCapacity(std::size_t count)
void ensureFloatCapacity(std::size_t count)
Pre-size float pool slots (Inactive) and reserve storage.
eve::Result< MotionVec3 > vec3Value(MotionHandle handle) const
eve::Result< MotionHandle > spawnColor(const ColorDesc &desc)
void ensureVec3Capacity(std::size_t count)
eve::Result< MotionColor > colorValue(MotionHandle handle) const
eve::Result< MotionHandle > spawnFloat(const FloatDesc &desc)
int activeCount() const noexcept
eve::Result< void > advance(const eve::SimulationStep &step)
eve::Result< MotionHandle > spawnVec2(const Vec2Desc &desc)
eve::Result< void > complete(MotionHandle handle)
eve::Result< MotionVec2 > vec2Value(MotionHandle handle) const
eve::Result< float > floatValue(MotionHandle handle) const
void ensureColorCapacity(std::size_t count)
eve::Result< MotionHandle > spawnVec3(const Vec3Desc &desc)
eve::Result< MotionHandle > spawnQuat(const QuatDesc &desc)
eve::Result< void > cancel(MotionHandle handle)
eve::Result< float > secondsForStep(const eve::SimulationStep &step, bool hasLastTick, eve::SimulationTick lastTick, const char *owner)
Validate a scheduler step before an animation object mutates state.
MotionQuat slerpMotionQuat(MotionQuat a, MotionQuat b, float t)
Spherical linear interpolation for MotionQuat (shortest path).
float evaluateMotionOscillation(float t, int frequency, float dampingRatio)
LitMotion-style damped sine envelope in [0,1] progress.
MotionColor lerpMotionColor(MotionColor a, MotionColor b, float t)
Component-wise lerp for MotionColor.
float evaluateMotionShakeSign(std::uint32_t seed, int frequency, float t, int axis)
Deterministic shake sign in [-1,1] for axis (0..n).
@ Yoyo
Alternate direction each cycle.
float evaluateMotionEase(float t, const char *kind)
Evaluate an ease curve; kinds match Math.ease / Tween.
MotionStyle
Evaluation style for a motion slot.
@ Tween
Lerp/slerp from -> to.
@ Shake
Punch with per-axis deterministic random sign.
Result< T > applied(T value, std::vector< Diagnostic > diagnostics={})
Construct an Applied result with an owning payload and optional diagnostics.
One deterministic fixed-step emitted by SimulationClock.
Compact RGBA color used by motion adapters.
Generation-checked slot identity for a live motion.