| #include "rive/animation/keyframe_uint.hpp" | |
| #include "rive/animation/keyframe_interpolator.hpp" | |
| #include "rive/generated/core_registry.hpp" | |
| #include <cmath> | |
| using namespace rive; | |
| // Uints hold by default -- most are enums, ids or mode flags. Defs opting in | |
| // with "interpolates": true tween instead, via the generated | |
| // CoreRegistry::isInterpolatableUint. Rounding and mixing must match | |
| // packages/rive_core/lib/animation/keyframe_uint.dart or editor preview and | |
| // runtime playback drift. | |
| // Clamps negatives to zero: a cubic interpolator can overshoot below zero and | |
| // the destination property is unsigned. | |
| static uint32_t roundToUint(float value) | |
| { | |
| return value <= 0.0f ? 0u : static_cast<uint32_t>(std::lround(value)); | |
| } | |
| static void applyUint(Core* object, int propertyKey, float mix, uint32_t value) | |
| { | |
| if (mix == 1.0f) | |
| { | |
| CoreRegistry::setUint(object, propertyKey, value); | |
| } | |
| else | |
| { | |
| float mixi = 1.0f - mix; | |
| CoreRegistry::setUint( | |
| object, | |
| propertyKey, | |
| roundToUint(CoreRegistry::getUint(object, propertyKey) * mixi + | |
| value * mix)); | |
| } | |
| } | |
| void KeyFrameUint::apply(Core* object, | |
| int propertyKey, | |
| float mix, | |
| const LinearAnimationInstance* context) | |
| { | |
| (void)context; | |
| if (CoreRegistry::isInterpolatableUint(propertyKey)) | |
| { | |
| applyUint(object, propertyKey, mix, value()); | |
| return; | |
| } | |
| CoreRegistry::setUint(object, propertyKey, value()); | |
| } | |
| void KeyFrameUint::applyInterpolation(Core* object, | |
| int propertyKey, | |
| float currentTime, | |
| const KeyFrame* nextFrame, | |
| float mix, | |
| const LinearAnimationInstance* context) | |
| { | |
| if (!CoreRegistry::isInterpolatableUint(propertyKey)) | |
| { | |
| CoreRegistry::setUint(object, propertyKey, value()); | |
| return; | |
| } | |
| const KeyFrameUint& nextUint = *nextFrame->as<KeyFrameUint>(); | |
| float fromValue = static_cast<float>(value()); | |
| float toValue = static_cast<float>(nextUint.value()); | |
| float f = (currentTime - seconds()) / (nextUint.seconds() - seconds()); | |
| float frameValue; | |
| if (KeyFrameInterpolator* keyframeInterpolator = | |
| effectiveInterpolator(context)) | |
| { | |
| frameValue = | |
| keyframeInterpolator->transformValue(fromValue, toValue, f); | |
| } | |
| else | |
| { | |
| frameValue = fromValue + (toValue - fromValue) * f; | |
| } | |
| applyUint(object, propertyKey, mix, roundToUint(frameValue)); | |
| } |