mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
api: revised the animation segment specification
Changed the unit of the segment from a normalized value to frame numbers, ensuring alignment with other frame control interfaces. Note that This change may break backward compatibility. issue: https://github.com/thorvg/thorvg/issues/3116
This commit is contained in:
parent
53487421b5
commit
fdd760a34f
9 changed files with 69 additions and 60 deletions
|
@ -48,32 +48,32 @@ struct UserExample : tvgexam::Example
|
||||||
|
|
||||||
//pad1 touch?
|
//pad1 touch?
|
||||||
if (auto paint = picture->paint(tvg::Accessor::id("pad1"))) {
|
if (auto paint = picture->paint(tvg::Accessor::id("pad1"))) {
|
||||||
if (hitting(paint, x, y, 0.2222f, 0.3333f)) return true;
|
if (hitting(paint, x, y, 20.0f, 30.0f)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pad3 touch?
|
//pad3 touch?
|
||||||
if (auto paint = picture->paint(tvg::Accessor::id("pad3"))) {
|
if (auto paint = picture->paint(tvg::Accessor::id("pad3"))) {
|
||||||
if (hitting(paint, x, y, 0.4444f, 0.5555f)) return true;
|
if (hitting(paint, x, y, 40.0f, 50.0f)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pad5 touch?
|
//pad5 touch?
|
||||||
if (auto paint = picture->paint(tvg::Accessor::id("pad5"))) {
|
if (auto paint = picture->paint(tvg::Accessor::id("pad5"))) {
|
||||||
if (hitting(paint, x, y, 0.1111f, 0.2222f)) return true;
|
if (hitting(paint, x, y, 10.0f, 20.0f)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pad7 touch?
|
//pad7 touch?
|
||||||
if (auto paint = picture->paint(tvg::Accessor::id("pad7"))) {
|
if (auto paint = picture->paint(tvg::Accessor::id("pad7"))) {
|
||||||
if (hitting(paint, x, y, 0.0000f, 0.1111f)) return true;
|
if (hitting(paint, x, y, 0.0f, 10.0f)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pad9 touch?
|
//pad9 touch?
|
||||||
if (auto paint = picture->paint(tvg::Accessor::id("pad9"))) {
|
if (auto paint = picture->paint(tvg::Accessor::id("pad9"))) {
|
||||||
if (hitting(paint, x, y, 0.3333f, 0.4444f)) return true;
|
if (hitting(paint, x, y, 30.0f, 40.0f)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//bar touch?
|
//bar touch?
|
||||||
if (auto paint = picture->paint(tvg::Accessor::id("bar"))) {
|
if (auto paint = picture->paint(tvg::Accessor::id("bar"))) {
|
||||||
if (hitting(paint, x, y, 0.6666f, 1.0f)) return true;
|
if (hitting(paint, x, y, 60.0f, 90.0f)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
30
inc/thorvg.h
30
inc/thorvg.h
|
@ -1891,7 +1891,6 @@ public:
|
||||||
*
|
*
|
||||||
* @since 0.13
|
* @since 0.13
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class TVG_API Animation
|
class TVG_API Animation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -1910,7 +1909,6 @@ public:
|
||||||
* Values less than 0.001 may be disregarded and may not be accurately retained by the Animation.
|
* Values less than 0.001 may be disregarded and may not be accurately retained by the Animation.
|
||||||
*
|
*
|
||||||
* @see totalFrame()
|
* @see totalFrame()
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
Result frame(float no) noexcept;
|
Result frame(float no) noexcept;
|
||||||
|
|
||||||
|
@ -1924,7 +1922,6 @@ public:
|
||||||
* @return A picture instance that is tied to this animation.
|
* @return A picture instance that is tied to this animation.
|
||||||
*
|
*
|
||||||
* @warning The picture instance is owned by Animation. It should not be deleted manually.
|
* @warning The picture instance is owned by Animation. It should not be deleted manually.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
Picture* picture() const noexcept;
|
Picture* picture() const noexcept;
|
||||||
|
|
||||||
|
@ -1935,9 +1932,8 @@ public:
|
||||||
*
|
*
|
||||||
* @note If the Picture is not properly configured, this function will return 0.
|
* @note If the Picture is not properly configured, this function will return 0.
|
||||||
*
|
*
|
||||||
* @see Animation::frame(float no)
|
* @see Animation::frame()
|
||||||
* @see Animation::totalFrame()
|
* @see Animation::totalFrame()
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
float curFrame() const noexcept;
|
float curFrame() const noexcept;
|
||||||
|
|
||||||
|
@ -1948,7 +1944,6 @@ public:
|
||||||
*
|
*
|
||||||
* @note Frame numbering starts from 0.
|
* @note Frame numbering starts from 0.
|
||||||
* @note If the Picture is not properly configured, this function will return 0.
|
* @note If the Picture is not properly configured, this function will return 0.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
float totalFrame() const noexcept;
|
float totalFrame() const noexcept;
|
||||||
|
|
||||||
|
@ -1958,7 +1953,6 @@ public:
|
||||||
* @return The duration of the animation in seconds.
|
* @return The duration of the animation in seconds.
|
||||||
*
|
*
|
||||||
* @note If the Picture is not properly configured, this function will return 0.
|
* @note If the Picture is not properly configured, this function will return 0.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
float duration() const noexcept;
|
float duration() const noexcept;
|
||||||
|
|
||||||
|
@ -1970,30 +1964,33 @@ public:
|
||||||
* After setting, the number of animation frames and the playback time are calculated
|
* After setting, the number of animation frames and the playback time are calculated
|
||||||
* by mapping the playback segment as the entire range.
|
* by mapping the playback segment as the entire range.
|
||||||
*
|
*
|
||||||
* @param[in] begin segment start.
|
* @param[in] begin segment begin frame.
|
||||||
* @param[in] end segment end.
|
* @param[in] end segment end frame.
|
||||||
*
|
*
|
||||||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||||
|
* @retval Result::InvalidArguments If the @p begin is higher than @p end.
|
||||||
* @retval Result::NonSupport When it's not animatable.
|
* @retval Result::NonSupport When it's not animatable.
|
||||||
*
|
*
|
||||||
* @note Animation allows a range from 0.0 to 1.0. @p end should not be higher than @p begin.
|
* @note Animation allows a range from 0.0 to the total frame. @p end should not be higher than @p begin.
|
||||||
* @note If a marker has been specified, its range will be disregarded.
|
* @note If a marker has been specified, its range will be disregarded.
|
||||||
* @see LottieAnimation::segment(const char* marker)
|
|
||||||
*
|
*
|
||||||
* @note Experimental API
|
* @see LottieAnimation::segment(const char* marker)
|
||||||
|
* @see Animation::totalFrame()
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
Result segment(float begin, float end) noexcept;
|
Result segment(float begin, float end) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the current segment.
|
* @brief Gets the current segment range information.
|
||||||
*
|
*
|
||||||
* @param[out] begin segment start.
|
* @param[out] begin segment begin frame.
|
||||||
* @param[out] end segment end.
|
* @param[out] end segment end frame.
|
||||||
*
|
*
|
||||||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||||
* @retval Result::NonSupport When it's not animatable.
|
* @retval Result::NonSupport When it's not animatable.
|
||||||
*
|
*
|
||||||
* @note Experimental API
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
Result segment(float* begin, float* end = nullptr) noexcept;
|
Result segment(float* begin, float* end = nullptr) noexcept;
|
||||||
|
|
||||||
|
@ -2001,7 +1998,6 @@ public:
|
||||||
* @brief Creates a new Animation object.
|
* @brief Creates a new Animation object.
|
||||||
*
|
*
|
||||||
* @return A new Animation object.
|
* @return A new Animation object.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static Animation* gen() noexcept;
|
static Animation* gen() noexcept;
|
||||||
|
|
||||||
|
|
|
@ -2373,31 +2373,42 @@ TVG_API Tvg_Result tvg_animation_get_duration(Tvg_Animation* animation, float* d
|
||||||
/*!
|
/*!
|
||||||
* @brief Specifies the playback segment of the animation.
|
* @brief Specifies the playback segment of the animation.
|
||||||
*
|
*
|
||||||
|
* The set segment is designated as the play area of the animation.
|
||||||
|
* This is useful for playing a specific segment within the entire animation.
|
||||||
|
* After setting, the number of animation frames and the playback time are calculated
|
||||||
|
* by mapping the playback segment as the entire range.
|
||||||
|
*
|
||||||
* @param[in] animation The Tvg_Animation pointer to the animation object.
|
* @param[in] animation The Tvg_Animation pointer to the animation object.
|
||||||
* @param[in] begin segment begin.
|
* @param[in] begin segment begin frame.
|
||||||
* @param[in] end segment end.
|
* @param[in] end segment end frame.
|
||||||
*
|
*
|
||||||
* @return Tvg_Result enumeration.
|
* @return Tvg_Result enumeration.
|
||||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION In case the animation is not loaded.
|
* @retval TVG_RESULT_INSUFFICIENT_CONDITION In case the animation is not loaded.
|
||||||
* @retval TVG_RESULT_INVALID_ARGUMENT When the given parameters are out of range.
|
* @retval TVG_RESULT_INVALID_ARGUMENT If the @p begin is higher than @p end.
|
||||||
*
|
*
|
||||||
* @note Experimental API
|
* @note Animation allows a range from 0.0 to the total frame. @p end should not be higher than @p begin.
|
||||||
|
* @note If a marker has been specified, its range will be disregarded.
|
||||||
|
*
|
||||||
|
* @see tvg_lottie_animation_set_marker()
|
||||||
|
* @see tvg_animation_get_total_frame()
|
||||||
|
|
||||||
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
TVG_API Tvg_Result tvg_animation_set_segment(Tvg_Animation* animation, float begin, float end);
|
TVG_API Tvg_Result tvg_animation_set_segment(Tvg_Animation* animation, float begin, float end);
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Gets the current segment.
|
* @brief Gets the current segment range information.
|
||||||
*
|
*
|
||||||
* @param[in] animation The Tvg_Animation pointer to the animation object.
|
* @param[in] animation The Tvg_Animation pointer to the animation object.
|
||||||
* @param[out] begin segment begin.
|
* @param[out] begin segment begin frame.
|
||||||
* @param[out] end segment end.
|
* @param[out] end segment end frame.
|
||||||
*
|
*
|
||||||
* @return Tvg_Result enumeration.
|
* @return Tvg_Result enumeration.
|
||||||
* @retval TVG_RESULT_INSUFFICIENT_CONDITION In case the animation is not loaded.
|
* @retval TVG_RESULT_INSUFFICIENT_CONDITION In case the animation is not loaded.
|
||||||
* @retval TVG_RESULT_INVALID_ARGUMENT When the given parameters are @c nullptr.
|
* @retval TVG_RESULT_INVALID_ARGUMENT An invalid Tvg_Animation pointer.
|
||||||
*
|
*
|
||||||
* @note Experimental API
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
TVG_API Tvg_Result tvg_animation_get_segment(Tvg_Animation* animation, float* begin, float* end);
|
TVG_API Tvg_Result tvg_animation_get_segment(Tvg_Animation* animation, float* begin, float* end);
|
||||||
|
|
||||||
|
|
|
@ -47,14 +47,14 @@ Result LottieAnimation::segment(const char* marker) noexcept
|
||||||
if (!loader) return Result::InsufficientCondition;
|
if (!loader) return Result::InsufficientCondition;
|
||||||
|
|
||||||
if (!marker) {
|
if (!marker) {
|
||||||
static_cast<FrameModule*>(loader)->segment(0.0f, 1.0f);
|
static_cast<LottieLoader*>(loader)->segment(0.0f, FLT_MAX);
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
float begin, end;
|
float begin, end;
|
||||||
if (!static_cast<LottieLoader*>(loader)->segment(marker, begin, end)) return Result::InvalidArguments;
|
if (!static_cast<LottieLoader*>(loader)->segment(marker, begin, end)) return Result::InvalidArguments;
|
||||||
|
|
||||||
return static_cast<Animation*>(this)->segment(begin, end);
|
return static_cast<LottieLoader*>(loader)->segment(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -97,8 +97,7 @@ bool LottieLoader::header()
|
||||||
if (comp) {
|
if (comp) {
|
||||||
w = static_cast<float>(comp->w);
|
w = static_cast<float>(comp->w);
|
||||||
h = static_cast<float>(comp->h);
|
h = static_cast<float>(comp->h);
|
||||||
frameDuration = comp->duration();
|
segmentEnd = frameCnt = comp->frameCnt();
|
||||||
frameCnt = comp->frameCnt();
|
|
||||||
frameRate = comp->frameRate;
|
frameRate = comp->frameRate;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -190,10 +189,9 @@ bool LottieLoader::header()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
frameCnt = (endFrame - startFrame);
|
segmentEnd = frameCnt = (endFrame - startFrame);
|
||||||
frameDuration = frameCnt / frameRate;
|
|
||||||
|
|
||||||
TVGLOG("LOTTIE", "info: frame rate = %f, duration = %f size = %f x %f", frameRate, frameDuration, w, h);
|
TVGLOG("LOTTIE", "info: frame rate = %f, duration = %f size = %f x %f", frameRate, frameCnt / frameRate, w, h);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -355,13 +353,13 @@ bool LottieLoader::frame(float no)
|
||||||
|
|
||||||
float LottieLoader::startFrame()
|
float LottieLoader::startFrame()
|
||||||
{
|
{
|
||||||
return frameCnt * segmentBegin;
|
return segmentBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float LottieLoader::totalFrame()
|
float LottieLoader::totalFrame()
|
||||||
{
|
{
|
||||||
return (segmentEnd - segmentBegin) * frameCnt;
|
return segmentEnd - segmentBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -373,8 +371,7 @@ float LottieLoader::curFrame()
|
||||||
|
|
||||||
float LottieLoader::duration()
|
float LottieLoader::duration()
|
||||||
{
|
{
|
||||||
if (segmentBegin == 0.0f && segmentEnd == 1.0f) return frameDuration;
|
return (segmentEnd - segmentBegin) / frameRate;
|
||||||
return frameCnt * (segmentEnd - segmentBegin) / frameRate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -400,14 +397,28 @@ const char* LottieLoader::markers(uint32_t index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Result LottieLoader::segment(float begin, float end)
|
||||||
|
{
|
||||||
|
if (begin < 0.0f) begin = 0.0f;
|
||||||
|
if (end > frameCnt) end = frameCnt;
|
||||||
|
|
||||||
|
if (begin > end) return Result::InvalidArguments;
|
||||||
|
|
||||||
|
segmentBegin = begin;
|
||||||
|
segmentEnd = end;
|
||||||
|
|
||||||
|
return Result::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LottieLoader::segment(const char* marker, float& begin, float& end)
|
bool LottieLoader::segment(const char* marker, float& begin, float& end)
|
||||||
{
|
{
|
||||||
if (!ready() || comp->markers.count == 0) return false;
|
if (!ready() || comp->markers.count == 0) return false;
|
||||||
|
|
||||||
ARRAY_FOREACH(p, comp->markers) {
|
ARRAY_FOREACH(p, comp->markers) {
|
||||||
if (!strcmp(marker, (*p)->name)) {
|
if (!strcmp(marker, (*p)->name)) {
|
||||||
begin = (*p)->time / frameCnt;
|
begin = (*p)->time;
|
||||||
end = ((*p)->time + (*p)->duration) / frameCnt;
|
end = (*p)->time + (*p)->duration;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ public:
|
||||||
uint32_t size = 0; //lottie data size
|
uint32_t size = 0; //lottie data size
|
||||||
float frameNo = 0.0f; //current frame number
|
float frameNo = 0.0f; //current frame number
|
||||||
float frameCnt = 0.0f;
|
float frameCnt = 0.0f;
|
||||||
float frameDuration = 0.0f;
|
|
||||||
float frameRate = 0.0f;
|
float frameRate = 0.0f;
|
||||||
|
|
||||||
LottieBuilder* builder;
|
LottieBuilder* builder;
|
||||||
|
@ -70,6 +69,7 @@ public:
|
||||||
uint32_t markersCnt();
|
uint32_t markersCnt();
|
||||||
const char* markers(uint32_t index);
|
const char* markers(uint32_t index);
|
||||||
bool segment(const char* marker, float& begin, float& end);
|
bool segment(const char* marker, float& begin, float& end);
|
||||||
|
Result segment(float begin, float end) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ready();
|
bool ready();
|
||||||
|
|
|
@ -88,15 +88,11 @@ float Animation::duration() const noexcept
|
||||||
|
|
||||||
Result Animation::segment(float begin, float end) noexcept
|
Result Animation::segment(float begin, float end) noexcept
|
||||||
{
|
{
|
||||||
if (begin < 0.0f || end > 1.0f || begin > end) return Result::InvalidArguments;
|
|
||||||
|
|
||||||
auto loader = PICTURE(pImpl->picture)->loader;
|
auto loader = PICTURE(pImpl->picture)->loader;
|
||||||
if (!loader) return Result::InsufficientCondition;
|
if (!loader) return Result::InsufficientCondition;
|
||||||
if (!loader->animatable()) return Result::NonSupport;
|
if (!loader->animatable()) return Result::NonSupport;
|
||||||
|
|
||||||
static_cast<FrameModule*>(loader)->segment(begin, end);
|
return static_cast<FrameModule*>(loader)->segment(begin, end);
|
||||||
|
|
||||||
return Result::Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ class FrameModule: public ImageLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
float segmentBegin = 0.0f;
|
float segmentBegin = 0.0f;
|
||||||
float segmentEnd = 1.0f;
|
float segmentEnd; //Initialize the value with the total frame number
|
||||||
|
|
||||||
FrameModule(FileType type) : ImageLoader(type) {}
|
FrameModule(FileType type) : ImageLoader(type) {}
|
||||||
virtual ~FrameModule() {}
|
virtual ~FrameModule() {}
|
||||||
|
@ -41,6 +41,7 @@ public:
|
||||||
virtual float totalFrame() = 0; //return the total frame count
|
virtual float totalFrame() = 0; //return the total frame count
|
||||||
virtual float curFrame() = 0; //return the current frame number
|
virtual float curFrame() = 0; //return the current frame number
|
||||||
virtual float duration() = 0; //return the animation duration in seconds
|
virtual float duration() = 0; //return the animation duration in seconds
|
||||||
|
virtual Result segment(float begin, float end) = 0;
|
||||||
|
|
||||||
void segment(float* begin, float* end)
|
void segment(float* begin, float* end)
|
||||||
{
|
{
|
||||||
|
@ -48,12 +49,6 @@ public:
|
||||||
if (end) *end = segmentEnd;
|
if (end) *end = segmentEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void segment(float begin, float end)
|
|
||||||
{
|
|
||||||
segmentBegin = begin;
|
|
||||||
segmentEnd = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool animatable() override { return true; }
|
virtual bool animatable() override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -301,7 +301,7 @@ TEST_CASE("Animation Segment", "[tvgAnimation]")
|
||||||
//Get current segment before segment
|
//Get current segment before segment
|
||||||
REQUIRE(animation->segment(&begin, &end) == Result::Success);
|
REQUIRE(animation->segment(&begin, &end) == Result::Success);
|
||||||
REQUIRE(begin == 0.0f);
|
REQUIRE(begin == 0.0f);
|
||||||
REQUIRE(end == 1.0f);
|
REQUIRE(end == animation->totalFrame());
|
||||||
|
|
||||||
//Segment by range
|
//Segment by range
|
||||||
REQUIRE(animation->segment(0.25, 0.5) == Result::Success);
|
REQUIRE(animation->segment(0.25, 0.5) == Result::Success);
|
||||||
|
@ -320,7 +320,7 @@ TEST_CASE("Animation Segment", "[tvgAnimation]")
|
||||||
REQUIRE(end == 0.5f);
|
REQUIRE(end == 0.5f);
|
||||||
|
|
||||||
//Segment by invalid range
|
//Segment by invalid range
|
||||||
REQUIRE(animation->segment(-0.5, 1.5) == Result::InvalidArguments);
|
REQUIRE(animation->segment(1.5, -0.5) == Result::InvalidArguments);
|
||||||
|
|
||||||
REQUIRE(Initializer::term() == Result::Success);
|
REQUIRE(Initializer::term() == Result::Success);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue