Conversation
Contributor
Author
|
Depends on #4 |
bbb7dd7 to
4146937
Compare
added 19 commits
September 12, 2018 14:59
If we know that two points are going to be of the same type, it is convenient to be able to compare them with the == operator as opposed to having to use agd::equals
The "box" type represents a simple perpendicular quadrilateral in 2D space given by its top left and bottom right co-ordinates (eg, x1, y1, x2, y2).
This is necessary in order to use it with some of the testing operators (like agd::Equals or agd::AlmostEq), since those testing operators use operator<< in order to print out the contents of the type in the event of a matching failure.
We're going to do affine transformations and glm is a particularly well respected library for things like that. Note that the dependency is a submodule, so you'll need to fetch and pull submodules before building.
Steppers encapsulate some progress change within the animation. The typical case is linear stepping, which just interpolates from 0 to 1. However, another case is reverse stepping which is composed by 1.0f - linear (ms). Future steppers can be added to add all sorts of easing parameters. https://phabricator.endlessm.com/T23543
Right now we only have 2D vector types, but some consumers like clutter want bounding volumes in a four dimensional space, so we need a type to represent such bounding volumes.
We'll do some affine transformations based on this one.
There's three main methods to override here:
- Step() -> Take a single step in the animation by a given
number of milliseconds. Returns true if more
steps need to be taken, false otherwise
- Matrix() -> Get the transformation matrix for the animated
surface at this point in the animation.
- Extremes() -> Get the four points specifying the 3D bounding
volume for this surface, usually transforming
the co-ordinates of the surface in scene-relative
co-ordinates that have been passed in.
We'll use these later for the affine transformation animations to calculate box offsets. Usually we want to compute where the center of a box is in both absolute co-ordinates and relative co-ordinates. ComputeBoxCenter will do it in absolute co-ordinates and ComputeBoxCenterOffset in co-ordinates relative to the top left corner of the box.
We'll use these later when implementing linear progress based animations. Right now we only have clamp(), used to ensure that the given value sits between some bounds.
These are just some simple macros to define ABI safe property
get/set functions. They are accessed by calling the correct overload,
for instance, to set properties:
animation.Target(target).Source(source)
And to get properties:
auto const &target = animation.Target();
These helpers are used to quickly append a new "interface"
construction prop to the existing construction properties
and make it easy to lookup the props inline.
Basically, we need these helpers because we are wrapping some
C++ interface implementation in a GObject. GObject doesn't require
all the properties to be set at construction time, whereas
constructing the C++ interface implementation does. So we need to
collect all the properties in the constructor and then construct
the underlying C++ interface there.
Doing this by looking over all the construct properties and assigning
values would be cumbersome, especially doing it for every effect
implementation. Instead, we put all the construct properties into
a hash table (hashed by the property name) and then fetch them in
O(1) using the InterfaceConstructor template.
This template constructs the "Interface" type (the type passed
should be the implementation of the interface you want to construct)
and variadically takes in all the construction parameters. Use
ForwardValueFromHT to extract a typed value from the given property name
from its corresponding GValue in the construct properties hash table. For
instance, supposing that MyType's constructor is defined as follows:
MyType::MyType (float bar,
animation::Point const &baz)
{
...
}
You would use the following in the constructor override for the GObject
wrapper:
const char *interesting_props = {
"bar",
"baz",
NULL
};
g_autoptr(GHashTable) props_ht =
static_hash_table_of_values_for_specs (interesting_props,
construct_params,
n_construct_params);
auto *interface = InterfaceConstructor <MyType>::construct (
ForwardValueFromHT (props_ht, g_value_get_float, "bar"),
ForwardValueFromHT (props_ht, animation_point_from_gvalue, "baz")
);
g_auto(GValue) interface_value = G_VALUE_INIT;
unsigned int new_n_construct_params = 0;
GObjectConstructParam *new_construct_params =
append_interface_prop_to_construct_params (construct_params,
n_construct_params,
object_class,
&interface_value,
interface,
&new_n_construct_params);
object_class->constructor (type,
new_construct_params,
new_n_construct_params);
This will be useful for printing out the contents of matrices when tests fail. Also necessary if we want to use comparison matchers with them.
This matcher allows the verify that one type instance is "almost equal" to another type instance. The way that is done is that the type must implement the animation::matcher::AlmostEqTrait type trait and define the apply() method.
This is a simple affine transformation that goes from one box to another. The animation runs "from" some source point "to" some target point which is the surface' "natural" position within the scene (eg, if there were a scene graph, the "to" position forms its co-ordinates and its geometry). For instance, if the window was minimizing, then the animation would have to be run in reverse, "from" the minimized point "to" the unminimized point, but stepping backwards.
This animation simulates a gentle bounce on a sine wave from the center of the window outwards. The best way to think of this animation is to think of an attenuating sine wave squeezed inwards by two bounds that converge on a single point. In thise case those lines are running from the "initialScale" to 1.0 and the "maximumScale" down to 1.0. We run the sine wave for 2pi * nBounce iterations (scaling it it to fit within the time range), but the effect of the naimation is scaled according to where we are on the bunds. Now, rotate the attenuating sine wave so that it is facing towards you on the z-axis (OpenGL co-ordinates). This is essentially what the animation is.
This animation rotates the surface from some rotated position towards a resting position where its rotation angle is 0, 0, 0 on all three axes. The axis that the surface can rotate on is configurable in unit-cordinates. Rotation on 0.5, 0.5 rotates at the center of the surface, whereas rotating from 0, 0 would rotate from the top left corner.
The GridAnimation interface represents transformations that are done
on a grid of vertices that a surface is subdivided into. The
transformation can be any arbitrary function. Implementations must
override three functions:
- Step() -> Take a single step on the function according to the
number of milliseconds passed. If more steps are needed
to complete the animation, return true, otherwise return
false.
- DeformUVToModelSpace() - Given some co-ordinates between (0, 0) and
(1, 1), deform the co-ordinates into model
space, that is the space in the scene of
the surface as if the function were applied.
- Extremes() - Get the geometry of a 2D bounding plane totally encompassing
the deformed surface.
This animation simulates the "genie" effect on another popular operating system, appearing to "suck" the window into a destination rectangle. The way it works is a little complicated. Basically, we subdivide the surface into a very high resolution grid and from each point in the source geometry to each point in the target geometry, we we have a sigmoid function (S-curve, eg e^x / (1 + ke^px) that each grid point travels down towards its destination. When deforming a UV into the pre-computed grid we must do a linear interpolation along both axes, finding the nearest subdivision source point on a UV mesh, then interpolating into that mesh component on the scene-relative internal mesh. https://phabricator.endlessm.com/T23697
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a GridAnimation template and helper functions, used to animation surfaces by deforming equally spaced vertices on a texture.
The MagicLampAnimation reimplements the "magic lamp" effect from Compiz.
https://phabricator.endlessm.com/T23697