mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
lottie: suppport writable expressions
This function sets the value of a specified expression variable within a particular layer. It is useful for dynamically changing the properties of a layer at runtime. Experimental API - Result LottieAnimation::assign(const char* layer, uint32_t ix, const char* variable, float value) - Tvg_Result tvg_lottie_animation_assign(Tvg_Animation* animation, const char* layer, uint32_t ix, const char* var, float val)
This commit is contained in:
parent
4c5ce9862e
commit
5de098f128
12 changed files with 148 additions and 1 deletions
|
@ -2569,6 +2569,24 @@ TVG_API Tvg_Result tvg_lottie_animation_get_marker(Tvg_Animation* animation, uin
|
|||
TVG_API Tvg_Result tvg_lottie_animation_tween(Tvg_Animation* animation, float from, float to, float progress);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Updates the value of an expression variable for a specific layer.
|
||||
*
|
||||
* \param[in] animation The Tvg_Animation pointer to the Lottie animation object.
|
||||
* \param[in] layer The name of the layer containing the variable to be updated.
|
||||
* \param[in] ix The property index of the variable within the layer.
|
||||
* \param[in] var The name of the variable to be updated.
|
||||
* \param[in] val The new value to assign to the variable.
|
||||
*
|
||||
* \return Tvg_Result enumeration.
|
||||
* \retval TVG_RESULT_INSUFFICIENT_CONDITION If the animation is not loaded.
|
||||
* \retval TVG_RESULT_INVALID_ARGUMENT When the given parameter is invalid.
|
||||
* \retval TVG_RESULT_NOT_SUPPORTED When neither the layer nor the property is found in the current animation.
|
||||
*
|
||||
* \note Experimental API
|
||||
*/
|
||||
TVG_API Tvg_Result tvg_lottie_animation_assign(Tvg_Animation* animation, const char* layer, uint32_t ix, const char* var, float val);
|
||||
|
||||
/** \} */ // end addtogroup ThorVGCapi_LottieAnimation
|
||||
|
||||
|
||||
|
|
|
@ -974,6 +974,16 @@ TVG_API Tvg_Result tvg_lottie_animation_tween(Tvg_Animation* animation, float fr
|
|||
return TVG_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
TVG_API Tvg_Result tvg_lottie_animation_assign(Tvg_Animation* animation, const char* layer, uint32_t ix, const char* var, float val)
|
||||
{
|
||||
#ifdef THORVG_LOTTIE_LOADER_SUPPORT
|
||||
if (!animation) return TVG_RESULT_INVALID_ARGUMENT;
|
||||
return (Tvg_Result) reinterpret_cast<LottieAnimation*>(animation)->assign(layer, ix, var, val);
|
||||
#endif
|
||||
return TVG_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -89,6 +89,25 @@ public:
|
|||
*/
|
||||
const char* marker(uint32_t idx) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Updates the value of an expression variable for a specific layer.
|
||||
*
|
||||
* This function sets the value of a specified expression variable within a particular layer.
|
||||
* It is useful for dynamically changing the properties of a layer at runtime.
|
||||
*
|
||||
* @param[in] layer The name of the layer containing the variable to be updated.
|
||||
* @param[in] ix The property index of the variable within the layer.
|
||||
* @param[in] var The name of the variable to be updated.
|
||||
* @param[in] val The new value to assign to the variable.
|
||||
*
|
||||
* @retval Result::InsufficientCondition If the animation is not loaded.
|
||||
* @retval Result::InvalidArguments When the given parameter is invalid.
|
||||
* @retval Result::NonSupport When neither the layer nor the property is found in the current animation.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result assign(const char* layer, uint32_t ix, const char* var, float val);
|
||||
|
||||
/**
|
||||
* @brief Creates a new LottieAnimation object.
|
||||
*
|
||||
|
|
|
@ -84,6 +84,18 @@ const char* LottieAnimation::marker(uint32_t idx) noexcept
|
|||
}
|
||||
|
||||
|
||||
Result LottieAnimation::assign(const char* layer, uint32_t ix, const char* var, float val)
|
||||
{
|
||||
if (!layer || !var) return Result::InvalidArguments;
|
||||
|
||||
auto loader = PICTURE(pImpl->picture)->loader;
|
||||
if (!loader) return Result::InsufficientCondition;
|
||||
if (static_cast<LottieLoader*>(loader)->assign(layer, ix, var, val)) return Result::Success;
|
||||
|
||||
return Result::NonSupport;
|
||||
}
|
||||
|
||||
|
||||
LottieAnimation* LottieAnimation::gen() noexcept
|
||||
{
|
||||
return new LottieAnimation;
|
||||
|
|
|
@ -1326,9 +1326,20 @@ jerry_value_t LottieExpressions::buildGlobal()
|
|||
}
|
||||
|
||||
|
||||
void LottieExpressions::buildWritables(LottieExpression* exp)
|
||||
{
|
||||
if (exp->writables.empty()) return;
|
||||
ARRAY_FOREACH(p, exp->writables) {
|
||||
auto writable = jerry_number(p->val);
|
||||
jerry_object_set_sz(global, p->var, writable);
|
||||
jerry_value_free(writable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jerry_value_t LottieExpressions::evaluate(float frameNo, LottieExpression* exp)
|
||||
{
|
||||
if (exp->disabled) return jerry_undefined();
|
||||
if (exp->disabled && exp->writables.empty()) return jerry_undefined();
|
||||
|
||||
buildGlobal(exp);
|
||||
|
||||
|
@ -1352,6 +1363,9 @@ jerry_value_t LottieExpressions::evaluate(float frameNo, LottieExpression* exp)
|
|||
//expansions per object type
|
||||
if (exp->object->type == LottieObject::Transform) _buildTransform(global, frameNo, static_cast<LottieTransform*>(exp->object));
|
||||
|
||||
//update writable values
|
||||
buildWritables(exp);
|
||||
|
||||
//evaluate the code
|
||||
auto eval = jerry_eval((jerry_char_t *) exp->code, strlen(exp->code), JERRY_PARSE_NO_OPTS);
|
||||
|
||||
|
|
|
@ -139,6 +139,7 @@ private:
|
|||
void buildComp(LottieComposition* comp, float frameNo, LottieExpression* exp);
|
||||
void buildComp(jerry_value_t context, float frameNo, LottieLayer* comp, LottieExpression* exp);
|
||||
void buildGlobal(LottieExpression* exp);
|
||||
void buildWritables(LottieExpression* exp);
|
||||
|
||||
//global object, attributes, methods
|
||||
jerry_value_t global;
|
||||
|
|
|
@ -458,3 +458,12 @@ bool LottieLoader::tween(float from, float to, float progress)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LottieLoader::assign(const char* layer, uint32_t ix, const char* var, float val)
|
||||
{
|
||||
if (!ready() || !comp->expressions) return false;
|
||||
comp->root->assign(layer, ix, var, val);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -73,6 +73,7 @@ public:
|
|||
|
||||
float shorten(float frameNo); //Reduce the accuracy for performance
|
||||
bool tween(float from, float to, float progress);
|
||||
bool assign(const char* layer, uint32_t ix, const char* var, float val);
|
||||
|
||||
private:
|
||||
bool ready();
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "tvgMath.h"
|
||||
#include "tvgTaskScheduler.h"
|
||||
#include "tvgLottieModel.h"
|
||||
#include "tvgCompressor.h"
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -531,6 +532,17 @@ LottieGroup::LottieGroup()
|
|||
}
|
||||
|
||||
|
||||
LottieProperty* LottieGroup::property(uint16_t ix)
|
||||
{
|
||||
ARRAY_FOREACH(p, children) {
|
||||
auto child = static_cast<LottieObject*>(*p);
|
||||
if (auto property = child->property(ix)) return property;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void LottieGroup::prepare(LottieObject::Type type)
|
||||
{
|
||||
LottieObject::type = type;
|
||||
|
@ -617,6 +629,16 @@ LottieLayer::~LottieLayer()
|
|||
}
|
||||
|
||||
|
||||
LottieProperty* LottieLayer::property(uint16_t ix)
|
||||
{
|
||||
if (transform) {
|
||||
if (auto property = transform->property(ix)) return property;
|
||||
}
|
||||
|
||||
return LottieGroup::property(ix);
|
||||
}
|
||||
|
||||
|
||||
void LottieLayer::prepare(RGB24* color)
|
||||
{
|
||||
/* if layer is hidden, only useful data is its transform matrix.
|
||||
|
@ -658,6 +680,20 @@ float LottieLayer::remap(LottieComposition* comp, float frameNo, LottieExpressio
|
|||
}
|
||||
|
||||
|
||||
bool LottieLayer::assign(const char* layer, uint32_t ix, const char* var, float val)
|
||||
{
|
||||
//find the target layer by name
|
||||
auto target = layerById(djb2Encode(layer));
|
||||
if (!target) return false;
|
||||
|
||||
//find the target property by ix
|
||||
auto property = target->property(ix);
|
||||
if (property && property->exp) return property->exp->assign(var, val);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
LottieComposition::~LottieComposition()
|
||||
{
|
||||
if (!initiated && root) delete(root->scene);
|
||||
|
|
|
@ -845,6 +845,7 @@ struct LottieGroup : LottieObject, LottieRenderPooler<tvg::Shape>
|
|||
|
||||
void prepare(LottieObject::Type type = LottieObject::Group);
|
||||
bool mergeable() override { return allowMerge; }
|
||||
LottieProperty* property(uint16_t ix);
|
||||
|
||||
LottieObject* content(unsigned long id)
|
||||
{
|
||||
|
@ -880,6 +881,8 @@ struct LottieLayer : LottieGroup
|
|||
bool mergeable() override { return false; }
|
||||
void prepare(RGB24* color = nullptr);
|
||||
float remap(LottieComposition* comp, float frameNo, LottieExpressions* exp);
|
||||
LottieProperty* property(uint16_t ix);
|
||||
bool assign(const char* layer, uint32_t ix, const char* var, float val);
|
||||
|
||||
char* name = nullptr;
|
||||
LottieLayer* parent = nullptr;
|
||||
|
|
|
@ -573,6 +573,7 @@ LottieTransform* LottieParser::parseTransform(bool ddd)
|
|||
else if (transform->coords && KEY_AS("y")) parseProperty<LottieProperty::Type::Float>(transform->coords->y);
|
||||
else if (KEY_AS("x") && expressions) transform->position.exp = getExpression(getStringCopy(), comp, context.layer, context.parent, &transform->position);
|
||||
else if (KEY_AS("sid")) registerSlot<LottieProperty::Type::Position>(transform, getString());
|
||||
else if (KEY_AS("ix")) transform->position.ix = getInt();
|
||||
else skip();
|
||||
}
|
||||
transform->position.type = LottieProperty::Type::Position;
|
||||
|
|
|
@ -128,11 +128,18 @@ struct LottieExpression
|
|||
{
|
||||
enum LoopMode : uint8_t { None = 0, InCycle = 1, InPingPong, InOffset, InContinue, OutCycle, OutPingPong, OutOffset, OutContinue };
|
||||
|
||||
//writable expressions variable name and value.
|
||||
struct Writable {
|
||||
char* var;
|
||||
float val;
|
||||
};
|
||||
|
||||
char* code;
|
||||
LottieComposition* comp;
|
||||
LottieLayer* layer;
|
||||
LottieObject* object;
|
||||
LottieProperty* property;
|
||||
Array<Writable> writables;
|
||||
bool disabled = false;
|
||||
|
||||
struct {
|
||||
|
@ -155,8 +162,24 @@ struct LottieExpression
|
|||
|
||||
~LottieExpression()
|
||||
{
|
||||
ARRAY_FOREACH(p, writables) {
|
||||
tvg::free(p->var);
|
||||
}
|
||||
tvg::free(code);
|
||||
}
|
||||
|
||||
bool assign(const char* var, float val)
|
||||
{
|
||||
//overwrite the existing value
|
||||
ARRAY_FOREACH(p, writables) {
|
||||
if (tvg::equal(var, p->var)) {
|
||||
p->val = val;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
writables.push({tvg::duplicate(var), val});
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue