mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 14:48:24 +00:00
Merge 3aa434ce03
into 16604a873a
This commit is contained in:
commit
31cdfb7079
12 changed files with 361 additions and 90 deletions
|
@ -41,6 +41,7 @@ struct UserExample : tvgexam::Example
|
|||
unique_ptr<tvg::LottieAnimation> slot9;
|
||||
unique_ptr<tvg::LottieAnimation> slot10;
|
||||
unique_ptr<tvg::LottieAnimation> marker;
|
||||
uint32_t slotId1, slotId2, slotId3, slotId4, slotId6, slotId7, slotId8, slotId9, slotId10;
|
||||
uint32_t w, h;
|
||||
uint32_t size;
|
||||
|
||||
|
@ -173,7 +174,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample1.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"gradient_fill":{"p":{"p":2,"k":{"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0,0,1,1]}}}})";
|
||||
if (!tvgexam::verify(slot1->override(slotJson))) return false;
|
||||
slotId1 = slot1->gen(slotJson);
|
||||
if (!tvgexam::verify(slot1->apply(slotId1))) return false;
|
||||
|
||||
sizing(picture, 1);
|
||||
|
||||
|
@ -187,7 +189,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample2.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"ball_color":{"p":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[0,0.176,0.867]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":22,"s":[0.867,0,0.533]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[0.867,0,0.533]},{"t":51,"s":[0,0.867,0.255]}]}}})";
|
||||
if (!tvgexam::verify(slot2->override(slotJson))) return false;
|
||||
slotId2 = slot2->gen(slotJson);
|
||||
if (!tvgexam::verify(slot2->apply(slotId2))) return false;
|
||||
|
||||
sizing(picture, 2);
|
||||
|
||||
|
@ -201,7 +204,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample3.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"path_img":{"p":{"id":"image_0","w":200,"h":300,"u":"images/","p":"logo.png","e":0}}})";
|
||||
if (!tvgexam::verify(slot3->override(slotJson))) return false;
|
||||
slotId3 = slot3->gen(slotJson);
|
||||
if (!tvgexam::verify(slot3->apply(slotId3))) return false;
|
||||
|
||||
sizing(picture, 3);
|
||||
|
||||
|
@ -215,7 +219,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample4.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"bg_color":{"p":{"a":0,"k":[1,0.8196,0.2275]}},"check_color":{"p":{"a":0,"k":[0.0078,0.0078,0.0078]}}})";
|
||||
if (!tvgexam::verify(slot4->override(slotJson))) return false;
|
||||
slotId4 = slot4->gen(slotJson);
|
||||
if (!tvgexam::verify(slot4->apply(slotId4))) return false;
|
||||
|
||||
sizing(picture, 4);
|
||||
|
||||
|
@ -240,7 +245,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample6.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"position_id":{"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[100,100],"t":0},{"s":[200,300],"t":100}]}}})";
|
||||
if (!tvgexam::verify(slot6->override(slotJson))) return false;
|
||||
slotId6 = slot6->gen(slotJson);
|
||||
if (!tvgexam::verify(slot6->apply(slotId6))) return false;
|
||||
|
||||
sizing(picture, 6);
|
||||
|
||||
|
@ -254,7 +260,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample7.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"scale_id":{"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[0,0],"t":0},{"s":[100,100],"t":100}]}}})";
|
||||
if (!tvgexam::verify(slot7->override(slotJson))) return false;
|
||||
slotId7 = slot7->gen(slotJson);
|
||||
if (!tvgexam::verify(slot7->apply(slotId7))) return false;
|
||||
|
||||
sizing(picture, 7);
|
||||
|
||||
|
@ -268,7 +275,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample8.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"rotation_id":{"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[0],"t":0},{"s":[180],"t":100}]}}})";
|
||||
if (!tvgexam::verify(slot8->override(slotJson))) return false;
|
||||
slotId8 = slot8->gen(slotJson);
|
||||
if (!tvgexam::verify(slot8->apply(slotId8))) return false;
|
||||
|
||||
sizing(picture, 8);
|
||||
|
||||
|
@ -282,7 +290,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample9.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"opacity_id":{"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"s":[0],"t":0},{"s":[100],"t":100}]}}})";
|
||||
if (!tvgexam::verify(slot9->override(slotJson))) return false;
|
||||
slotId9 = slot9->gen(slotJson);
|
||||
if (!tvgexam::verify(slot9->apply(slotId9))) return false;
|
||||
|
||||
sizing(picture, 9);
|
||||
|
||||
|
@ -296,7 +305,8 @@ struct UserExample : tvgexam::Example
|
|||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample10.json"))) return false;
|
||||
|
||||
const char* slotJson = R"({"rect_rotation":{"p":{"x":"var $bm_rt = time * 360;"}},"rect_scale":{"p":{"x":"var $bm_rt = [];$bm_rt[0] = value[0] + Math.cos(2 * Math.PI * time) * 100;$bm_rt[1] = value[1];"}},"rect_position":{"p":{"x":"var $bm_rt = [];$bm_rt[0] = value[0] + Math.cos(2 * Math.PI * time) * 100;$bm_rt[1] = value[1];"}}})";
|
||||
if (!tvgexam::verify(slot10->override(slotJson))) return false;
|
||||
slotId10 = slot10->gen(slotJson);
|
||||
if (!tvgexam::verify(slot10->apply(slotId10))) return false;
|
||||
|
||||
sizing(picture, 10);
|
||||
|
||||
|
@ -317,6 +327,19 @@ struct UserExample : tvgexam::Example
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
~UserExample()
|
||||
{
|
||||
slot1->del(slotId1);
|
||||
slot2->del(slotId2);
|
||||
slot3->del(slotId3);
|
||||
slot4->del(slotId4);
|
||||
slot6->del(slotId6);
|
||||
slot7->del(slotId7);
|
||||
slot8->del(slotId8);
|
||||
slot9->del(slotId9);
|
||||
slot10->del(slotId10);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2623,19 +2623,49 @@ TVG_API Tvg_Animation* tvg_lottie_animation_new(void);
|
|||
|
||||
|
||||
/*!
|
||||
* @brief Override the lottie properties through the slot data.
|
||||
* @brief Generates a new slot from the given slot data.
|
||||
*
|
||||
* @param[in] animation The Tvg_Animation object to override the property with the slot.
|
||||
* @param[in] slot The Lottie slot data in json, or @c nullptr to reset.
|
||||
* @param[in] animation The Tvg_Animation pointer to the Lottie animation object.
|
||||
* @param[in] slot The Lottie slot data in JSON format.
|
||||
*
|
||||
* @return The generated slot ID when successful, 0 otherwise.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
TVG_API uint32_t tvg_lottie_animation_gen_slot(Tvg_Animation* animation, const char* slot);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Applies a previously generated slot to the animation.
|
||||
*
|
||||
* @param[in] animation The Tvg_Animation pointer to the Lottie animation object.
|
||||
* @param[in] id The ID of the slot to apply, or 0 to reset all slots.
|
||||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION In case the animation is not loaded.
|
||||
* @retval TVG_RESULT_INVALID_ARGUMENT When the given @p slot is invalid
|
||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION In case the animation is not loaded or the slot ID is invalid.
|
||||
* @retval TVG_RESULT_NOT_SUPPORTED The Lottie Animation is not supported.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
TVG_API Tvg_Result tvg_lottie_animation_override(Tvg_Animation* animation, const char* slot);
|
||||
TVG_API Tvg_Result tvg_lottie_animation_apply_slot(Tvg_Animation* animation, uint32_t id);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Deletes a previously generated slot.
|
||||
*
|
||||
* @param[in] animation The Tvg_Animation pointer to the Lottie animation object.
|
||||
* @param[in] id The ID of the slot to delete.
|
||||
*
|
||||
* @return Tvg_Result enumeration.
|
||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION In case the animation is not loaded or the slot ID is invalid.
|
||||
* @retval TVG_RESULT_NOT_SUPPORTED The Lottie Animation is not supported.
|
||||
*
|
||||
* @note This function should be paired with gen.
|
||||
* @see tvg_lottie_animation_gen_slot()
|
||||
* @since 1.0
|
||||
*/
|
||||
TVG_API Tvg_Result tvg_lottie_animation_del_slot(Tvg_Animation* animation, uint32_t id);
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
|
|
|
@ -1035,10 +1035,29 @@ TVG_API Tvg_Animation* tvg_lottie_animation_new()
|
|||
}
|
||||
|
||||
|
||||
TVG_API Tvg_Result tvg_lottie_animation_override(Tvg_Animation* animation, const char* slot)
|
||||
TVG_API uint32_t tvg_lottie_animation_gen_slot(Tvg_Animation* animation, const char* slot)
|
||||
{
|
||||
#ifdef THORVG_LOTTIE_LOADER_SUPPORT
|
||||
if (animation) return (Tvg_Result) reinterpret_cast<LottieAnimation*>(animation)->override(slot);
|
||||
if (animation) return reinterpret_cast<LottieAnimation*>(animation)->gen(slot);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TVG_API Tvg_Result tvg_lottie_animation_apply_slot(Tvg_Animation* animation, uint32_t id)
|
||||
{
|
||||
#ifdef THORVG_LOTTIE_LOADER_SUPPORT
|
||||
if (animation) return (Tvg_Result) reinterpret_cast<LottieAnimation*>(animation)->apply(id);
|
||||
return TVG_RESULT_INVALID_ARGUMENT;
|
||||
#endif
|
||||
return TVG_RESULT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
TVG_API Tvg_Result tvg_lottie_animation_del_slot(Tvg_Animation* animation, uint32_t id)
|
||||
{
|
||||
#ifdef THORVG_LOTTIE_LOADER_SUPPORT
|
||||
if (animation) return (Tvg_Result) reinterpret_cast<LottieAnimation*>(animation)->del(id);
|
||||
return TVG_RESULT_INVALID_ARGUMENT;
|
||||
#endif
|
||||
return TVG_RESULT_NOT_SUPPORTED;
|
||||
|
|
|
@ -22,17 +22,6 @@ class TVG_API LottieAnimation final : public Animation
|
|||
public:
|
||||
~LottieAnimation() override;
|
||||
|
||||
/**
|
||||
* @brief Override Lottie properties using slot data.
|
||||
*
|
||||
* @param[in] slot The Lottie slot data in JSON format to override, or @c nullptr to reset.
|
||||
*
|
||||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
Result override(const char* slot) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Specifies a segment by marker.
|
||||
*
|
||||
|
@ -110,6 +99,56 @@ public:
|
|||
*/
|
||||
Result assign(const char* layer, uint32_t ix, const char* var, float val);
|
||||
|
||||
/**
|
||||
* @brief Creates a new slot based on the given Lottie slot data.
|
||||
*
|
||||
* This function parses the provided JSON-formatted slot data and generates
|
||||
* a new slot for animation control. The returned slot ID can be used to apply
|
||||
* or delete the slot later.
|
||||
*
|
||||
* @param[in] slot A JSON string representing the Lottie slot data.
|
||||
*
|
||||
* @return A unique, non-zero slot ID on success. Returns @c 0 if the slot generation fails.
|
||||
*
|
||||
* @see apply(uint32_t id)
|
||||
* @see del(uint32_t id)
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
uint32_t gen(const char* slot) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Applies a previously generated slot to the animation.
|
||||
*
|
||||
* This function applies the animation parameters defined by a slot.
|
||||
* If the provided slot ID is 0, all previously applied slots will be reset.
|
||||
*
|
||||
* @param[in] id The ID of the slot to apply. Use 0 to reset all slots.
|
||||
*
|
||||
* @retval Result::InvalidArguments If the animation is not loaded or the slot ID is invalid.
|
||||
*
|
||||
* @see gen(const char* slot)
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
Result apply(uint32_t id) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Deletes a previously generated slot.
|
||||
*
|
||||
* This function removes a slot by its ID.
|
||||
*
|
||||
* @param[in] id The ID of the slot to delete. Retrieve the ID from gen().
|
||||
*
|
||||
* @retval Result::InvalidArguments If the animation is not loaded or the slot ID is invalid.
|
||||
*
|
||||
* @note This function should be paired with gen.
|
||||
* @see gen(const char* slot)
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
Result del(uint32_t id) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Creates a new LottieAnimation object.
|
||||
*
|
||||
|
|
|
@ -30,15 +30,39 @@ LottieAnimation::LottieAnimation() = default;
|
|||
LottieAnimation::~LottieAnimation() = default;
|
||||
|
||||
|
||||
Result LottieAnimation::override(const char* slot) noexcept
|
||||
uint32_t LottieAnimation::gen(const char* slot) noexcept
|
||||
{
|
||||
auto loader = PICTURE(pImpl->picture)->loader;
|
||||
if (!loader) return 0;
|
||||
|
||||
return static_cast<LottieLoader*>(loader)->gen(slot);
|
||||
}
|
||||
|
||||
|
||||
Result LottieAnimation::apply(uint32_t id) noexcept
|
||||
{
|
||||
auto loader = PICTURE(pImpl->picture)->loader;
|
||||
if (!loader) return Result::InsufficientCondition;
|
||||
|
||||
if (static_cast<LottieLoader*>(loader)->override(slot)) {
|
||||
if (static_cast<LottieLoader*>(loader)->apply(id)) {
|
||||
PAINT(pImpl->picture)->mark(RenderUpdateFlag::All);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
return Result::InvalidArguments;
|
||||
}
|
||||
|
||||
|
||||
Result LottieAnimation::del(uint32_t id) noexcept
|
||||
{
|
||||
auto loader = PICTURE(pImpl->picture)->loader;
|
||||
if (!loader) return Result::InsufficientCondition;
|
||||
|
||||
if (static_cast<LottieLoader*>(loader)->del(id)) {
|
||||
PAINT(pImpl->picture)->mark(RenderUpdateFlag::All);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
return Result::InvalidArguments;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "tvgLottieModel.h"
|
||||
#include "tvgLottieParser.h"
|
||||
#include "tvgLottieBuilder.h"
|
||||
#include "tvgCompressor.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
|
@ -44,7 +45,9 @@ void LottieLoader::run(unsigned tid)
|
|||
comp = parser.comp;
|
||||
}
|
||||
if (parser.slots) {
|
||||
override(parser.slots, true);
|
||||
auto slotcode = gen(parser.slots, true);
|
||||
apply(slotcode, true);
|
||||
del(slotcode, true);
|
||||
parser.slots = nullptr;
|
||||
}
|
||||
builder->build(comp);
|
||||
|
@ -288,45 +291,98 @@ Paint* LottieLoader::paint()
|
|||
}
|
||||
|
||||
|
||||
bool LottieLoader::override(const char* slots, bool byDefault)
|
||||
bool LottieLoader::apply(uint32_t slotcode, bool byDefault)
|
||||
{
|
||||
if (!ready() || comp->slots.count == 0) return false;
|
||||
|
||||
//override slots
|
||||
if (slots) {
|
||||
//Copy the input data because the JSON parser will encode the data immediately.
|
||||
auto temp = byDefault ? slots : duplicate(slots);
|
||||
|
||||
//parsing slot json
|
||||
LottieParser parser(temp, dirName, builder->expressions());
|
||||
parser.comp = comp;
|
||||
|
||||
auto idx = 0;
|
||||
auto succeed = false;
|
||||
while (auto sid = parser.sid(idx == 0)) {
|
||||
auto applied = false;
|
||||
ARRAY_FOREACH(p, comp->slots) {
|
||||
if (strcmp((*p)->sid, sid)) continue;
|
||||
if (parser.apply(*p, byDefault)) succeed = applied = true;
|
||||
break;
|
||||
}
|
||||
if (!applied) parser.skip();
|
||||
++idx;
|
||||
bool applied = false;
|
||||
ARRAY_FOREACH(p, comp->slots) {
|
||||
// Reset all slots if slotcode is 0
|
||||
if (slotcode == 0) {
|
||||
(*p)->reset();
|
||||
applied = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
INLIST_FOREACH((*p)->values, q) {
|
||||
if (q->slotcode != slotcode) continue;
|
||||
(*p)->apply(q->prop, byDefault);
|
||||
applied = true;
|
||||
break;
|
||||
}
|
||||
tvg::free((char*)temp);
|
||||
rebuild = succeed;
|
||||
overridden |= succeed;
|
||||
return rebuild;
|
||||
//reset slots
|
||||
} else if (overridden) {
|
||||
ARRAY_FOREACH(p, comp->slots) (*p)->reset();
|
||||
overridden = false;
|
||||
rebuild = true;
|
||||
}
|
||||
|
||||
if (!applied) return false;
|
||||
|
||||
overridden = slotcode != 0;
|
||||
rebuild = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LottieLoader::del(uint32_t slotcode, bool byDefault)
|
||||
{
|
||||
if (!ready() || comp->slots.count == 0 || slotcode == 0) return false;
|
||||
|
||||
// Search matching value and remove
|
||||
ARRAY_FOREACH(p, comp->slots) {
|
||||
INLIST_FOREACH((*p)->values, q) {
|
||||
if (q->slotcode != slotcode) continue;
|
||||
if (!byDefault && (*p)->overridden) {
|
||||
(*p)->reset();
|
||||
rebuild = true;
|
||||
}
|
||||
(*p)->values.remove(q);
|
||||
delete(q);
|
||||
break;
|
||||
}
|
||||
if ((*p)->values.empty()) (*p)->overridden = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t LottieLoader::gen(const char* slots, bool byDefault)
|
||||
{
|
||||
if (!slots || !ready() || comp->slots.count == 0) return 0;
|
||||
|
||||
auto slotcode = djb2Encode(slots);
|
||||
ARRAY_FOREACH(p, comp->slots) {
|
||||
INLIST_FOREACH((*p)->values, q) {
|
||||
if (q->slotcode == slotcode) return slotcode;
|
||||
}
|
||||
}
|
||||
|
||||
auto temp = byDefault ? slots : duplicate(slots);
|
||||
|
||||
//parsing slot json
|
||||
LottieParser parser(temp, dirName, builder->expressions());
|
||||
parser.comp = comp;
|
||||
|
||||
auto idx = 0;
|
||||
bool generated = false;
|
||||
while (auto sid = parser.sid(idx == 0)) {
|
||||
ARRAY_FOREACH(p, comp->slots) {
|
||||
if (strcmp((*p)->sid, sid)) continue;
|
||||
auto prop = parser.parseSlot(*p);
|
||||
|
||||
if (prop) {
|
||||
(*p)->add(slotcode, prop);
|
||||
generated = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
|
||||
tvg::free((char*)temp);
|
||||
|
||||
if (!generated) return 0;
|
||||
return slotcode;
|
||||
}
|
||||
|
||||
|
||||
float LottieLoader::shorten(float frameNo)
|
||||
{
|
||||
//This ensures that the target frame number is reached.
|
||||
|
|
|
@ -56,7 +56,11 @@ public:
|
|||
bool resize(Paint* paint, float w, float h) override;
|
||||
bool read() override;
|
||||
Paint* paint() override;
|
||||
bool override(const char* slot, bool byDefault = false);
|
||||
|
||||
//Slot APIs
|
||||
uint32_t gen(const char* slot, bool byDefault = false);
|
||||
bool apply(uint32_t slotcode, bool byDefault = false);
|
||||
bool del(uint32_t slotcode, bool byDefault = false);
|
||||
|
||||
//Frame Controls
|
||||
bool frame(float no) override;
|
||||
|
|
|
@ -203,7 +203,52 @@ void LottieSlot::reset()
|
|||
}
|
||||
|
||||
|
||||
void LottieSlot::assign(LottieObject* target, bool byDefault)
|
||||
LottieProperty* LottieSlot::property(LottieObject* target)
|
||||
{
|
||||
LottieProperty* prop = nullptr;
|
||||
//apply slot object to all targets
|
||||
ARRAY_FOREACH(pair, pairs) {
|
||||
//backup the original properties before overwriting
|
||||
switch (type) {
|
||||
case LottieProperty::Type::Vector: {
|
||||
return new LottieVector(static_cast<LottieTransform*>(target)->position);
|
||||
}
|
||||
case LottieProperty::Type::Scalar: {
|
||||
return new LottieScalar(static_cast<LottieTransform*>(target)->scale);
|
||||
}
|
||||
case LottieProperty::Type::Float: {
|
||||
return new LottieFloat(static_cast<LottieTransform*>(target)->rotation);
|
||||
}
|
||||
case LottieProperty::Type::Opacity: {
|
||||
return new LottieOpacity(static_cast<LottieSolid*>(target)->opacity);
|
||||
}
|
||||
case LottieProperty::Type::Color: {
|
||||
return new LottieColor(static_cast<LottieSolid*>(target)->color);
|
||||
}
|
||||
case LottieProperty::Type::ColorStop: {
|
||||
return new LottieColorStop(static_cast<LottieGradient*>(target)->colorStops);
|
||||
}
|
||||
case LottieProperty::Type::TextDoc: {
|
||||
return new LottieTextDoc(static_cast<LottieText*>(target)->doc);
|
||||
}
|
||||
case LottieProperty::Type::Image: {
|
||||
return new LottieBitmap(static_cast<LottieImage*>(target)->data);
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
||||
void LottieSlot::add(uint32_t slotcode, LottieProperty* prop)
|
||||
{
|
||||
values.back(new Value{nullptr, nullptr, slotcode, prop});
|
||||
}
|
||||
|
||||
|
||||
void LottieSlot::apply(LottieProperty* prop, bool byDefault)
|
||||
{
|
||||
auto copy = !overridden && !byDefault;
|
||||
auto shallow = pairs.count == 1 ? true : false;
|
||||
|
@ -214,22 +259,22 @@ void LottieSlot::assign(LottieObject* target, bool byDefault)
|
|||
switch (type) {
|
||||
case LottieProperty::Type::Float: {
|
||||
if (copy) pair->prop = new LottieFloat(static_cast<LottieTransform*>(pair->obj)->rotation);
|
||||
pair->obj->override(&static_cast<LottieTransform*>(target)->rotation, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::Scalar: {
|
||||
if (copy) pair->prop = new LottieScalar(static_cast<LottieTransform*>(pair->obj)->scale);
|
||||
pair->obj->override(&static_cast<LottieTransform*>(target)->scale, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::Vector: {
|
||||
if (copy) pair->prop = new LottieVector(static_cast<LottieTransform*>(pair->obj)->position);
|
||||
pair->obj->override(&static_cast<LottieTransform*>(target)->position, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::Color: {
|
||||
if (copy) pair->prop = new LottieColor(static_cast<LottieSolid*>(pair->obj)->color);
|
||||
pair->obj->override(&static_cast<LottieSolid*>(target)->color, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::Opacity: {
|
||||
|
@ -237,27 +282,28 @@ void LottieSlot::assign(LottieObject* target, bool byDefault)
|
|||
if (pair->obj->type == LottieObject::Type::Transform) pair->prop = new LottieOpacity(static_cast<LottieTransform*>(pair->obj)->opacity);
|
||||
else pair->prop = new LottieOpacity(static_cast<LottieSolid*>(pair->obj)->opacity);
|
||||
}
|
||||
pair->obj->override(&static_cast<LottieSolid*>(target)->opacity, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::ColorStop: {
|
||||
if (copy) pair->prop = new LottieColorStop(static_cast<LottieGradient*>(pair->obj)->colorStops);
|
||||
pair->obj->override(&static_cast<LottieGradient*>(target)->colorStops, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::TextDoc: {
|
||||
if (copy) pair->prop = new LottieTextDoc(static_cast<LottieText*>(pair->obj)->doc);
|
||||
pair->obj->override(&static_cast<LottieText*>(target)->doc, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
case LottieProperty::Type::Image: {
|
||||
if (copy) pair->prop = new LottieBitmap(static_cast<LottieImage*>(pair->obj)->data);
|
||||
pair->obj->override(&static_cast<LottieImage*>(target)->data, shallow, !copy);
|
||||
pair->obj->override(prop, shallow, !copy);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!byDefault) overridden = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "tvgCommon.h"
|
||||
#include "tvgStr.h"
|
||||
#include "tvgCompressor.h"
|
||||
#include "tvgInlist.h"
|
||||
#include "tvgRender.h"
|
||||
#include "tvgLottieProperty.h"
|
||||
#include "tvgLottieRenderPooler.h"
|
||||
|
@ -1058,7 +1059,21 @@ struct LottieSlot
|
|||
LottieProperty* prop;
|
||||
};
|
||||
|
||||
void assign(LottieObject* target, bool byDefault);
|
||||
struct Value {
|
||||
INLIST_ITEM(Value);
|
||||
|
||||
uint32_t slotcode;
|
||||
LottieProperty* prop;
|
||||
|
||||
~Value()
|
||||
{
|
||||
delete(prop);
|
||||
}
|
||||
};
|
||||
|
||||
LottieProperty* property(LottieObject* target);
|
||||
void add(uint32_t slotcode, LottieProperty* prop);
|
||||
void apply(LottieProperty* prop, bool byDefault = false);
|
||||
void reset();
|
||||
|
||||
LottieSlot(LottieLayer* layer, LottieObject* parent, char* sid, LottieObject* obj, LottieProperty::Type type) : context{layer, parent}, sid(sid), type(type)
|
||||
|
@ -1069,6 +1084,7 @@ struct LottieSlot
|
|||
~LottieSlot()
|
||||
{
|
||||
tvg::free(sid);
|
||||
values.free();
|
||||
if (!overridden) return;
|
||||
ARRAY_FOREACH(pair, pairs) delete(pair->prop);
|
||||
}
|
||||
|
@ -1079,7 +1095,8 @@ struct LottieSlot
|
|||
} context;
|
||||
|
||||
char* sid;
|
||||
Array<Pair> pairs;
|
||||
Array<Pair> pairs; // Object-property pairs that can be overridden by this slot
|
||||
Inlist<Value> values; // Available slot values for property overrides
|
||||
LottieProperty::Type type;
|
||||
|
||||
bool overridden = false;
|
||||
|
|
|
@ -1539,7 +1539,7 @@ const char* LottieParser::sid(bool first)
|
|||
}
|
||||
|
||||
|
||||
bool LottieParser::apply(LottieSlot* slot, bool byDefault)
|
||||
LottieProperty* LottieParser::parseSlot(LottieSlot* slot)
|
||||
{
|
||||
enterObject();
|
||||
|
||||
|
@ -1598,14 +1598,13 @@ bool LottieParser::apply(LottieSlot* slot, bool byDefault)
|
|||
|
||||
if (!obj || Invalid()) {
|
||||
delete(obj);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slot->assign(obj, byDefault);
|
||||
|
||||
auto prop = slot->property(obj);
|
||||
delete(obj);
|
||||
|
||||
return true;
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ public:
|
|||
}
|
||||
|
||||
bool parse();
|
||||
bool apply(LottieSlot* slot, bool byDefault);
|
||||
const char* sid(bool first = false);
|
||||
LottieProperty* parseSlot(LottieSlot* slot);
|
||||
void captureSlots(const char* key);
|
||||
void registerSlot(LottieObject* obj, const char* sid, LottieProperty::Type type);
|
||||
|
||||
|
|
|
@ -46,26 +46,33 @@ TEST_CASE("Lottie Slot", "[tvgLottie]")
|
|||
|
||||
const char* slotJson = R"({"gradient_fill":{"p":{"p":2,"k":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}}})";
|
||||
|
||||
//Slot override before loaded
|
||||
REQUIRE(animation->override(slotJson) == Result::InsufficientCondition);
|
||||
//Slot generation before loaded
|
||||
REQUIRE(animation->gen(slotJson) == 0);
|
||||
|
||||
//Animation load
|
||||
REQUIRE(picture->load(TEST_DIR"/lottieslot.json") == Result::Success);
|
||||
|
||||
//Slot generation
|
||||
auto id = animation->gen(slotJson);
|
||||
REQUIRE(id > 0);
|
||||
|
||||
//Slot revert before overriding
|
||||
REQUIRE(animation->override(nullptr) == Result::Success);
|
||||
REQUIRE(animation->apply(0) == Result::Success);
|
||||
|
||||
//Slot override
|
||||
REQUIRE(animation->override(slotJson) == Result::Success);
|
||||
REQUIRE(animation->apply(id) == Result::Success);
|
||||
|
||||
//Slot revert
|
||||
REQUIRE(animation->override(nullptr) == Result::Success);
|
||||
REQUIRE(animation->apply(0) == Result::Success);
|
||||
|
||||
//Slot override after reverting
|
||||
REQUIRE(animation->override(slotJson) == Result::Success);
|
||||
REQUIRE(animation->apply(id) == Result::Success);
|
||||
|
||||
//Slot override with invalid JSON
|
||||
REQUIRE(animation->override("") == Result::InvalidArguments);
|
||||
//Slot generation with invalid JSON
|
||||
REQUIRE(animation->gen("") == 0);
|
||||
|
||||
//Slot deletion
|
||||
REQUIRE(animation->del(id) == Result::Success);
|
||||
|
||||
REQUIRE(Initializer::term() == Result::Success);
|
||||
}
|
||||
|
@ -84,14 +91,21 @@ TEST_CASE("Lottie Slot 2", "[tvgLottie]")
|
|||
//Animation load
|
||||
REQUIRE(picture->load(TEST_DIR"/lottieslotkeyframe.json") == Result::Success);
|
||||
|
||||
//Slot generation
|
||||
auto id = animation->gen(slotJson);
|
||||
REQUIRE(id > 0);
|
||||
|
||||
//Slot override
|
||||
REQUIRE(animation->override(slotJson) == Result::Success);
|
||||
REQUIRE(animation->apply(id) == Result::Success);
|
||||
|
||||
//Slot revert
|
||||
REQUIRE(animation->override(nullptr) == Result::Success);
|
||||
REQUIRE(animation->apply(0) == Result::Success);
|
||||
|
||||
//Slot override after reverting
|
||||
REQUIRE(animation->override(slotJson) == Result::Success);
|
||||
REQUIRE(animation->apply(id) == Result::Success);
|
||||
|
||||
//Slot deletion
|
||||
REQUIRE(animation->del(id) == Result::Success);
|
||||
|
||||
REQUIRE(Initializer::term() == Result::Success);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue