-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PropertyAnimation #51
Conversation
1fb501c
to
5896210
Compare
rwatch/ui/animation/animation.c
Outdated
@@ -60,9 +63,14 @@ void _animation_update(Animation *anim) | |||
if (progress > anim->duration) { | |||
/* Ok, we're done. */ | |||
if (anim->impl.update) | |||
anim->impl.update(anim, ANIMATION_NORMALIZED_MAX); | |||
//anim->impl.update(anim, ANIMATION_NORMALIZED_MAX); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems incorrect.
rwatch/ui/animation/animation.c
Outdated
if (anim->impl.teardown) | ||
anim->impl.teardown(anim); | ||
|
||
// Free the prop anim | ||
if (anim->property_anim) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I wonder if it's possible to have animation
itself not depend on property_animation
. I think that, for instance, this property_animation_destroy
could be part of an AnimationImplementation
's teardown
routine -- and similarly, the update
routine, the same. In particular, I'm kind of thinking that an AnimationImplementation
should contain an Animation
-- not the other way around?
new_rect.origin.y = from->origin.y + (((to->origin.y - from->origin.y) / 100.0)*progress); | ||
if (property_animation->impl.accessors.setter.gpoint) | ||
property_animation->impl.accessors.setter.gpoint(layer, new_rect.origin); | ||
//layer_set_frame(layer, new_rect); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove comment
GRect *from = &property_animation->values.from.grect; | ||
GRect *to = &property_animation->values.to.grect; | ||
|
||
GRect new_rect = GRect(from->origin.x + (((to->origin.x - from->origin.x) / 100.0)*progress), from->origin.y + (((to->origin.y - from->origin.y) / 100.0)*progress), from->size.w + (((to->size.w - from->size.w) / 100.0)*progress), from->size.h + (((to->size.h - from->size.h) / 100.0)*progress)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to multiply through by progress first, then divide by 100. Floating point arithmetic is very expensive. i.e., (to->origin.x - from->origin.x) * progress / 100
. Or, better, to just integrate the progress
change there: (to->origin.x - from->origin.x) * distance_normalized / ANIMATION_NORMALIZED_MAX
(which works, because we know that x * ANIMATION_NORMALIZED_MAX
will not be larger than a uint32_t
.)
One way that I did made this easier in Dali Pebble was to define a linear-interpolation macro, along the lines of:
#define LERP(a, b) ((a) + ((b) - (a)) * distance_normalized / ANIMATION_NORMALIZED_MAX)
Which can then be used later as: GRect(LERP(from->origin.x, to->origin.x), LERP(from->origin.y, to->origin.y) ...)
.
GRect *to = &property_animation->values.to.grect; | ||
|
||
GRect new_rect = *from; | ||
new_rect.origin.x = from->origin.x + (((to->origin.x - from->origin.x) / 100.0)*progress); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar in this case -- avoid floating point arith, by doing your interpolation as fixed point.
new_gcolor.g = from->g + (((to->g - from->g) / 100.0)*progress); | ||
new_gcolor.b = from->b + (((to->g - from->b) / 100.0)*progress); | ||
new_gcolor.a = from->a + (((to->a - from->a) / 100.0)*progress); | ||
if (property_animation->impl.accessors.setter.gcolor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing of note -- perhaps we can save all of this computation entirely by returning early if the setter
is null?
property_animation->impl.accessors.setter.uint32(uint32, (int)(((to - from) / 100.0)*progress)); | ||
} | ||
|
||
void property_animation_update_gcolor8(PropertyAnimation * property_animation, const uint32_t distance_normalized) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
local functions can be static
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh I didn't realize this is an API function, ignore that
property_animation->subject = subject; | ||
|
||
// Check the type of the values | ||
if (((GRect *) from_value)->size.w != NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can just store pointers to from_value and to_value, rather than having to guess the type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They'll probably be destroyed when the function the animation is created in returns (maybe I'm thinking of that wrong). It depends on how the developer wrote their part.
rwatch/ui/layer/scroll_layer.c
Outdated
@@ -29,6 +29,8 @@ ScrollLayer *scroll_layer_create(GRect frame) | |||
return slayer; | |||
} | |||
|
|||
PropertyAnimation *prop_anim; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er, hmm. This should presumably be a property of the ScrollLayer structure, right?
Looks really good. I left a handful of relatively small comments that I anticipate you should be able to address readily. Thanks! |
16a5301
to
639cc83
Compare
(and use it in the scroll_layer)
d347ed8
to
c0dfbe5
Compare
Okay I made your changes. Should be good to go. |
|
||
void property_animation_update_grect(PropertyAnimation * property_animation, const uint32_t distance_normalized) | ||
{ | ||
if (property_animation->impl.accessors.getter.grect != NULL && property_animation->impl.accessors.setter.grect != NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(informational; I'll merge anyway)
Better to invert the sense of this:
if (blah == NULL || blah2 == NULL)
return;
everything else...
Or perhaps:
if (!blah || !blah2)
return;
everything else...
#include "appmanager.h" | ||
|
||
// Use to easily calculate changes | ||
#define LERP(a, b) ((a) + ((b) - (a)) * distance_normalized / ANIMATION_NORMALIZED_MAX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(informational; I'll merge anyway)
Would be better not to expose this symbol in the global namespace (other people may want a LERP
define of their own). Better to have this only inside the .c
file.
Overall looks very clean. Good work! |
Add the
PropertyAnimation
(convenience). I added it to thescroll_layer
as an example implementation. I plan to go through and animate a lot of things.Also made
animation_destroy
actually free the animation.