blob: 55ca96409de97dfacf5d396789ec476d1a366895 [file] [log] [blame]
#include "rive/animation/animation_reset_factory.hpp"
#include "rive/animation/linear_animation.hpp"
#include "rive/animation/animation_state.hpp"
#include "rive/animation/keyed_object.hpp"
#include "rive/animation/keyed_property.hpp"
#include "rive/generated/core_registry.hpp"
#include <map>
#include <set>
using namespace rive;
class KeyedPropertyData
{
public:
const KeyedProperty* keyedProperty;
bool isBaseline;
KeyedPropertyData(const KeyedProperty* value, bool baselineValue) :
keyedProperty(value), isBaseline(baselineValue)
{}
};
class KeyedObjectData
{
public:
std::vector<KeyedPropertyData> keyedPropertiesData;
std::set<int> keyedPropertiesSet;
uint32_t objectId;
KeyedObjectData(const uint32_t value) { objectId = value; }
void addProperties(const KeyedObject* keyedObject, bool isBaseline)
{
size_t index = 0;
while (index < keyedObject->numKeyedProperties())
{
auto keyedProperty = keyedObject->getProperty(index);
auto pos = keyedPropertiesSet.find(keyedProperty->propertyKey());
if (pos == keyedPropertiesSet.end())
{
switch (CoreRegistry::propertyFieldId(keyedProperty->propertyKey()))
{
case CoreDoubleType::id:
case CoreColorType::id:
keyedPropertiesSet.insert(keyedProperty->propertyKey());
keyedPropertiesData.push_back(KeyedPropertyData(keyedProperty, isBaseline));
break;
}
}
index++;
}
}
};
class AnimationsData
{
private:
std::vector<std::unique_ptr<KeyedObjectData>> keyedObjectsData;
KeyedObjectData* getKeyedObjectData(const KeyedObject* keyedObject)
{
for (auto& keyedObjectData : keyedObjectsData)
{
if (keyedObjectData->objectId == keyedObject->objectId())
{
return keyedObjectData.get();
}
}
auto keyedObjectData = rivestd::make_unique<KeyedObjectData>(keyedObject->objectId());
auto ref = keyedObjectData.get();
keyedObjectsData.push_back(std::move(keyedObjectData));
return ref;
}
void findKeyedObjects(const LinearAnimation* animation, bool isFirstAnimation)
{
size_t index = 0;
while (index < animation->numKeyedObjects())
{
auto keyedObject = animation->getObject(index);
auto keyedObjectData = getKeyedObjectData(keyedObject);
keyedObjectData->addProperties(keyedObject, isFirstAnimation);
index++;
}
}
public:
AnimationsData(std::vector<const LinearAnimation*>& animations, bool useFirstAsBaseline)
{
bool isFirstAnimation = useFirstAsBaseline;
for (auto animation : animations)
{
findKeyedObjects(animation, isFirstAnimation);
isFirstAnimation = false;
}
}
void writeObjects(AnimationReset* animationReset, ArtboardInstance* artboard)
{
for (auto& keyedObjectData : keyedObjectsData)
{
auto object = artboard->resolve(keyedObjectData->objectId)->as<Component>();
auto propertiesData = keyedObjectData->keyedPropertiesData;
if (propertiesData.size() > 0)
{
animationReset->writeObjectId(keyedObjectData->objectId);
animationReset->writeTotalProperties(propertiesData.size());
for (auto keyedPropertyData : propertiesData)
{
auto keyedProperty = keyedPropertyData.keyedProperty;
auto propertyKey = keyedProperty->propertyKey();
switch (CoreRegistry::propertyFieldId(propertyKey))
{
case CoreDoubleType::id:
animationReset->writePropertyKey(propertyKey);
if (keyedPropertyData.isBaseline)
{
auto firstKeyframe = keyedProperty->first();
if (firstKeyframe != nullptr)
{
auto value =
keyedProperty->first()->as<KeyFrameDouble>()->value();
animationReset->writePropertyValue(value);
}
}
else
{
animationReset->writePropertyValue(
CoreRegistry::getDouble(object, propertyKey));
}
break;
case CoreColorType::id:
animationReset->writePropertyKey(propertyKey);
if (keyedPropertyData.isBaseline)
{
auto firstKeyframe = keyedProperty->first();
if (firstKeyframe != nullptr)
{
auto value =
keyedProperty->first()->as<KeyFrameColor>()->value();
animationReset->writePropertyValue(value);
}
}
else
{
animationReset->writePropertyValue(
CoreRegistry::getColor(object, propertyKey));
}
break;
}
}
}
}
animationReset->complete();
}
};
std::unique_ptr<AnimationReset> AnimationResetFactory::getInstance()
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_resources.size() > 0)
{
auto instance = std::move(m_resources.back());
m_resources.pop_back();
return instance;
}
auto instance = rivestd::make_unique<AnimationReset>();
return instance;
}
void AnimationResetFactory::fromState(StateInstance* stateInstance,
std::vector<const LinearAnimation*>& animations)
{
if (stateInstance != nullptr)
{
auto state = stateInstance->state();
if (state->is<AnimationState>() && state->as<AnimationState>()->animation() != nullptr)
{
animations.push_back(state->as<AnimationState>()->animation());
}
}
}
std::unique_ptr<AnimationReset> AnimationResetFactory::fromStates(StateInstance* stateFrom,
StateInstance* currentState,
ArtboardInstance* artboard)
{
std::vector<const LinearAnimation*> animations;
fromState(stateFrom, animations);
fromState(currentState, animations);
return fromAnimations(animations, artboard, false);
}
std::unique_ptr<AnimationReset> AnimationResetFactory::fromAnimations(
std::vector<const LinearAnimation*>& animations,
ArtboardInstance* artboard,
bool useFirstAsBaseline)
{
auto animationsData = new AnimationsData(animations, useFirstAsBaseline);
auto animationReset = AnimationResetFactory::getInstance();
animationsData->writeObjects(animationReset.get(), artboard);
delete animationsData;
return animationReset;
}
std::vector<std::unique_ptr<AnimationReset>> AnimationResetFactory::m_resources;
std::mutex AnimationResetFactory::m_mutex;
void AnimationResetFactory::release(std::unique_ptr<AnimationReset> value)
{
std::unique_lock<std::mutex> lock(m_mutex);
value->clear();
m_resources.push_back(std::move(value));
}