lottie/expressions: make it up the insufficient content() behavior

this is a follow-up fix for the initial expressions feature.
This commit is contained in:
Hermet Park 2024-05-02 20:24:23 +09:00 committed by Hermet Park
parent 1b4502bade
commit 830e5de0ce
3 changed files with 160 additions and 135 deletions

View file

@ -1232,7 +1232,7 @@ bool LottieBuilder::update(LottieComposition* comp, float frameNo)
auto root = comp->root; auto root = comp->root;
root->scene->clear(); root->scene->clear();
if (exps && comp->expressions) exps->update(frameNo, comp->timeAtFrame(frameNo)); if (exps && comp->expressions) exps->update(comp->timeAtFrame(frameNo));
for (auto child = root->children.end() - 1; child >= root->children.begin(); --child) { for (auto child = root->children.end() - 1; child >= root->children.begin(); --child) {
_updateLayer(root, static_cast<LottieLayer*>(*child), frameNo, exps); _updateLayer(root, static_cast<LottieLayer*>(*child), frameNo, exps);

View file

@ -31,7 +31,12 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
static uint32_t engineRefCnt = 0; //Expressions Engine reference count struct ExpContent
{
LottieObject* obj;
float frameNo;
};
//reserved expressions speicifiers //reserved expressions speicifiers
static const char* EXP_NAME = "name"; static const char* EXP_NAME = "name";
@ -47,7 +52,14 @@ static const char* EXP_VALUE = "value";
static const char* EXP_INDEX = "index"; static const char* EXP_INDEX = "index";
static const char* EXP_EFFECT= "effect"; static const char* EXP_EFFECT= "effect";
static void _buildLayer(jerry_value_t context, LottieLayer* layer, LottieComposition* comp);
static void contentFree(void *native_p, struct jerry_object_native_info_t *info_p)
{
free(native_p);
}
static jerry_object_native_info_t freeCb {contentFree, 0, 0};
static uint32_t engineRefCnt = 0; //Expressions Engine reference count
static char* _name(jerry_value_t args) static char* _name(jerry_value_t args)
@ -62,6 +74,14 @@ static char* _name(jerry_value_t args)
} }
static jerry_value_t _toComp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
{
TVGERR("LOTTIE", "toComp is not supported in expressions!");
return jerry_undefined();
}
static void _buildTransform(jerry_value_t context, LottieTransform* transform) static void _buildTransform(jerry_value_t context, LottieTransform* transform)
{ {
if (!transform) return; if (!transform) return;
@ -98,6 +118,86 @@ static void _buildTransform(jerry_value_t context, LottieTransform* transform)
} }
static void _buildLayer(jerry_value_t context, LottieLayer* layer, LottieComposition* comp)
{
auto width = jerry_number(layer->w);
jerry_object_set_sz(context, EXP_WIDTH, width);
jerry_value_free(width);
auto height = jerry_number(layer->h);
jerry_object_set_sz(context, EXP_HEIGHT, height);
jerry_value_free(height);
auto index = jerry_number(layer->id);
jerry_object_set_sz(context, EXP_INDEX, index);
jerry_value_free(index);
auto parent = jerry_object();
jerry_object_set_native_ptr(parent, nullptr, layer->parent);
jerry_object_set_sz(context, "parent", parent);
jerry_value_free(parent);
auto hasParent = jerry_boolean(layer->parent ? true : false);
jerry_object_set_sz(context, "hasParent", hasParent);
jerry_value_free(hasParent);
auto inPoint = jerry_number(layer->inFrame);
jerry_object_set_sz(context, "inPoint", inPoint);
jerry_value_free(inPoint);
auto outPoint = jerry_number(layer->outFrame);
jerry_object_set_sz(context, "outPoint", outPoint);
jerry_value_free(outPoint);
auto startTime = jerry_number(comp->timeAtFrame(layer->startFrame));
jerry_object_set_sz(context, "startTime", startTime);
jerry_value_free(startTime);
auto hasVideo = jerry_boolean(false);
jerry_object_set_sz(context, "hasVideo", hasVideo);
jerry_value_free(hasVideo);
auto hasAudio = jerry_boolean(false);
jerry_object_set_sz(context, "hasAudio", hasAudio);
jerry_value_free(hasAudio);
//active, #current in the animation range?
auto enabled = jerry_boolean(!layer->hidden);
jerry_object_set_sz(context, "enabled", enabled);
jerry_value_free(enabled);
auto audioActive = jerry_boolean(false);
jerry_object_set_sz(context, "audioActive", audioActive);
jerry_value_free(audioActive);
//sampleImage(point, radius = [.5, .5], postEffect=true, t=time)
_buildTransform(context, layer->transform);
//audioLevels, #the value of the Audio Levels property of the layer in decibels
auto timeRemap = jerry_object();
jerry_object_set_native_ptr(timeRemap, nullptr, &layer->timeRemap);
jerry_object_set_sz(context, "timeRemap", timeRemap);
jerry_value_free(timeRemap);
//marker.key(index)
//marker.key(name)
//marker.nearestKey(t)
//marker.numKeys
auto name = jerry_string_sz(layer->name);
jerry_object_set_sz(context, EXP_NAME, name);
jerry_value_free(name);
auto toComp = jerry_function_external(_toComp);
jerry_object_set_sz(context, "toComp", toComp);
jerry_object_set_native_ptr(toComp, nullptr, comp);
jerry_value_free(toComp);
}
static jerry_value_t _value(float frameNo, LottieExpression* exp) static jerry_value_t _value(float frameNo, LottieExpression* exp)
{ {
switch (exp->type) { switch (exp->type) {
@ -433,50 +533,58 @@ static jerry_value_t _fromCompToSurface(const jerry_call_info_t* info, const jer
} }
static jerry_value_t _path(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) static jerry_value_t _content(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
{ {
auto name = _name(args[0]); auto name = _name(args[0]);
auto data = static_cast<ExpContent*>(jerry_object_get_native_ptr(info->function, &freeCb));
//find the a path property(sh) in the shape layer auto group = static_cast<LottieGroup*>(data->obj);
auto group = static_cast<LottieGroup*>(jerry_object_get_native_ptr(info->function, nullptr)); auto target = group->content((char*)name);
auto path = group->content((char*)name);
free(name); free(name);
if (!target) return jerry_undefined();
if (!path) return jerry_undefined(); //find the a path property(sh) in the group layer?
switch (target->type) {
jerry_value_t pathset = jerry_object(); case LottieObject::Group: {
jerry_object_set_native_ptr(pathset, nullptr, &static_cast<LottiePath*>(path)->pathset); auto group = static_cast<LottieGroup*>(target);
jerry_object_set_sz(pathset, "path", pathset); auto obj = jerry_function_external(_content);
return pathset;
}
static jerry_value_t _shape(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
{
auto name = _name(args[0]);
//find a shape layer(group) from the root
auto layer = static_cast<LottieLayer*>(jerry_object_get_native_ptr(info->function, nullptr));
auto group = static_cast<LottieGroup*>(layer->content((char*)name));
free(name);
if (!group) return jerry_undefined();
auto property = jerry_function_external(_path);
//attach a transform //attach a transform
for (auto c = group->children.begin(); c < group->children.end(); ++c) { for (auto c = group->children.begin(); c < group->children.end(); ++c) {
if ((*c)->type == LottieObject::Type::Transform) { if ((*c)->type == LottieObject::Type::Transform) {
_buildTransform(property, static_cast<LottieTransform*>(*c)); _buildTransform(obj, static_cast<LottieTransform*>(*c));
break; break;
} }
} }
auto data2 = (ExpContent*)malloc(sizeof(ExpContent));
jerry_object_set_native_ptr(property, nullptr, group); data2->obj = group;
jerry_object_set_sz(property, EXP_CONTENT, property); data2->frameNo = data->frameNo;
jerry_object_set_native_ptr(obj, &freeCb, data2);
return property; jerry_object_set_sz(obj, EXP_CONTENT, obj);
return obj;
}
case LottieObject::Path: {
jerry_value_t obj = jerry_object();
jerry_object_set_native_ptr(obj, nullptr, &static_cast<LottiePath*>(target)->pathset);
jerry_object_set_sz(obj, "path", obj);
return obj;
}
case LottieObject::Trimpath: {
auto trimpath = static_cast<LottieTrimpath*>(target);
jerry_value_t obj = jerry_object();
auto start = jerry_number(trimpath->start(data->frameNo));
jerry_object_set_sz(obj, "start", start);
jerry_value_free(start);
auto end = jerry_number(trimpath->end(data->frameNo));
jerry_object_set_sz(obj, "end", end);
jerry_value_free(end);
auto offset = jerry_number(trimpath->offset(data->frameNo));
jerry_object_set_sz(obj, "offset", end);
jerry_value_free(offset);
return obj;
}
default: break;
}
return jerry_undefined();
} }
@ -736,13 +844,6 @@ static jerry_value_t _key(const jerry_call_info_t* info, const jerry_value_t arg
} }
static jerry_value_t _toComp(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
{
TVGERR("LOTTIE", "toComp is not supported in expressions!");
return jerry_undefined();
}
static jerry_value_t _createPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt) static jerry_value_t _createPath(const jerry_call_info_t* info, const jerry_value_t args[], const jerry_length_t argsCnt)
{ {
@ -807,86 +908,6 @@ static void _buildPath(jerry_value_t context, LottieExpression* exp)
} }
static void _buildLayer(jerry_value_t context, LottieLayer* layer, LottieComposition* comp)
{
auto width = jerry_number(layer->w);
jerry_object_set_sz(context, EXP_WIDTH, width);
jerry_value_free(width);
auto height = jerry_number(layer->h);
jerry_object_set_sz(context, EXP_HEIGHT, height);
jerry_value_free(height);
auto index = jerry_number(layer->id);
jerry_object_set_sz(context, EXP_INDEX, index);
jerry_value_free(index);
auto parent = jerry_object();
jerry_object_set_native_ptr(parent, nullptr, layer->parent);
jerry_object_set_sz(context, "parent", parent);
jerry_value_free(parent);
auto hasParent = jerry_boolean(layer->parent ? true : false);
jerry_object_set_sz(context, "hasParent", hasParent);
jerry_value_free(hasParent);
auto inPoint = jerry_number(layer->inFrame);
jerry_object_set_sz(context, "inPoint", inPoint);
jerry_value_free(inPoint);
auto outPoint = jerry_number(layer->outFrame);
jerry_object_set_sz(context, "outPoint", outPoint);
jerry_value_free(outPoint);
auto startTime = jerry_number(comp->timeAtFrame(layer->startFrame));
jerry_object_set_sz(context, "startTime", startTime);
jerry_value_free(startTime);
auto hasVideo = jerry_boolean(false);
jerry_object_set_sz(context, "hasVideo", hasVideo);
jerry_value_free(hasVideo);
auto hasAudio = jerry_boolean(false);
jerry_object_set_sz(context, "hasAudio", hasAudio);
jerry_value_free(hasAudio);
//active, #current in the animation range?
auto enabled = jerry_boolean(!layer->hidden);
jerry_object_set_sz(context, "enabled", enabled);
jerry_value_free(enabled);
auto audioActive = jerry_boolean(false);
jerry_object_set_sz(context, "audioActive", audioActive);
jerry_value_free(audioActive);
//sampleImage(point, radius = [.5, .5], postEffect=true, t=time)
_buildTransform(context, layer->transform);
//audioLevels, #the value of the Audio Levels property of the layer in decibels
auto timeRemap = jerry_object();
jerry_object_set_native_ptr(timeRemap, nullptr, &layer->timeRemap);
jerry_object_set_sz(context, "timeRemap", timeRemap);
jerry_value_free(timeRemap);
//marker.key(index)
//marker.key(name)
//marker.nearestKey(t)
//marker.numKeys
auto name = jerry_string_sz(layer->name);
jerry_object_set_sz(context, EXP_NAME, name);
jerry_value_free(name);
auto toComp = jerry_function_external(_toComp);
jerry_object_set_sz(context, "toComp", toComp);
jerry_object_set_native_ptr(toComp, nullptr, comp);
jerry_value_free(toComp);
}
static void _buildProperty(float frameNo, jerry_value_t context, LottieExpression* exp) static void _buildProperty(float frameNo, jerry_value_t context, LottieExpression* exp)
{ {
auto value = _value(frameNo, exp); auto value = _value(frameNo, exp);
@ -960,10 +981,14 @@ static void _buildProperty(float frameNo, jerry_value_t context, LottieExpressio
//propertyIndex //propertyIndex
//name //name
//content("name"), #look for the named shape object from a layer //content("name"), #look for the named property from a layer
auto content = jerry_function_external(_shape); auto data = (ExpContent*)malloc(sizeof(ExpContent));
data->obj = exp->layer;
data->frameNo = frameNo;
auto content = jerry_function_external(_content);
jerry_object_set_sz(context, EXP_CONTENT, content); jerry_object_set_sz(context, EXP_CONTENT, content);
jerry_object_set_native_ptr(content, nullptr, exp->layer); jerry_object_set_native_ptr(content, &freeCb, data);
jerry_value_free(content); jerry_value_free(content);
} }
@ -1224,7 +1249,7 @@ LottieExpressions::LottieExpressions()
} }
void LottieExpressions::update(float frameNo, float curTime) void LottieExpressions::update(float curTime)
{ {
//time, #current time in seconds //time, #current time in seconds
auto time = jerry_number(curTime); auto time = jerry_number(curTime);

View file

@ -128,7 +128,7 @@ public:
return success; return success;
} }
void update(float frameNo, float curTime); void update(float curTime);
//singleton (no thread safety) //singleton (no thread safety)
static LottieExpressions* instance(); static LottieExpressions* instance();
@ -160,7 +160,7 @@ struct LottieExpressions
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED RGB24&, TVG_UNUSED LottieExpression*) { return false; } template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED RGB24&, TVG_UNUSED LottieExpression*) { return false; }
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED Fill*, TVG_UNUSED LottieExpression*) { return false; } template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED Fill*, TVG_UNUSED LottieExpression*) { return false; }
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED Array<PathCommand>&, TVG_UNUSED Array<Point>&, TVG_UNUSED Matrix* transform, TVG_UNUSED LottieExpression*) { return false; } template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED Array<PathCommand>&, TVG_UNUSED Array<Point>&, TVG_UNUSED Matrix* transform, TVG_UNUSED LottieExpression*) { return false; }
void update(TVG_UNUSED float, TVG_UNUSED float) {} void update(TVG_UNUSED float) {}
static LottieExpressions* instance() { return nullptr; } static LottieExpressions* instance() { return nullptr; }
static void retrieve(TVG_UNUSED LottieExpressions* instance) {} static void retrieve(TVG_UNUSED LottieExpressions* instance) {}
}; };