diff --git a/.gitmodules b/.gitmodules index e69de29..018c244 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "animation/third_party/glm"] + path = animation/third_party/glm + url = git://github.com/g-truc/glm diff --git a/animation-glib/bounce/bounce.cpp b/animation-glib/bounce/bounce.cpp new file mode 100644 index 0000000..72e06d1 --- /dev/null +++ b/animation-glib/bounce/bounce.cpp @@ -0,0 +1,349 @@ +/* + * animation-glib/bounce/bounce.cpp + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject implementation for a "bounce" animation. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace agd = animation::geometry::dimension; +namespace ab = animation::bounce; +namespace as = animation::stepper; +namespace at = animation::transform; + +struct _AnimationBounceAnimation +{ + AnimationTransformAnimation parent_instance; +}; + +typedef struct _AnimationBounceAnimationPrivate +{ +} AnimationBounceAnimationPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AnimationBounceAnimation, + animation_bounce_animation, + ANIMATION_TYPE_TRANSFORM_ANIMATION) + +enum { + PROP_0, + PROP_INITIAL_SCALE, + PROP_MAXIMUM_SCALE, + PROP_N_BOUNCE, + PROP_TARGET, + PROP_STEPPER, + NPROPS +}; + +static GParamSpec *animation_bounce_animation_props [NPROPS] = { NULL, }; + +float +animation_bounce_animation_get_initial_scale (AnimationBounceAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->InitialScale (); +} + +void +animation_bounce_animation_set_initial_scale (AnimationBounceAnimation *animation, + float initial_scale) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->InitialScale (initial_scale); +} + +float +animation_bounce_animation_get_maximum_scale (AnimationBounceAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->MaximumScale (); +} + +void +animation_bounce_animation_set_maximum_scale (AnimationBounceAnimation *animation, + float maximum_scale) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->MaximumScale (maximum_scale); +} + +unsigned int +animation_bounce_animation_get_n_bounce (AnimationBounceAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->NBounce (); +} + +void +animation_bounce_animation_set_n_bounce (AnimationBounceAnimation *animation, + unsigned int n_bounce) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->NBounce (n_bounce); +} + +/** + * animation_bounce_animation_get_target: + * @animation: An #AnimationBounceAnimation + * @out_box: (out caller-allocates): Return location for an #AnimationBox + * + * Get the box representing the animation target. + */ +void +animation_bounce_animation_get_target (AnimationBounceAnimation *animation, + AnimationBox *out_box) +{ + g_return_if_fail (out_box != nullptr); + + animation::Box const &box = + LookupTypedInterfaceProp (G_OBJECT (animation))->Target (); + + out_box->top_left.x = agd::get <0> (box.topLeft ()); + out_box->top_left.y = agd::get <1> (box.topLeft ()); + out_box->bottom_right.x = agd::get <0> (box.bottomRight ()); + out_box->bottom_right.y = agd::get <1> (box.bottomRight ()); +} + +void +animation_bounce_animation_set_stepper (AnimationBounceAnimation *animation, + AnimationStepper *stepper) +{ + animation::stepper::Stepper *stepper_ptr = nullptr; + g_object_get (stepper, "stepper", (gpointer) &stepper_ptr, NULL); + + LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper (*stepper_ptr); +} + +/** + * animation_bounce_animation_get_stepper: + * @animation: An #AnimationBounceAnimation + * + * Returns: (transfer full): Get the stepper for this #AnimationBounceAnimation + */ +AnimationStepper * +animation_bounce_animation_get_stepper (AnimationBounceAnimation *animation) +{ + auto const &stepper (LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper ()); + + return animation_stepper_wrapper_new ((gpointer) &stepper); +} + +static void +animation_bounce_animation_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_INITIAL_SCALE: + animation_bounce_animation_set_initial_scale (ANIMATION_BOUNCE_ANIMATION (object), + g_value_get_float (value)); + break; + case PROP_MAXIMUM_SCALE: + animation_bounce_animation_set_maximum_scale (ANIMATION_BOUNCE_ANIMATION (object), + g_value_get_float (value)); + break; + case PROP_N_BOUNCE: + animation_bounce_animation_set_n_bounce (ANIMATION_BOUNCE_ANIMATION (object), + g_value_get_uint (value)); + break; + case PROP_TARGET: + /* No-op here to handle the constructor */ + break; + case PROP_STEPPER: + animation_bounce_animation_set_stepper (ANIMATION_BOUNCE_ANIMATION (object), + ANIMATION_STEPPER (g_value_get_object (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_bounce_animation_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AnimationBounceAnimation *bounce_animation = ANIMATION_BOUNCE_ANIMATION (object); + + switch (prop_id) + { + case PROP_INITIAL_SCALE: + g_value_set_float (value, animation_bounce_animation_get_initial_scale (bounce_animation)); + break; + case PROP_MAXIMUM_SCALE: + g_value_set_float (value, animation_bounce_animation_get_maximum_scale (bounce_animation)); + break; + case PROP_N_BOUNCE: + g_value_set_uint (value, animation_bounce_animation_get_n_bounce (bounce_animation)); + break; + case PROP_TARGET: + { + AnimationBox target; + animation_bounce_animation_get_target (bounce_animation, &target); + + g_value_set_boxed (value, &target); + break; + } + case PROP_STEPPER: + g_value_take_object (value, animation_bounce_animation_get_stepper (bounce_animation)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static GObject * +animation_bounce_animation_constructor (GType type, + unsigned int n_construct_params, + GObjectConstructParam *construct_params) +{ + replace_named_pointer_prop_in_construct_params_if_null (construct_params, + n_construct_params, + "stepper", + g_value_get_object, + g_value_set_object, + []() -> gpointer { + return animation_linear_stepper_new (300); + }); + + const char * const wanted_properties[] = { + "initial-scale", + "maximum-scale", + "n-bounce", + "target", + "stepper", + NULL + }; + g_autoptr(GHashTable) properties_table = + static_hash_table_of_values_for_specs (wanted_properties, + construct_params, + n_construct_params); + + auto *interface = + static_cast (InterfaceConstructor ::construct ( + ForwardFromValueHT (properties_table, g_value_get_float, "initial-scale"), + ForwardFromValueHT (properties_table, g_value_get_float, "maximum-scale"), + ForwardFromValueHT (properties_table, g_value_get_uint, "n-bounce"), + ForwardFromValueHT (properties_table, animation_box_from_gvalue, "target"), + ForwardFromValueHT (properties_table, animation_stepper_from_gvalue, "stepper") + )); + + replace_interface_prop_in_construct_params (construct_params, + n_construct_params, + g_steal_pointer (&interface)); + + return G_OBJECT_CLASS (animation_bounce_animation_parent_class)->constructor (type, + n_construct_params, + construct_params); +} + +static void +animation_bounce_animation_init (AnimationBounceAnimation *model) +{ +} + + +static void +animation_bounce_animation_class_init (AnimationBounceAnimationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = animation_bounce_animation_constructor; + object_class->get_property = animation_bounce_animation_get_property; + object_class->set_property = animation_bounce_animation_set_property; + + animation_bounce_animation_props[PROP_INITIAL_SCALE] = + g_param_spec_float ("initial-scale", + "Initial Scale", + "The initial scale of the animation", + 0.1f, + 1.0f, + 0.7f, + static_cast (G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + animation_bounce_animation_props[PROP_MAXIMUM_SCALE] = + g_param_spec_float ("maximum-scale", + "Maximum Scale", + "The maximum scale of the animation", + 1.0f, + 3.0f, + 1.2f, + static_cast (G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + animation_bounce_animation_props[PROP_N_BOUNCE] = + g_param_spec_uint ("n-bounce", + "Number of Bounces", + "The number of bounces in the animation", + 1, + 10, + 1, + static_cast (G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + animation_bounce_animation_props[PROP_TARGET] = + g_param_spec_boxed ("target", + "Target Box", + "Box that we are animating to", + ANIMATION_TYPE_BOX, + static_cast (G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + animation_bounce_animation_props[PROP_STEPPER] = + g_param_spec_object ("stepper", + "Stepper", + "Stepper to use to progress the animation", + ANIMATION_TYPE_STEPPER, + static_cast (G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_properties (object_class, + NPROPS, + animation_bounce_animation_props); +} + +/** + * animation_bounce_new: + * @initial_scale: Scale factor that the surface will initially have. + * @maximum_scale: Scale factor that the surface will have at maximum. + * @n_bounce: Number of bounces. + * @target: The #AnimationBox that we are animating to. + * @stepper: The #AnimationStepper of the animation. + * + * Returns: (transfer full): A new #AnimationBounceAnimation. + */ +AnimationBounceAnimation * +animation_bounce_new (float initial_scale, + float maximum_scale, + unsigned int n_bounce, + const AnimationBox *target, + AnimationStepper *stepper) +{ + return ANIMATION_BOUNCE_ANIMATION (g_object_new (ANIMATION_TYPE_BOUNCE_ANIMATION, + "initial-scale", initial_scale, + "maximum-scale", maximum_scale, + "n-bounce", n_bounce, + "target", target, + "stepper", stepper, + NULL)); +} diff --git a/animation-glib/bounce/bounce.h b/animation-glib/bounce/bounce.h new file mode 100644 index 0000000..684f44f --- /dev/null +++ b/animation-glib/bounce/bounce.h @@ -0,0 +1,61 @@ +/* + * animation-glib/bounce/bounce.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject Interface for "bounce" animation. + */ +#pragma once + +#include + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_BOUNCE_ANIMATION animation_bounce_animation_get_type () +G_DECLARE_FINAL_TYPE (AnimationBounceAnimation, animation_bounce_animation, ANIMATION, BOUNCE_ANIMATION, AnimationTransformAnimation) + +float animation_bounce_animation_get_initial_scale (AnimationBounceAnimation *animation); +void animation_bounce_animation_set_initial_scale (AnimationBounceAnimation *animation, + float initial_scale); + +float animation_bounce_animation_get_maximum_scale (AnimationBounceAnimation *animation); +void animation_bounce_animation_set_maximum_scale (AnimationBounceAnimation *animation, + float maximum_scale); + +unsigned int animation_bounce_animation_get_n_bounce (AnimationBounceAnimation *animation); +void animation_bounce_animation_set_n_bounce (AnimationBounceAnimation *animation, + unsigned int n_bounce); + +void animation_bounce_animation_get_target (AnimationBounceAnimation *animation, + AnimationBox *out_box); + +void animation_bounce_animation_set_stepper (AnimationBounceAnimation *animation, + AnimationStepper *stepper); +AnimationStepper * animation_bounce_animation_get_stepper (AnimationBounceAnimation *animation); + +AnimationBounceAnimation * animation_bounce_new (float initial_scale, + float maximum_scale, + unsigned int n_bounce, + const AnimationBox *target, + AnimationStepper *stepper); + +G_END_DECLS + +#pragma once diff --git a/animation-glib/bounce/meson.build b/animation-glib/bounce/meson.build new file mode 100644 index 0000000..0c47361 --- /dev/null +++ b/animation-glib/bounce/meson.build @@ -0,0 +1,18 @@ +# /animation/bounce/meson.build +# +# Build the libanimation library (bounce animation component). +# +# See /LICENCE.md for Copyright information. + +bounce_introspectable_sources = files([ + 'bounce.cpp' +]) + +bounce_headers = files([ + 'bounce.h' +]) + +animation_glib_introspectable_sources += bounce_introspectable_sources +animation_glib_headers += bounce_headers + +install_headers(bounce_headers, subdir: join_paths(animation_headers_subdir, 'bounce')) diff --git a/animation-glib/box.cpp b/animation-glib/box.cpp new file mode 100644 index 0000000..ca21198 --- /dev/null +++ b/animation-glib/box.cpp @@ -0,0 +1,40 @@ +/* + * animation-glib/box.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject Interface for "wobbly" textures, box + * type implementation. + */ + +#include + +static gpointer +animation_box_copy (gpointer ptr) +{ + AnimationBox *src = reinterpret_cast (ptr); + AnimationBox *dst = g_new0 (AnimationBox, 1); + + *dst = *src; + + return reinterpret_cast (dst); +} + +G_DEFINE_BOXED_TYPE (AnimationBox, + animation_box, + animation_box_copy, + g_free) diff --git a/animation-glib/box.h b/animation-glib/box.h new file mode 100644 index 0000000..30b635c --- /dev/null +++ b/animation-glib/box.h @@ -0,0 +1,39 @@ +/* + * animation-glib/box.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject Interface for "wobbly" textures, 2D box type. + */ +#pragma once + +#include + +#include + +G_BEGIN_DECLS + +typedef struct { + AnimationVector top_left; + AnimationVector bottom_right; +} AnimationBox; + +#define ANIMATION_TYPE_BOX animation_box_get_type () + +GType animation_box_get_type (void); + +G_END_DECLS diff --git a/animation-glib/constructor-helpers.cpp b/animation-glib/constructor-helpers.cpp new file mode 100644 index 0000000..41af673 --- /dev/null +++ b/animation-glib/constructor-helpers.cpp @@ -0,0 +1,156 @@ +/* + * animation-glib/constructor-helpers.cpp + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Helpers for constructing C++ objects directly from GObject properties + * in a GObject constructor. + */ + +#include + +#include "constructor-helpers.h" + +GHashTable * +static_hash_table_of_values_for_specs (const char * const *wanted_properties, + GObjectConstructParam *construct_params, + unsigned int n_construct_params) +{ + g_autoptr(GHashTable) ht = g_hash_table_new (g_str_hash, g_str_equal); + + /* Insert all the properties we intend to + * have in the hash table, with NULL as + * their value. */ + for (const char * const *iter = wanted_properties; *iter != NULL; ++iter) + g_hash_table_insert (ht, + (gpointer) (*iter), + NULL); + + /* Now go through all the construct params and insert + * their value pointer into the hash table. */ + for (unsigned int i = 0; i < n_construct_params; ++i) + { + GParamSpec *pspec = construct_params[i].pspec; + GValue *value = construct_params[i].value; + + if (g_hash_table_contains (ht, pspec->name)) + g_hash_table_insert (ht, + (gpointer) pspec->name, + value); + } + + return reinterpret_cast (g_steal_pointer (&ht)); +} + +/** + * replace_construct_param: + * @construct_params: (array length=n_construct_params) An array of #GObjectConstructParam + * @n_construct_params: Number of elements in @construct_params. + * @prop_name: The name of the construct prop to replace the value of. + * @initialize_func: A function which sets the GValue to something sensible. + * + * Replace a construction parameter @prop_name in the + * passed @construct_params by using the passed @initialize_func. + * + * This function must always replace one construct parameter, it is + * an error to pass a @prop_name that is not in the @construct_params. + */ +void +replace_construct_param (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + const char *prop_name, + AnimationConstructorHelpersInitializeValueFunc initialize_func, + gpointer initialize_func_data) +{ + /* The prop should always be found in the array so that we can replace + * it, this function doesn't support appending the prop. That means + * that the relevant prop must always G_PARAM_CONSTRUCT or + * G_PARAM_CONSTRUCT_ONLY. */ + for (unsigned int i = 0; i < n_construct_params; ++i) + { + if (g_strcmp0 (construct_params[i].pspec->name, prop_name) == 0) + { + g_value_unset (construct_params[i].value); + initialize_func (construct_params[i].value, initialize_func_data); + return; + } + } + + g_assert_not_reached (); +} + +template +static typename std::result_of ::type +invoke_function_thunk (Args... args, gpointer lambda) +{ + FunctionType *f = reinterpret_cast (lambda); + + return (*f)(args...); +} + + +void +replace_named_pointer_prop_in_construct_params (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + const char *prop_name, + gpointer ptr) +{ + auto set_value = [ptr](GValue *value) { + g_value_init (value, G_TYPE_POINTER); + g_value_set_pointer (value, ptr); + }; + replace_construct_param (construct_params, + n_construct_params, + prop_name, + (AnimationConstructorHelpersInitializeValueFunc) invoke_function_thunk , + &set_value); +} + +void +replace_interface_prop_in_construct_params (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + gpointer interface) +{ + replace_named_pointer_prop_in_construct_params (construct_params, + n_construct_params, + "interface", + interface); +} + +void +replace_named_pointer_prop_in_construct_params_if_null (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + const char *prop_name, + AnimationConstructorHelpersGValueGetPointerFunc get_func, + AnimationConstructorHelpersGValueSetPointerFunc set_func, + AnimationConstructorHelpersConstructDefaultValueFunc construct_func) +{ + /* The prop should always be found in the array so that we can replace + * it, this function doesn't support appending the prop. That means + * that the relevant prop must always G_PARAM_CONSTRUCT or + * G_PARAM_CONSTRUCT_ONLY. */ + for (unsigned int i = 0; i < n_construct_params; ++i) + { + if (g_strcmp0 (construct_params[i].pspec->name, prop_name) == 0) + { + if (get_func (construct_params[i].value) == nullptr) + set_func (construct_params[i].value, construct_func ()); + + return; + } + } + + g_assert_not_reached (); +} diff --git a/animation-glib/constructor-helpers.h b/animation-glib/constructor-helpers.h new file mode 100644 index 0000000..1c3c72b --- /dev/null +++ b/animation-glib/constructor-helpers.h @@ -0,0 +1,163 @@ +/* + * animation-glib/constructor-helpers.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Helpers for constructing C++ objects directly from GObject properties + * in a GObject constructor. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +inline GValue * +lookup_gvalue (GHashTable *ht, const char *key) +{ + return reinterpret_cast (g_hash_table_lookup (ht, key)); +} + +GHashTable * +static_hash_table_of_values_for_specs (const char * const *wanted_properties, + GObjectConstructParam *construct_params, + unsigned int n_construct_params); + +typedef void (*AnimationConstructorHelpersInitializeValueFunc) (GValue *value, + gpointer user_data); + +void replace_construct_param (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + const char *prop_name, + AnimationConstructorHelpersInitializeValueFunc initialize_func, + gpointer initialize_func_data); + +void replace_named_pointer_prop_in_construct_params (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + const char *prop_name, + gpointer ptr); + +void replace_interface_prop_in_construct_params (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + gpointer interface); + +typedef gpointer (*AnimationConstructorHelpersGValueGetPointerFunc) (const GValue *value); +typedef void (*AnimationConstructorHelpersGValueSetPointerFunc) (GValue *value, gpointer); +typedef gpointer (*AnimationConstructorHelpersConstructDefaultValueFunc) (void); + +void replace_named_pointer_prop_in_construct_params_if_null (GObjectConstructParam *construct_params, + unsigned int n_construct_params, + const char *prop_name, + AnimationConstructorHelpersGValueGetPointerFunc get_func, + AnimationConstructorHelpersGValueSetPointerFunc set_func, + AnimationConstructorHelpersConstructDefaultValueFunc construct_func); + +G_END_DECLS + +#ifdef __cplusplus +inline animation::Box +animation_box_from_gvalue (GValue *value) +{ + AnimationBox *boxed_box = reinterpret_cast (g_value_get_boxed (value)); + + if (boxed_box == nullptr) + return animation::Box (animation::Point (0, 0), + animation::Point (1, 1)); + + return animation::Box (animation::Point (boxed_box->top_left.x, + boxed_box->top_left.y), + animation::Point (boxed_box->bottom_right.x, + boxed_box->bottom_right.y)); +} + +inline animation::Point +animation_point_from_gvalue (GValue *value) +{ + AnimationVector *boxed_point = reinterpret_cast (g_value_get_boxed (value)); + + if (boxed_point == nullptr) + return animation::geometry::PointModel (0, 0); + + return animation::Point (boxed_point->x, boxed_point->y); +} + +inline animation::geometry::PointModel +animation_point_size_t_from_gvalue (GValue *value) +{ + AnimationVector *boxed_point = reinterpret_cast (g_value_get_boxed (value)); + + if (boxed_point == nullptr) + return animation::geometry::PointModel (0, 0); + + return animation::geometry::PointModel (boxed_point->x, boxed_point->y); +} + +inline animation::stepper::Stepper +animation_stepper_from_gvalue (GValue *value) +{ + static const unsigned int DefaultAnimationLength = 300; + + AnimationStepper *stepper = + reinterpret_cast (g_value_get_object (value)); + animation::stepper::Stepper *stepper_ptr = NULL; + + if (stepper != nullptr) + { + g_object_get (G_OBJECT (stepper), "stepper", &stepper_ptr, NULL); + return *stepper_ptr; + } + + return animation::stepper::Linear (DefaultAnimationLength); +} + +template +typename std::result_of ::type ForwardFromValueHT (GHashTable *ht, + Marshaller &&m, + const char *name) +{ + return m (lookup_gvalue (ht, name)); +} + +template +struct InterfaceConstructor +{ + template + static Interface * construct (ArgTypes&&... args) + { + return new Interface (args...); + } +}; + +template +DerivedType * LookupTypedInterfaceProp (GObject *object) +{ + InterfaceType *iface = nullptr; + g_object_get (object, "interface", (gpointer) &iface, NULL); + + return static_cast (iface); +} +#endif diff --git a/animation-glib/glide/glide.cpp b/animation-glib/glide/glide.cpp new file mode 100644 index 0000000..525f959 --- /dev/null +++ b/animation-glib/glide/glide.cpp @@ -0,0 +1,404 @@ +/* + * animation-glib/glide/glide.cpp + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject implementation for a "glide" animation. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace agd = animation::geometry::dimension; +namespace ag = animation::glide; +namespace at = animation::transform; + +struct _AnimationGlideAnimation +{ + AnimationTransformAnimation parent_instance; +}; + +typedef struct _AnimationGlideAnimationPrivate +{ +} AnimationGlideAnimationPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AnimationGlideAnimation, + animation_glide_animation, + ANIMATION_TYPE_TRANSFORM_ANIMATION) + +enum { + PROP_0, + PROP_INITIAL_DISTANCE, + PROP_X_ROTATION_ANGLE_DEGREES, + PROP_Y_ROTATION_ANGLE_DEGREES, + PROP_X_AXIS_LOCATION_UNIT, + PROP_Y_AXIS_LOCATION_UNIT, + PROP_SCREEN_WIDTH, + PROP_TARGET, + PROP_STEPPER, + NPROPS +}; + +static GParamSpec *animation_glide_animation_props [NPROPS] = { NULL, }; + +void +animation_glide_animation_set_initial_distance (AnimationGlideAnimation *animation, + float initial_distance) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->InitialDistance (initial_distance); +} + +float +animation_glide_animation_get_initial_distance (AnimationGlideAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->InitialDistance (); +} + +void +animation_glide_animation_set_x_rotation_angle_degrees (AnimationGlideAnimation *animation, + float x_rotation_angle_degrees) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->XRotationAngleDegrees (x_rotation_angle_degrees); +} + +float +animation_glide_animation_get_x_rotation_angle_degrees (AnimationGlideAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->XRotationAngleDegrees (); +} + +void +animation_glide_animation_set_y_rotation_angle_degrees (AnimationGlideAnimation *animation, + float y_rotation_angle_degrees) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->YRotationAngleDegrees (y_rotation_angle_degrees); +} + +float +animation_glide_animation_get_y_rotation_angle_degrees (AnimationGlideAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->YRotationAngleDegrees (); +} + +void +animation_glide_animation_set_x_axis_location_unit (AnimationGlideAnimation *animation, + float x_axis_location_unit) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->XAxisLocationUnit (x_axis_location_unit); +} + +float +animation_glide_animation_get_x_axis_location_unit (AnimationGlideAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->XAxisLocationUnit (); +} + +void +animation_glide_animation_set_y_axis_location_unit (AnimationGlideAnimation *animation, + float y_axis_location_unit) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->YAxisLocationUnit (y_axis_location_unit); +} + +float +animation_glide_animation_get_y_axis_location_unit (AnimationGlideAnimation *animation) +{ + return LookupTypedInterfaceProp (G_OBJECT (animation))->YAxisLocationUnit (); +} + +void +animation_glide_animation_set_stepper (AnimationGlideAnimation *animation, + AnimationStepper *stepper) +{ + animation::stepper::Stepper *stepper_ptr = nullptr; + g_object_get (stepper, "stepper", (gpointer) &stepper_ptr, NULL); + + LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper (*stepper_ptr); +} + +/** + * animation_glide_animation_get_stepper: + * @animation: An #AnimationGlideAnimation + * + * Returns: (transfer full): Get the stepper for this #AnimationGlideAnimation + */ +AnimationStepper * +animation_glide_animation_get_stepper (AnimationGlideAnimation *animation) +{ + auto const &stepper (LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper ()); + + return animation_stepper_wrapper_new ((gpointer) &stepper); +} + +static void +animation_glide_animation_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + AnimationGlideAnimation *glide_animation = ANIMATION_GLIDE_ANIMATION (object); + + switch (prop_id) + { + case PROP_INITIAL_DISTANCE: + animation_glide_animation_set_initial_distance (glide_animation, g_value_get_float (value)); + break; + case PROP_X_ROTATION_ANGLE_DEGREES: + animation_glide_animation_set_x_rotation_angle_degrees (glide_animation, g_value_get_float (value)); + break; + case PROP_Y_ROTATION_ANGLE_DEGREES: + animation_glide_animation_set_y_rotation_angle_degrees (glide_animation, g_value_get_float (value)); + break; + case PROP_X_AXIS_LOCATION_UNIT: + animation_glide_animation_set_x_axis_location_unit (glide_animation, g_value_get_float (value)); + break; + case PROP_Y_AXIS_LOCATION_UNIT: + animation_glide_animation_set_y_axis_location_unit (glide_animation, g_value_get_float (value)); + break; + case PROP_SCREEN_WIDTH: + /* Not writable, except on construction */ + break; + case PROP_TARGET: + /* Not writable, except on construction */ + break; + case PROP_STEPPER: + animation_glide_animation_set_stepper (glide_animation, + ANIMATION_STEPPER (g_value_get_object (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_glide_animation_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AnimationGlideAnimation *glide_animation = ANIMATION_GLIDE_ANIMATION (object); + + switch (prop_id) + { + case PROP_INITIAL_DISTANCE: + g_value_set_float (value, animation_glide_animation_get_initial_distance (glide_animation)); + break; + case PROP_X_ROTATION_ANGLE_DEGREES: + g_value_set_float (value, animation_glide_animation_get_x_rotation_angle_degrees (glide_animation)); + break; + case PROP_Y_ROTATION_ANGLE_DEGREES: + g_value_set_float (value, animation_glide_animation_get_y_rotation_angle_degrees (glide_animation)); + break; + case PROP_X_AXIS_LOCATION_UNIT: + g_value_set_float (value, animation_glide_animation_get_x_axis_location_unit (glide_animation)); + break; + case PROP_Y_AXIS_LOCATION_UNIT: + g_value_set_float (value, animation_glide_animation_get_y_axis_location_unit (glide_animation)); + break; + case PROP_SCREEN_WIDTH: + /* Not readable */ + break; + case PROP_TARGET: + /* Not readable */ + break; + case PROP_STEPPER: + g_value_take_object (value, animation_glide_animation_get_stepper (glide_animation)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static GObject * +animation_glide_animation_constructor (GType type, + unsigned int n_construct_params, + GObjectConstructParam *construct_params) +{ + replace_named_pointer_prop_in_construct_params_if_null (construct_params, + n_construct_params, + "stepper", + g_value_get_object, + g_value_set_object, + []() -> gpointer { + return animation_linear_stepper_new (300); + }); + + + const char * const wanted_properties[] = { + "initial-distance", + "x-rotation-angle-degrees", + "y-rotation-angle-degrees", + "x-axis-location-unit", + "y-axis-location-unit", + "screen-width", + "target", + "stepper", + NULL + }; + g_autoptr(GHashTable) properties_table = + static_hash_table_of_values_for_specs (wanted_properties, + construct_params, + n_construct_params); + + auto *interface = + static_cast (InterfaceConstructor ::construct ( + ForwardFromValueHT (properties_table, g_value_get_float, "initial-distance"), + ForwardFromValueHT (properties_table, g_value_get_float, "x-rotation-angle-degrees"), + ForwardFromValueHT (properties_table, g_value_get_float, "y-rotation-angle-degrees"), + ForwardFromValueHT (properties_table, g_value_get_float, "x-axis-location-unit"), + ForwardFromValueHT (properties_table, g_value_get_float, "y-axis-location-unit"), + ForwardFromValueHT (properties_table, g_value_get_uint, "screen-width"), + ForwardFromValueHT (properties_table, animation_box_from_gvalue, "target"), + ForwardFromValueHT (properties_table, animation_stepper_from_gvalue, "stepper") + )); + + replace_interface_prop_in_construct_params (construct_params, + n_construct_params, + g_steal_pointer (&interface)); + + return G_OBJECT_CLASS (animation_glide_animation_parent_class)->constructor (type, + n_construct_params, + construct_params); +} + +static void +animation_glide_animation_init (AnimationGlideAnimation *model) +{ +} + + +static void +animation_glide_animation_class_init (AnimationGlideAnimationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = animation_glide_animation_constructor; + object_class->get_property = animation_glide_animation_get_property; + object_class->set_property = animation_glide_animation_set_property; + + animation_glide_animation_props[PROP_INITIAL_DISTANCE] = + g_param_spec_float ("initial-distance", + "Initial Distance", + "The initial distance away from the camera", + -1.0f, + 1.0f, + -0.3f, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + animation_glide_animation_props[PROP_X_ROTATION_ANGLE_DEGREES] = + g_param_spec_float ("x-rotation-angle-degrees", + "X Rotation Angle Degrees", + "Number of degrees on the X axis to rotate", + -360.0f, + 360.0f, + 0.0f, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + animation_glide_animation_props[PROP_Y_ROTATION_ANGLE_DEGREES] = + g_param_spec_float ("y-rotation-angle-degrees", + "Y Rotation Angle Degrees", + "Number of degrees on the Y axis to rotate", + -360.0f, + 360.0f, + 0.0f, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + animation_glide_animation_props[PROP_X_AXIS_LOCATION_UNIT] = + g_param_spec_float ("x-axis-location-unit", + "X Axis Location Unit", + "Unit-coordinates of where the X axis is on the surface", + 0.0f, + 1.0f, + 0.2f, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + animation_glide_animation_props[PROP_Y_AXIS_LOCATION_UNIT] = + g_param_spec_float ("y-axis-location-unit", + "Y Axis Location Unit", + "Unit-coordinates of where the Y axis is on the surface", + 0.0f, + 1.0f, + 0.5f, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + animation_glide_animation_props[PROP_SCREEN_WIDTH] = + g_param_spec_uint ("screen-width", + "Screen Width", + "Width of the screen in pixels", + 1, + G_MAXUINT, + 1, + static_cast (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + animation_glide_animation_props[PROP_TARGET] = + g_param_spec_boxed ("target", + "Target Box", + "Box that we are animating to", + ANIMATION_TYPE_BOX, + static_cast (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + animation_glide_animation_props[PROP_STEPPER] = + g_param_spec_object ("stepper", + "Stepper", + "Stepper to use to progress the animation", + ANIMATION_TYPE_STEPPER, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_properties (object_class, + NPROPS, + animation_glide_animation_props); +} + +/** + * animation_glide_new: + * @initial_distance: Initial distance frm the camera. + * @x_rotation_angle_degrees: Degrees of rotation towards the X axis. + * @y_rotation_angle_degrees: Degrees of rotation towards the Y axis. + * @y_axis_location_unit: Unit-coordinates of where the X axis is on the surface. + * @x_axis_location_unit: Unit-coordinates of where the Y axis is on the surface. + * @screen_width: Width of the screen, in pixels. + * @target_box: The #AnimationBox that we are animating to. + * @length: The length of the animation. + * + * Returns: (transfer full): A new #AnimationGlideAnimation. + */ +AnimationGlideAnimation * +animation_glide_new (float initial_distance, + float x_rotation_angle_degrees, + float y_rotation_angle_degrees, + float x_axis_location_unit, + float y_axis_location_unit, + unsigned int screen_width, + const AnimationBox *target_box, + unsigned int length) +{ + return ANIMATION_GLIDE_ANIMATION (g_object_new (ANIMATION_TYPE_GLIDE_ANIMATION, + "initial-distance", initial_distance, + "x-rotation-angle-degrees", x_rotation_angle_degrees, + "y-rotation-angle-degrees", y_rotation_angle_degrees, + "x-axis-location-unit", x_axis_location_unit, + "y-axis-location-unit", y_axis_location_unit, + "screen-width", screen_width, + "target", target_box, + "length", length, + NULL)); +} diff --git a/animation-glib/glide/glide.h b/animation-glib/glide/glide.h new file mode 100644 index 0000000..af17866 --- /dev/null +++ b/animation-glib/glide/glide.h @@ -0,0 +1,66 @@ +/* + * animation-glib/glide/glide.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject Interface for "glide" animation. + */ +#pragma once + +#include + +#include +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_GLIDE_ANIMATION animation_glide_animation_get_type () +G_DECLARE_FINAL_TYPE (AnimationGlideAnimation, animation_glide_animation, ANIMATION, GLIDE_ANIMATION, AnimationTransformAnimation) + +void animation_glide_animation_set_initial_distance (AnimationGlideAnimation *animation, + float initial_distance); +float animation_glide_animation_get_initial_distance (AnimationGlideAnimation *animation); + +void animation_glide_animation_set_x_rotation_angle_degrees (AnimationGlideAnimation *animation, + float x_rotation_angle_degrees); +float animation_glide_animation_get_x_rotation_angle_degrees (AnimationGlideAnimation *animation); + +void animation_glide_animation_set_y_rotation_angle_degrees (AnimationGlideAnimation *animation, + float y_rotation_angle_degrees); +float animation_glide_animation_get_y_rotation_angle_degrees (AnimationGlideAnimation *animation); + +void animation_glide_animation_set_x_axis_location_unit (AnimationGlideAnimation *animation, + float x_axis_location_unit); +float animation_glide_animation_get_x_axis_location_unit (AnimationGlideAnimation *animation); + +void animation_glide_animation_set_y_axis_location_unit (AnimationGlideAnimation *animation, + float y_axis_location_unit); +float animation_glide_animation_get_y_axis_location_unit (AnimationGlideAnimation *animation); + +void animation_glide_animation_set_stepper (AnimationGlideAnimation *animation, + AnimationStepper *stepper); +AnimationStepper * animation_glide_animation_get_stepper (AnimationGlideAnimation *animation); + +AnimationGlideAnimation * animation_glide_new (float initial_distance, + float x_rotation_angle_degrees, + float y_rotation_angle_degrees, + float x_axis_location_unit, + float y_axis_location_unit, + unsigned int screen_width, + const AnimationBox *target_box, + unsigned int length); + +G_END_DECLS diff --git a/animation-glib/glide/meson.build b/animation-glib/glide/meson.build new file mode 100644 index 0000000..d5f1026 --- /dev/null +++ b/animation-glib/glide/meson.build @@ -0,0 +1,18 @@ +# /animation/glide/meson.build +# +# Build the libanimation library (glide animation component). +# +# See /LICENCE.md for Copyright information. + +glide_introspectable_sources = files([ + 'glide.cpp' +]) + +glide_headers = files([ + 'glide.h' +]) + +animation_glib_introspectable_sources += glide_introspectable_sources +animation_glib_headers += glide_headers + +install_headers(glide_headers, subdir: join_paths(animation_glib_headers_subdir, 'glide')) diff --git a/animation-glib/meson.build b/animation-glib/meson.build index fb997bb..78407e6 100644 --- a/animation-glib/meson.build +++ b/animation-glib/meson.build @@ -20,18 +20,40 @@ api_version = '0' -animation_glib_toplevel_headers = ['vector.h'] -animation_glib_toplevel_introspectable_sources = ['vector.cpp'] +animation_glib_toplevel_headers = files([ + 'box.h', + 'vector.h' +]) +animation_glib_toplevel_introspectable_sources = files([ + 'box.cpp', + 'vector.cpp', + 'vector4d.cpp' +]) +animation_glib_toplevel_private_headers = files([ + 'constructor-helpers.h', + 'vector4d-internal.h' +]) +animation_glib_toplevel_private_sources = files([ + 'constructor-helpers.cpp' +]) -animation_glib_introspectable_sources = [] -animation_glib_private_sources = [] -animation_glib_headers = [] +animation_glib_introspectable_sources = files([]) +animation_glib_private_headers = files([]) +animation_glib_private_sources = files([]) +animation_glib_headers = files([]) animation_glib_headers_subdir = 'animation-glib' +subdir('bounce') +subdir('glide') +subdir('stepper') +subdir('transform') subdir('wobbly') +subdir('zoom') -animation_glib_introspectable_sources += files(animation_glib_toplevel_introspectable_sources) -animation_glib_headers += files(animation_glib_toplevel_headers) +animation_glib_introspectable_sources += animation_glib_toplevel_introspectable_sources +animation_glib_private_sources += animation_glib_toplevel_private_sources +animation_glib_headers += animation_glib_toplevel_headers +animation_glib_private_headers += animation_glib_toplevel_private_headers install_headers(animation_glib_toplevel_headers, subdir: animation_glib_headers_subdir) diff --git a/animation-glib/stepper/linear.cpp b/animation-glib/stepper/linear.cpp new file mode 100644 index 0000000..605784c --- /dev/null +++ b/animation-glib/stepper/linear.cpp @@ -0,0 +1,137 @@ +/* + * animation-glib/stepper/linear.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject wrapper for linear stepper. + */ + +#include +#include + +#include +#include +#include + +namespace as = animation::stepper; + +struct _AnimationLinearStepper +{ + GObject parent_instance; +}; + +typedef struct _AnimationLinearStepperPrivate +{ +} AnimationLinearStepperPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AnimationLinearStepper, + animation_linear_stepper, + ANIMATION_TYPE_STEPPER_HOLDER) + +enum { + PROP_0, + PROP_LENGTH, + NPROPS +}; + +static GParamSpec *animation_linear_stepper_properties[NPROPS]; + +static void +animation_linear_stepper_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_LENGTH: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static GObject * +animation_linear_stepper_constructor (GType type, + unsigned int n_construct_params, + GObjectConstructParam *construct_params) +{ + const char * const wanted_properties[] = { + "length", + NULL + }; + g_autoptr(GHashTable) properties_table = + static_hash_table_of_values_for_specs (wanted_properties, + construct_params, + n_construct_params); + + auto stepper = as::Linear (ForwardFromValueHT (properties_table, g_value_get_uint, "length")); + + replace_named_pointer_prop_in_construct_params (construct_params, + n_construct_params, + "stepper", + &stepper); + + return G_OBJECT_CLASS (animation_linear_stepper_parent_class)->constructor (type, + n_construct_params, + construct_params); +} + +static void +animation_linear_stepper_init (AnimationLinearStepper *model) +{ +} + +static void +animation_linear_stepper_class_init (AnimationLinearStepperClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = animation_linear_stepper_constructor; + object_class->set_property = animation_linear_stepper_set_property; + + animation_linear_stepper_properties[PROP_LENGTH] = + g_param_spec_uint ("length", + "Length", + "How long the animation lasts", + 1, + 5000, + 300, + static_cast (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_properties (object_class, + NPROPS, + animation_linear_stepper_properties); +} + +/** + * animation_linear_stepper_new: + * @length: Length of the transition in milliseconds. + * + * Return a new #AnimationStepper which linearly increments progress + * every time the step() method is called on it. + * + * Returns: (transfer full): An #AnimationLinearStepper + * implementation of #AnimationStepper + */ +AnimationStepper * +animation_linear_stepper_new (unsigned int length) +{ + return ANIMATION_STEPPER (g_object_new (ANIMATION_TYPE_LINEAR_STEPPER, + "length", length, + NULL)); +} diff --git a/animation-glib/stepper/linear.h b/animation-glib/stepper/linear.h new file mode 100644 index 0000000..1c83c5f --- /dev/null +++ b/animation-glib/stepper/linear.h @@ -0,0 +1,36 @@ +/* + * animation-glib/stepper/linear.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject class for linear stepper. + */ +#pragma once + +#include + +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_LINEAR_STEPPER animation_linear_stepper_get_type () +G_DECLARE_FINAL_TYPE (AnimationLinearStepper, animation_linear_stepper, ANIMATION, LINEAR_STEPPER, AnimationStepperHolder) + +AnimationStepper * animation_linear_stepper_new (unsigned int length); + +G_END_DECLS diff --git a/animation-glib/stepper/meson.build b/animation-glib/stepper/meson.build new file mode 100644 index 0000000..8eb30b1 --- /dev/null +++ b/animation-glib/stepper/meson.build @@ -0,0 +1,42 @@ +# /animation/stepper/meson.build +# +# Meson build file for libanimation stepper GObject classes. +# +# Copyright (C) 2017, 2018 Endless Mobile, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Build the libanimation library (stepper base component) + +stepper_introspectable_sources = files([ + 'linear.cpp', + 'reverse.cpp', + 'stepper.cpp', + 'stepper-holder.cpp', + 'stepper-wrapper.cpp' +]) + +stepper_headers = files([ + 'linear.h', + 'reverse.h', + 'stepper.h', + 'stepper-holder.h', + 'stepper-wrapper.h' +]) + +animation_glib_introspectable_sources += stepper_introspectable_sources +animation_glib_headers += stepper_headers + +install_headers(stepper_headers, subdir: join_paths(animation_glib_headers_subdir, 'stepper')) diff --git a/animation-glib/stepper/reverse.cpp b/animation-glib/stepper/reverse.cpp new file mode 100644 index 0000000..8b3c66c --- /dev/null +++ b/animation-glib/stepper/reverse.cpp @@ -0,0 +1,176 @@ +/* + * animation-glib/stepper/reverse.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject wrapper for reverse stepper. + */ + +#include +#include + +#include +#include +#include + +namespace as = animation::stepper; + +struct _AnimationReverseStepper +{ + GObject parent_instance; +}; + +typedef struct _AnimationReverseStepperPrivate +{ + AnimationStepper *base_stepper; +} AnimationReverseStepperPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AnimationReverseStepper, + animation_reverse_stepper, + ANIMATION_TYPE_STEPPER_HOLDER) + +enum { + PROP_0, + PROP_BASE_STEPPER, + NPROPS +}; + +static GParamSpec *animation_reverse_stepper_properties[NPROPS]; + +static void +animation_reverse_stepper_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + AnimationReverseStepper *stepper = ANIMATION_REVERSE_STEPPER (object); + AnimationReverseStepperPrivate *priv = + reinterpret_cast (animation_reverse_stepper_get_instance_private (stepper)); + + switch (prop_id) + { + case PROP_BASE_STEPPER: + priv->base_stepper = ANIMATION_STEPPER (g_value_dup_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_reverse_stepper_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AnimationReverseStepper *stepper = ANIMATION_REVERSE_STEPPER (object); + AnimationReverseStepperPrivate *priv = + reinterpret_cast (animation_reverse_stepper_get_instance_private (stepper)); + + switch (prop_id) + { + case PROP_BASE_STEPPER: + g_value_set_object (value, G_OBJECT (priv->base_stepper)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_reverse_stepper_dispose (GObject *object) +{ + AnimationReverseStepper *stepper = ANIMATION_REVERSE_STEPPER (object); + AnimationReverseStepperPrivate *priv = + reinterpret_cast (animation_reverse_stepper_get_instance_private (stepper)); + + g_clear_object (&priv->base_stepper); + + G_OBJECT_CLASS (animation_reverse_stepper_parent_class)->dispose (object); +} + +static GObject * +animation_reverse_stepper_constructor (GType type, + unsigned int n_construct_params, + GObjectConstructParam *construct_params) +{ + const char * const wanted_properties[] = { + "base-stepper", + NULL + }; + g_autoptr(GHashTable) properties_table = + static_hash_table_of_values_for_specs (wanted_properties, + construct_params, + n_construct_params); + + auto stepper = as::Reverse (ForwardFromValueHT (properties_table, + animation_stepper_from_gvalue, + "base-stepper")); + + replace_named_pointer_prop_in_construct_params (construct_params, + n_construct_params, + "stepper", + &stepper); + + return G_OBJECT_CLASS (animation_reverse_stepper_parent_class)->constructor (type, + n_construct_params, + construct_params); +} + +static void +animation_reverse_stepper_init (AnimationReverseStepper *model) +{ +} + +static void +animation_reverse_stepper_class_init (AnimationReverseStepperClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = animation_reverse_stepper_constructor; + object_class->get_property = animation_reverse_stepper_get_property; + object_class->set_property = animation_reverse_stepper_set_property; + object_class->dispose = animation_reverse_stepper_dispose; + + animation_reverse_stepper_properties[PROP_BASE_STEPPER] = + g_param_spec_object ("base-stepper", + "Base Stepper", + "Stepper to reverse", + ANIMATION_TYPE_STEPPER, + static_cast (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_properties (object_class, + NPROPS, + animation_reverse_stepper_properties); +} + +/** + * animation_reverse_stepper_new: + * @base_stepper: The stepper to reverse. + * + * Return a new #AnimationStepper which runs @base_stepper in reverse. + * + * Returns: (transfer full): An #AnimationReverseStepper + * implementation of #AnimationStepper + */ +AnimationStepper * +animation_reverse_stepper_new (AnimationStepper *base_stepper) +{ + return ANIMATION_STEPPER (g_object_new (ANIMATION_TYPE_REVERSE_STEPPER, + "base-stepper", base_stepper, + NULL)); +} diff --git a/animation-glib/stepper/reverse.h b/animation-glib/stepper/reverse.h new file mode 100644 index 0000000..0a4f625 --- /dev/null +++ b/animation-glib/stepper/reverse.h @@ -0,0 +1,36 @@ +/* + * animation-glib/stepper/reverse.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject class for reverse stepper. + */ +#pragma once + +#include + +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_REVERSE_STEPPER animation_reverse_stepper_get_type () +G_DECLARE_FINAL_TYPE (AnimationReverseStepper, animation_reverse_stepper, ANIMATION, REVERSE_STEPPER, AnimationStepperHolder) + +AnimationStepper * animation_reverse_stepper_new (AnimationStepper *base_stepper); + +G_END_DECLS diff --git a/animation-glib/stepper/stepper-holder.cpp b/animation-glib/stepper/stepper-holder.cpp new file mode 100644 index 0000000..64a96ac --- /dev/null +++ b/animation-glib/stepper/stepper-holder.cpp @@ -0,0 +1,196 @@ +/* + * animation-glib/stepper/stepper-holder.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject base class for steppers. Copies the stepper + * passed to it in its construct parameters. + */ + +#include +#include + +#include +#include + +namespace as = animation::stepper; + +struct _AnimationStepperHolder +{ + GObject parent_instance; +}; + +typedef struct _AnimationStepperHolderPrivate +{ + as::Stepper *stepper; +} AnimationStepperHolderPrivate; + +static void animation_stepper_iface_init (AnimationStepperInterface *stepper_iface); + +G_DEFINE_TYPE_WITH_CODE (AnimationStepperHolder, + animation_stepper_holder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (ANIMATION_TYPE_STEPPER, animation_stepper_iface_init) + G_ADD_PRIVATE (AnimationStepperHolder)) + +enum { + PROP_0, + PROP_STEPPER, + NPROPS +}; + +static float +animation_stepper_holder_step (AnimationStepper *stepper, + unsigned int ms) +{ + AnimationStepperHolderPrivate *priv = + reinterpret_cast (animation_stepper_holder_get_instance_private (ANIMATION_STEPPER_HOLDER (stepper))); + + return (*priv->stepper) (ms); +} + +template +static T * +copy_ptr_if_set (T *ptr) +{ + if (ptr != nullptr) + return new T (*ptr); + + return nullptr; +} + +static void +animation_stepper_holder_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + AnimationStepperHolder *holder = ANIMATION_STEPPER_HOLDER (object); + AnimationStepperHolderPrivate *priv = + reinterpret_cast (animation_stepper_holder_get_instance_private (holder)); + + switch (prop_id) + { + case PROP_STEPPER: + /* We need to copy-construct here as the property is + * not transfer full. */ + priv->stepper = copy_ptr_if_set (reinterpret_cast (g_value_get_pointer (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_stepper_holder_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AnimationStepperHolder *holder = ANIMATION_STEPPER_HOLDER (object); + AnimationStepperHolderPrivate *priv = + reinterpret_cast (animation_stepper_holder_get_instance_private (holder)); + + switch (prop_id) + { + case PROP_STEPPER: + g_value_set_pointer (value, reinterpret_cast (priv->stepper)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_stepper_holder_finalize (GObject *object) +{ + AnimationStepperHolder *holder = ANIMATION_STEPPER_HOLDER (object); + AnimationStepperHolderPrivate *priv = + reinterpret_cast (animation_stepper_holder_get_instance_private (holder)); + + delete priv->stepper; + priv->stepper = nullptr; + + G_OBJECT_CLASS (animation_stepper_holder_parent_class)->finalize (object); +} + +static GObject * +animation_stepper_holder_constructor (GType type, + unsigned int n_construct_params, + GObjectConstructParam *construct_params) +{ + auto defaultStepperHolder = as::Linear (300); + + /* Check the passed stepper_holder prop to ensure that it is set. If not, + * then we need to set it to some sensible default value. */ + for (unsigned int i = 0; i < n_construct_params; ++i) + { + if (g_strcmp0 (construct_params[i].pspec->name, "stepper") == 0) + { + if (g_value_get_pointer (construct_params[i].value) == nullptr) + g_value_set_pointer (construct_params[i].value, &defaultStepperHolder); + } + } + + return G_OBJECT_CLASS (animation_stepper_holder_parent_class)->constructor (type, + n_construct_params, + construct_params); +} + +static void +animation_stepper_holder_init (AnimationStepperHolder *stepper_holder) +{ +} + +static void +animation_stepper_iface_init (AnimationStepperInterface *interface) +{ + interface->step = animation_stepper_holder_step; +} + +static void +animation_stepper_holder_class_init (AnimationStepperHolderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = animation_stepper_holder_constructor; + object_class->get_property = animation_stepper_holder_get_property; + object_class->set_property = animation_stepper_holder_set_property; + object_class->finalize = animation_stepper_holder_finalize; + + g_object_class_override_property (object_class, + PROP_STEPPER, + "stepper"); +} + +/** + * animation_stepper_holder_new: (skip): + * @interface: A pointer to an interlying stepper implementation. + * + * Create a new #AnimationStepperHolder, an implementation of + * #AnimationStepper which copies the underlying stepper when it + * is constructed (thus resetting its internal state, as copying + * a C++ lambda default-constructs its closure). + * + * Returns: (transfer full): A new #AnimationStepper with the underlying + * stepper copied. + */ +AnimationStepper * +animation_stepper_holder_new (gpointer interface) +{ + return ANIMATION_STEPPER (g_object_new (ANIMATION_TYPE_STEPPER_HOLDER, "stepper", interface, NULL)); +} diff --git a/animation-glib/stepper/stepper-holder.h b/animation-glib/stepper/stepper-holder.h new file mode 100644 index 0000000..967ce28 --- /dev/null +++ b/animation-glib/stepper/stepper-holder.h @@ -0,0 +1,36 @@ +/* + * animation-glib/stepper/stepper-holder.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject base class for steppers, which holds a copy of a stepper. + */ +#pragma once + +#include + +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_STEPPER_HOLDER animation_stepper_holder_get_type () +G_DECLARE_FINAL_TYPE (AnimationStepperHolder, animation_stepper_holder, ANIMATION, STEPPER_HOLDER, GObject) + +AnimationStepper * animation_stepper_holder_new (gpointer interface); + +G_END_DECLS diff --git a/animation-glib/stepper/stepper-wrapper.cpp b/animation-glib/stepper/stepper-wrapper.cpp new file mode 100644 index 0000000..830b0bd --- /dev/null +++ b/animation-glib/stepper/stepper-wrapper.cpp @@ -0,0 +1,160 @@ +/* + * animation-glib/stepper/stepper-wrapper.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject base class for steppers. Only observes the stepper passed + * to it in its construct parameters - not expected to outlive the stepper. + */ + +#include +#include + +#include +#include + +namespace as = animation::stepper; + +struct _AnimationStepperWrapper +{ + GObject parent_instance; +}; + +typedef struct _AnimationStepperWrapperPrivate +{ + as::Stepper *stepper; +} AnimationStepperWrapperPrivate; + +static void animation_stepper_iface_init (AnimationStepperInterface *stepper_iface); + +G_DEFINE_TYPE_WITH_CODE (AnimationStepperWrapper, + animation_stepper_wrapper, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (ANIMATION_TYPE_STEPPER, animation_stepper_iface_init) + G_ADD_PRIVATE (AnimationStepperWrapper)) + +enum { + PROP_0, + PROP_STEPPER, + NPROPS +}; + +static float +animation_stepper_wrapper_step (AnimationStepper *stepper, + unsigned int ms) +{ + AnimationStepperWrapperPrivate *priv = + reinterpret_cast (animation_stepper_wrapper_get_instance_private (ANIMATION_STEPPER_WRAPPER (stepper))); + + return (*priv->stepper) (ms); +} + +static void +animation_stepper_wrapper_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + AnimationStepperWrapper *holder = ANIMATION_STEPPER_WRAPPER (object); + AnimationStepperWrapperPrivate *priv = + reinterpret_cast (animation_stepper_wrapper_get_instance_private (holder)); + + switch (prop_id) + { + case PROP_STEPPER: + priv->stepper = reinterpret_cast (g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_stepper_wrapper_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AnimationStepperWrapper *holder = ANIMATION_STEPPER_WRAPPER (object); + AnimationStepperWrapperPrivate *priv = + reinterpret_cast (animation_stepper_wrapper_get_instance_private (holder)); + + switch (prop_id) + { + case PROP_STEPPER: + g_value_set_pointer (value, reinterpret_cast (priv->stepper)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_stepper_wrapper_finalize (GObject *object) +{ + AnimationStepperWrapper *holder = ANIMATION_STEPPER_WRAPPER (object); + AnimationStepperWrapperPrivate *priv = + reinterpret_cast (animation_stepper_wrapper_get_instance_private (holder)); + + delete priv->stepper; + priv->stepper = nullptr; + + G_OBJECT_CLASS (animation_stepper_wrapper_parent_class)->finalize (object); +} + +static void +animation_stepper_wrapper_init (AnimationStepperWrapper *stepper_wrapper) +{ +} + +static void +animation_stepper_iface_init (AnimationStepperInterface *interface) +{ + interface->step = animation_stepper_wrapper_step; +} + +static void +animation_stepper_wrapper_class_init (AnimationStepperWrapperClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = animation_stepper_wrapper_get_property; + object_class->set_property = animation_stepper_wrapper_set_property; + object_class->finalize = animation_stepper_wrapper_finalize; + + g_object_class_override_property (object_class, + PROP_STEPPER, + "stepper"); +} + +/** + * animation_stepper_wrapper_new: (skip): + * @interface: A pointer to an interlying stepper implementation. + * + * Create a new #AnimationStepperWrapper, an implementation of + * #AnimationStepper which only observes the underlying stepper when it + * is constructed (keeping its internal state). However, the wrapper + * must not outlive the underlying stepper. + * + * Returns: (transfer full): A new #AnimationStepper with the underlying + * stepper merely observed. + */ +AnimationStepper * +animation_stepper_wrapper_new (gpointer interface) +{ + return ANIMATION_STEPPER (g_object_new (ANIMATION_TYPE_STEPPER_WRAPPER, "stepper", interface, NULL)); +} diff --git a/animation-glib/stepper/stepper-wrapper.h b/animation-glib/stepper/stepper-wrapper.h new file mode 100644 index 0000000..bd59e53 --- /dev/null +++ b/animation-glib/stepper/stepper-wrapper.h @@ -0,0 +1,36 @@ +/* + * animation-glib/stepper/stepper-wrapper.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject base class for steppers, which holds a copy of a stepper. + */ +#pragma once + +#include + +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_STEPPER_WRAPPER animation_stepper_wrapper_get_type () +G_DECLARE_FINAL_TYPE (AnimationStepperWrapper, animation_stepper_wrapper, ANIMATION, STEPPER_WRAPPER, GObject) + +AnimationStepper * animation_stepper_wrapper_new (gpointer interface); + +G_END_DECLS diff --git a/animation-glib/stepper/stepper.cpp b/animation-glib/stepper/stepper.cpp new file mode 100644 index 0000000..714f4a2 --- /dev/null +++ b/animation-glib/stepper/stepper.cpp @@ -0,0 +1,49 @@ +/* + * animation-glib/stepper/stepper.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject base interface for steppers. + */ + +#include +#include + +namespace as = animation::stepper; + + +G_DEFINE_INTERFACE (AnimationStepper, + animation_stepper, + G_TYPE_OBJECT) +float +animation_stepper_step (AnimationStepper *stepper, + unsigned int ms) +{ + g_return_val_if_fail (ANIMATION_IS_STEPPER (stepper), 0.0f); + + return ANIMATION_STEPPER_GET_IFACE (stepper)->step (stepper, ms); +} + +static void +animation_stepper_default_init (AnimationStepperInterface *iface) +{ + g_object_interface_install_property ((gpointer) iface, + g_param_spec_pointer ("stepper", + "Internal Interface", + "Internal C++ interface that this class wraps", + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); +} diff --git a/animation-glib/stepper/stepper.h b/animation-glib/stepper/stepper.h new file mode 100644 index 0000000..40e98f3 --- /dev/null +++ b/animation-glib/stepper/stepper.h @@ -0,0 +1,44 @@ +/* + * animation-glib/stepper/stepper.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject base interface for steppers. + */ +#pragma once + +#include + +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_STEPPER animation_stepper_get_type () +G_DECLARE_INTERFACE (AnimationStepper, animation_stepper, ANIMATION, STEPPER, GObject) + +struct _AnimationStepperInterface +{ + GTypeInterface parent_iface; + + float (*step) (AnimationStepper *self, + unsigned int ms); +}; + +float animation_stepper_step (AnimationStepper *stepper, + unsigned int ms); + +G_END_DECLS diff --git a/animation-glib/transform/meson.build b/animation-glib/transform/meson.build new file mode 100644 index 0000000..6a64bff --- /dev/null +++ b/animation-glib/transform/meson.build @@ -0,0 +1,34 @@ +# /animation/transform/meson.build +# +# Toplevel meson build file for libanimation. +# +# Copyright (C) 2017, 2018 Endless Mobile, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Build the libanimation library (transform animation base component + +transform_introspectable_sources = files([ + 'transform.cpp' +]) + +transform_headers = files([ + 'transform.h' +]) + +animation_glib_introspectable_sources += transform_introspectable_sources +animation_glib_headers += transform_headers + +install_headers(transform_headers, subdir: join_paths(animation_glib_headers_subdir, 'transform')) diff --git a/animation-glib/transform/transform.cpp b/animation-glib/transform/transform.cpp new file mode 100644 index 0000000..190fc9d --- /dev/null +++ b/animation-glib/transform/transform.cpp @@ -0,0 +1,202 @@ +/* + * animation-glib/transform/transform.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject base class for affine transform based animations. + */ + +#include + +#include +#include +#include +#include + +namespace agd = animation::geometry::dimension; +namespace at = animation::transform; + +typedef struct _AnimationTransformAnimationPrivate +{ + at::TransformAnimation *interface; +} AnimationTransformAnimationPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AnimationTransformAnimation, + animation_transform_animation, + G_TYPE_OBJECT) + +enum { + PROP_0, + PROP_INTERFACE, + NPROPS +}; + +static GParamSpec *animation_transform_animation_props [NPROPS] = { NULL, }; + +gboolean +animation_transform_animation_step (AnimationTransformAnimation *transform_animation, + unsigned int ms) +{ + AnimationTransformAnimationPrivate *priv = + reinterpret_cast (animation_transform_animation_get_instance_private (transform_animation)); + + return priv->interface->Step (ms); +} + +/** + * animation_transform_animation_matrix: + * @transform_animation: A #AnimationTransformAnimation + * + * Get the 4x4 column-major transformation matrix for this + * representing the state of this animation. + * + * Returns: (array fixed-size=16): The 4x4 column-major ordered + * transformation matrix. + */ +float const * +animation_transform_animation_matrix (AnimationTransformAnimation *transform_animation) +{ + AnimationTransformAnimationPrivate *priv = + reinterpret_cast (animation_transform_animation_get_instance_private (transform_animation)); + + return priv->interface->Matrix (); +} + +/** + * animation_transform_animation_extremes: + * @transform_animation: A #AnimationTransformAnimation + * @corners: (array fixed-size=4): The four #AnimationVector4D values + * describing the location of the surface corners. + * @out_extremes: (array fixed-size=4) (out): The transformed four #AnimationVector + * values describing the location of the transformed surface + * surface corners. + * + * Get the four co-ordinates of a 3D plane which bound the animated surface. + */ +void +animation_transform_animation_extremes (AnimationTransformAnimation *transform_animation, + AnimationVector const *corners, + AnimationVector4D *out_extremes) +{ + g_return_if_fail (corners != NULL); + g_return_if_fail (out_extremes != NULL); + + AnimationTransformAnimationPrivate *priv = + reinterpret_cast (animation_transform_animation_get_instance_private (transform_animation)); + + std::array points = { + animation::Point (corners[0].x, corners[0].y), + animation::Point (corners[1].x, corners[1].y), + animation::Point (corners[2].x, corners[2].y), + animation::Point (corners[3].x, corners[3].y) + }; + + std::array extremes = priv->interface->Extremes (points); + + agd::assign (out_extremes[0], extremes[0]); + agd::assign (out_extremes[1], extremes[1]); + agd::assign (out_extremes[2], extremes[2]); + agd::assign (out_extremes[3], extremes[3]); +} + +float +animation_transform_animation_progress (AnimationTransformAnimation *transform_animation) +{ + AnimationTransformAnimationPrivate *priv = + reinterpret_cast (animation_transform_animation_get_instance_private (transform_animation)); + + return priv->interface->Progress (); +} + +static void +animation_transform_animation_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + AnimationTransformAnimation *transform_animation = ANIMATION_TRANSFORM_ANIMATION (object); + AnimationTransformAnimationPrivate *priv = + reinterpret_cast (animation_transform_animation_get_instance_private (transform_animation)); + + switch (prop_id) + { + case PROP_INTERFACE: + priv->interface = reinterpret_cast (g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_transform_animation_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AnimationTransformAnimation *transform_animation = ANIMATION_TRANSFORM_ANIMATION (object); + AnimationTransformAnimationPrivate *priv = + reinterpret_cast (animation_transform_animation_get_instance_private (transform_animation)); + + switch (prop_id) + { + case PROP_INTERFACE: + g_value_set_pointer (value, reinterpret_cast (priv->interface)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_transform_animation_finalize (GObject *object) +{ + AnimationTransformAnimation *transform_animation = ANIMATION_TRANSFORM_ANIMATION (object); + AnimationTransformAnimationPrivate *priv = + reinterpret_cast (animation_transform_animation_get_instance_private (transform_animation)); + + delete priv->interface; + priv->interface = nullptr; + + G_OBJECT_CLASS (animation_transform_animation_parent_class)->finalize (object); +} + +static void +animation_transform_animation_init (AnimationTransformAnimation *model) +{ +} + + +static void +animation_transform_animation_class_init (AnimationTransformAnimationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = animation_transform_animation_get_property; + object_class->set_property = animation_transform_animation_set_property; + object_class->finalize = animation_transform_animation_finalize; + + animation_transform_animation_props[PROP_INTERFACE] = + g_param_spec_pointer ("interface", + "Internal Interface", + "Internal C++ interface that this class wraps", + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_properties (object_class, + NPROPS, + animation_transform_animation_props); +} diff --git a/animation-glib/transform/transform.h b/animation-glib/transform/transform.h new file mode 100644 index 0000000..58a3be8 --- /dev/null +++ b/animation-glib/transform/transform.h @@ -0,0 +1,49 @@ +/* + * animation-glib/transform/transform.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject Interface for affine transform animations. + */ +#pragma once + +#include + +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_TRANSFORM_ANIMATION animation_transform_animation_get_type () +G_DECLARE_DERIVABLE_TYPE (AnimationTransformAnimation, animation_transform_animation, ANIMATION, TRANSFORM_ANIMATION, GObject) + +struct _AnimationTransformAnimationClass { + GObjectClass parent_class; +}; + +gboolean animation_transform_animation_step (AnimationTransformAnimation *transform_animation, + unsigned int ms); + +float animation_transform_animation_progress (AnimationTransformAnimation *transform_animation); + +float const * animation_transform_animation_matrix (AnimationTransformAnimation *transform_animation); + +void animation_transform_animation_extremes (AnimationTransformAnimation *transform_animation, + AnimationVector const *corners, + AnimationVector4D *out_extremes); + +G_END_DECLS diff --git a/animation-glib/vector4d-internal.h b/animation-glib/vector4d-internal.h new file mode 100644 index 0000000..ca5e305 --- /dev/null +++ b/animation-glib/vector4d-internal.h @@ -0,0 +1,99 @@ +/* + * animation-glib/vector4d-internal.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject boxed type 4D vector implementation. + */ + +#include + +namespace animation +{ + namespace geometry + { + namespace dimension + { + template <> + struct Dimension + { + typedef double data_type; + static const size_t dimensions = 4; + }; + + template <> + struct DimensionAccess + { + static inline double get (AnimationVector4D const &p) + { + return p.x; + } + + static inline void + set (AnimationVector4D &p, double const &value) + { + p.x = value; + } + }; + + template <> + struct DimensionAccess + { + static inline double get (AnimationVector4D const &p) + { + return p.y; + } + + static inline void + set (AnimationVector4D &p, double const &value) + { + p.y = value; + } + }; + + template <> + struct DimensionAccess + { + static inline double get (AnimationVector4D const &p) + { + return p.z; + } + + static inline void + set (AnimationVector4D &p, double const &value) + { + p.z = value; + } + }; + + template <> + struct DimensionAccess + { + static inline double get (AnimationVector4D const &p) + { + return p.w; + } + + static inline void + set (AnimationVector4D &p, double const &value) + { + p.w = value; + } + }; + } + } +} diff --git a/animation-glib/vector4d.cpp b/animation-glib/vector4d.cpp new file mode 100644 index 0000000..e54c1d9 --- /dev/null +++ b/animation-glib/vector4d.cpp @@ -0,0 +1,39 @@ +/* + * animation-glib/vector4d.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject boxed type 4D vector implementation. + */ + +#include + +static gpointer +animation_vector4d_copy (gpointer ptr) +{ + AnimationVector4D *src = reinterpret_cast (ptr); + AnimationVector4D *dst = g_new0 (AnimationVector4D, 1); + + *dst = *src; + + return reinterpret_cast (dst); +} + +G_DEFINE_BOXED_TYPE (AnimationVector4D, + animation_vector4d, + animation_vector4d_copy, + g_free) diff --git a/animation-glib/vector4d.h b/animation-glib/vector4d.h new file mode 100644 index 0000000..ff2b2b5 --- /dev/null +++ b/animation-glib/vector4d.h @@ -0,0 +1,39 @@ +/* + * animation-glib/vector4d.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject boxed type 4D vector implementation. + */ +#pragma once + +#include + +G_BEGIN_DECLS + +typedef struct { + double x; + double y; + double z; + double w; +} AnimationVector4D; + +#define ANIMATION_TYPE_VECTOR4D animation_vector4d_get_type () + +GType animation_vector4d_get_type (void); + +G_END_DECLS diff --git a/animation-glib/zoom/meson.build b/animation-glib/zoom/meson.build new file mode 100644 index 0000000..c206a40 --- /dev/null +++ b/animation-glib/zoom/meson.build @@ -0,0 +1,18 @@ +# /animation/zoom/meson.build +# +# Build the libanimation library (zoom animation component). +# +# See /LICENCE.md for Copyright information. + +zoom_introspectable_sources = files([ + 'zoom.cpp' +]) + +zoom_headers = files([ + 'zoom.h' +]) + +animation_glib_introspectable_sources += zoom_introspectable_sources +animation_glib_headers += zoom_headers + +install_headers(zoom_headers, subdir: join_paths(animation_glib_headers_subdir, 'zoom')) diff --git a/animation-glib/zoom/zoom.cpp b/animation-glib/zoom/zoom.cpp new file mode 100644 index 0000000..6d799a2 --- /dev/null +++ b/animation-glib/zoom/zoom.cpp @@ -0,0 +1,295 @@ +/* + * animation-glib/zoom/zoom.cpp + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject interface for a zoom animation. + */ + +#include + +#include +#include +#include +#include +#include +#include + +namespace agd = animation::geometry::dimension; +namespace at = animation::transform; +namespace az = animation::zoom; + +struct _AnimationZoomAnimation +{ + AnimationTransformAnimation parent_instance; +}; + +typedef struct _AnimationZoomAnimationPrivate +{ +} AnimationZoomAnimationPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AnimationZoomAnimation, + animation_zoom_animation, + ANIMATION_TYPE_TRANSFORM_ANIMATION) + +enum { + PROP_0, + PROP_FROM, + PROP_TO, + PROP_STEPPER, + NPROPS +}; + +static GParamSpec *animation_zoom_animation_props [NPROPS] = { NULL, }; + +void +animation_zoom_animation_set_from (AnimationZoomAnimation *animation, + AnimationBox box) +{ + LookupTypedInterfaceProp (G_OBJECT (animation))->From (animation::Box (animation::Point (box.top_left.x, + box.top_left.y), + animation::Point (box.bottom_right.x, + box.bottom_right.y))); +} + +/** + * animation_zoom_animation_get_from: + * @animation: An #AnimationZoomAnimation + * @out_box: (out caller-allocates): Return location for an #AnimationBox to the source + * + * Get the source box for this animation. + */ +void +animation_zoom_animation_get_from (AnimationZoomAnimation *animation, + AnimationBox *out_box) +{ + g_return_if_fail (out_box != NULL); + + auto box = LookupTypedInterfaceProp (G_OBJECT (animation))->From (); + + out_box->top_left.x = agd::get <0> (box.topLeft ()); + out_box->top_left.y = agd::get <1> (box.topLeft ()); + out_box->bottom_right.x = agd::get <0> (box.bottomRight ()); + out_box->bottom_right.y = agd::get <1> (box.bottomRight ()); +} + + +/** + * animation_zoom_animation_get_to: + * @animation: An #AnimationZoomAnimation + * @out_box: (out caller-allocates): Return location for an #AnimationBox to the target + * + * Get the source box for this animation. + */ +void +animation_zoom_animation_get_to (AnimationZoomAnimation *animation, + AnimationBox *out_box) +{ + g_return_if_fail (out_box != NULL); + + auto box = LookupTypedInterfaceProp (G_OBJECT (animation))->To (); + + out_box->top_left.x = agd::get <0> (box.topLeft ()); + out_box->top_left.y = agd::get <1> (box.topLeft ()); + out_box->bottom_right.x = agd::get <0> (box.bottomRight ()); + out_box->bottom_right.y = agd::get <1> (box.bottomRight ()); +} + +void +animation_zoom_animation_set_stepper (AnimationZoomAnimation *animation, + AnimationStepper *stepper) +{ + animation::stepper::Stepper *stepper_ptr = nullptr; + g_object_get (stepper, "stepper", (gpointer) &stepper_ptr, NULL); + + LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper (*stepper_ptr); +} + +/** + * animation_zoom_animation_get_stepper: + * @animation: An #AnimationZoomAnimation + * + * Returns: (transfer full): Get the stepper for this #AnimationZoomAnimation + */ +AnimationStepper * +animation_zoom_animation_get_stepper (AnimationZoomAnimation *animation) +{ + auto const &stepper (LookupTypedInterfaceProp (G_OBJECT (animation))->Stepper ()); + + return animation_stepper_wrapper_new ((gpointer) &stepper); +} + +static void +animation_zoom_animation_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + AnimationZoomAnimation *zoom_animation = ANIMATION_ZOOM_ANIMATION (object); + + switch (prop_id) + { + case PROP_FROM: + { + AnimationBox *box = reinterpret_cast (g_value_get_boxed (value)); + + if (box != nullptr) + animation_zoom_animation_set_from (zoom_animation, *box); + } + break; + case PROP_TO: + break; + case PROP_STEPPER: + animation_zoom_animation_set_stepper (zoom_animation, reinterpret_cast (g_value_get_object (value))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +animation_zoom_animation_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + AnimationZoomAnimation *zoom_animation = ANIMATION_ZOOM_ANIMATION (object); + + switch (prop_id) + { + case PROP_FROM: + { + AnimationBox box; + animation_zoom_animation_get_from (zoom_animation, &box); + + g_value_set_boxed (value, (gpointer) &box); + } + break; + case PROP_TO: + { + AnimationBox box; + animation_zoom_animation_get_to (zoom_animation, &box); + + g_value_set_boxed (value, (gpointer) &box); + } + break; + case PROP_STEPPER: + g_value_take_object (value, animation_zoom_animation_get_stepper (zoom_animation)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static GObject * +animation_zoom_animation_constructor (GType type, + unsigned int n_construct_params, + GObjectConstructParam *construct_params) +{ + replace_named_pointer_prop_in_construct_params_if_null (construct_params, + n_construct_params, + "stepper", + g_value_get_object, + g_value_set_object, + []() -> gpointer { + return animation_linear_stepper_new (300); + }); + + const char * const wanted_properties[] = { + "from", + "to", + "stepper", + NULL + }; + g_autoptr(GHashTable) properties_table = + static_hash_table_of_values_for_specs (wanted_properties, + construct_params, + n_construct_params); + + auto *interface = + static_cast (InterfaceConstructor ::construct ( + ForwardFromValueHT (properties_table, animation_box_from_gvalue, "from"), + ForwardFromValueHT (properties_table, animation_box_from_gvalue, "to"), + ForwardFromValueHT (properties_table, animation_stepper_from_gvalue, "stepper") + )); + + replace_interface_prop_in_construct_params (construct_params, + n_construct_params, + g_steal_pointer (&interface)); + + return G_OBJECT_CLASS (animation_zoom_animation_parent_class)->constructor (type, + n_construct_params, + construct_params); +} + +static void +animation_zoom_animation_init (AnimationZoomAnimation *model) +{ +} + +static void +animation_zoom_animation_class_init (AnimationZoomAnimationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = animation_zoom_animation_constructor; + object_class->get_property = animation_zoom_animation_get_property; + object_class->set_property = animation_zoom_animation_set_property; + + animation_zoom_animation_props[PROP_FROM] = + g_param_spec_boxed ("from", + "From Box", + "Box that we are animating from", + ANIMATION_TYPE_BOX, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + animation_zoom_animation_props[PROP_TO] = + g_param_spec_boxed ("to", + "To Box", + "Box that we are animating to", + ANIMATION_TYPE_BOX, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + animation_zoom_animation_props[PROP_STEPPER] = + g_param_spec_object ("stepper", + "Stepper", + "Stepper to use to progress the animation", + ANIMATION_TYPE_STEPPER, + static_cast (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_properties (object_class, + NPROPS, + animation_zoom_animation_props); +} + +/** + * animation_zoom_new: + * @from: The #AnimationBox that we are animating from. + * @to: The #AnimationBox that we are animating to (current location). + * @stepper: The stepper to use. + * + * Returns: (transfer full): A new #AnimationZoomAnimation. + */ +AnimationZoomAnimation * +animation_zoom_new (const AnimationBox *current, + const AnimationBox *from, + const AnimationBox *to, + AnimationStepper *stepper) +{ + return ANIMATION_ZOOM_ANIMATION (g_object_new (ANIMATION_TYPE_ZOOM_ANIMATION, + "from", from, + "to", to, + "stepper", stepper, + NULL)); +} diff --git a/animation-glib/zoom/zoom.h b/animation-glib/zoom/zoom.h new file mode 100644 index 0000000..47f4cd0 --- /dev/null +++ b/animation-glib/zoom/zoom.h @@ -0,0 +1,50 @@ +/* + * animation-glib/zoom/zoom.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * GObject Interface for "zoom" animation. + */ +#pragma once + +#include + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define ANIMATION_TYPE_ZOOM_ANIMATION animation_zoom_animation_get_type () +G_DECLARE_FINAL_TYPE (AnimationZoomAnimation, animation_zoom_animation, ANIMATION, ZOOM_ANIMATION, AnimationTransformAnimation) + +void animation_zoom_animation_set_from (AnimationZoomAnimation *animation, + AnimationBox box); +void animation_zoom_animation_get_from (AnimationZoomAnimation *animation, + AnimationBox *out_box); + +void animation_zoom_animation_get_to (AnimationZoomAnimation *animation, + AnimationBox *out_box); + +void animation_zoom_animation_set_stepper (AnimationZoomAnimation *animation, + AnimationStepper *stepper); +AnimationStepper * animation_zoom_animation_get_stepper (AnimationZoomAnimation *animation); + +AnimationZoomAnimation * animation_zoom_new (const AnimationBox *from, + const AnimationBox *to, + AnimationStepper *stepper); + +G_END_DECLS diff --git a/animation/bounce/bounce.cpp b/animation/bounce/bounce.cpp new file mode 100644 index 0000000..bd18566 --- /dev/null +++ b/animation/bounce/bounce.cpp @@ -0,0 +1,218 @@ +/* + * animation/bounce/bounce.cpp + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * An animation that causes a surface to bounce onto screen, gently + * following an attenuating sine wave. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace agd = animation::geometry::dimension; +namespace ab = animation::bounce; +namespace abc = animation::box_calculation; +namespace am = animation::math; +namespace atc = animation::transform_calculation; + +namespace +{ + float SampleSineWave (float progress, + unsigned int nBounces) + { + return ::sin (progress * M_PI * nBounces); + } + + /* 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 this 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 to fit within the time range), but the effect + * of the animation is scaled according to where we are on the bounds. + * + * 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. */ + float ComputeScaleFactorFromProgressParameters (float progress, + float initialScale, + float maximumScale, + unsigned int nBounces) + { + /* Squeeze the sine wave into place by applying a linear + * interpolation to it */ + float const targetScale = 1.0f; + float sampledSine = SampleSineWave (progress, nBounces); + float range = (maximumScale - initialScale) * (1.0f - progress); + float scaleFloor = initialScale + (targetScale - initialScale) * progress; + + return scaleFloor + range * sampledSine; + } + + void ComputeBounceTransform (glm::mat4 &transform, + float progress, + float initialScale, + float maximumScale, + unsigned int nBounces, + animation::Box const &targetBox) + { + animation::Point boxCenterOffset (abc::ComputeBoxCenterOffset (targetBox)); + + float const scaleFactor = ComputeScaleFactorFromProgressParameters (progress, + initialScale, + maximumScale, + nBounces); + auto centerMat = glm::translate (glm::mat4 (1.0), + glm::vec3 (-1 * agd::get <0> (boxCenterOffset), + -1 *agd::get <1> (boxCenterOffset), + 0.0)); + auto scaleMat = glm::scale (glm::mat4 (1.0), + glm::vec3 (scaleFactor, + scaleFactor, + 1.0)); + auto invCenterMat = glm::translate (glm::mat4 (1.0), + glm::vec3 (agd::get <0> (boxCenterOffset), + agd::get <1> (boxCenterOffset), + 0.0)); + + transform = invCenterMat * scaleMat * centerMat; + } +} + +namespace animation +{ + namespace bounce + { + struct BounceAnimation::Private + { + Private (float initialScale, + float maximumScale, + unsigned int nBounce, + animation::Box const &target, + animation::stepper::Stepper const &stepper); + + float initialScale; + float maximumScale; + unsigned int nBounce; + animation::Box target; + + glm::mat4 transform; + float progress; + + animation::stepper::Stepper stepper; + }; + + BounceAnimation::Private::Private (float initialScale, + float maximumScale, + unsigned int nBounce, + animation::Box const &target, + animation::stepper::Stepper const &stepper) : + initialScale (initialScale), + maximumScale (maximumScale), + nBounce (nBounce), + target (target), + transform (glm::mat4 (1.0)), + progress (stepper (0)), + stepper (stepper) + { + ComputeBounceTransform (transform, + progress, + initialScale, + maximumScale, + nBounce, + target); + } + } +} + +std::array +ab::BounceAnimation::Extremes (std::array const &corners) const +{ + return std::array { + atc::TransformFlattened2DPointBy3DMatrix (corners[0], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[1], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[2], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[3], priv->transform) + }; +} + +float +ab::BounceAnimation::Progress () const +{ + return priv->progress; +} + +bool +ab::BounceAnimation::Step (unsigned int ms) +{ + priv->progress = am::clamp (priv->stepper (ms), 0.0f, 1.0f); + + ComputeBounceTransform (priv->transform, + priv->progress, + priv->initialScale, + priv->maximumScale, + priv->nBounce, + priv->target); + + return priv->progress != 0.0f && priv->progress != 1.0f; +} + +float * const +ab::BounceAnimation::Matrix () const +{ + return glm::value_ptr (priv->transform); +} + +ANIMATION_DEFINE_PROPERTY (ab::BounceAnimation, InitialScale, float, priv->initialScale) +ANIMATION_DEFINE_PROPERTY (ab::BounceAnimation, MaximumScale, float, priv->maximumScale) +ANIMATION_DEFINE_PROPERTY (ab::BounceAnimation, NBounce, unsigned int, priv->nBounce) +ANIMATION_DEFINE_PROPERTY (ab::BounceAnimation, Stepper, animation::stepper::Stepper, priv->stepper) +ANIMATION_DEFINE_READONLY_PROPERTY (ab::BounceAnimation, Target, animation::Box , priv->target) + +ab::BounceAnimation::BounceAnimation (float initialScale, + float maximumScale, + unsigned int nBounce, + animation::Box const &target, + animation::stepper::Stepper const &stepper) : + priv (new ab::BounceAnimation::Private (initialScale, + maximumScale, + nBounce, + target, + stepper)) +{ +} + +ab::BounceAnimation::~BounceAnimation () +{ +} diff --git a/animation/bounce/bounce.h b/animation/bounce/bounce.h new file mode 100644 index 0000000..58d079d --- /dev/null +++ b/animation/bounce/bounce.h @@ -0,0 +1,65 @@ +/* + * animation/bounce/bounce.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * An animation that causes a surface to bounce onto screen, gently + * following an attenuating sine wave. + */ + +#include +#include + +#include +#include +#include +#include + +#pragma once + +namespace animation +{ + namespace bounce + { + class BounceAnimation : + public animation::transform::TransformAnimation + { + public: + + BounceAnimation (float initialScale, + float maximumScale, + unsigned int nBounce, + animation::Box const &target, + animation::stepper::Stepper const &stepper); + ~BounceAnimation (); + + float * const Matrix () const; + float Progress () const; + bool Step (unsigned int ms); + std::array Extremes (std::array const &corners) const; + + ANIMATION_DECLARE_PROPERTY (BounceAnimation, InitialScale, float) + ANIMATION_DECLARE_PROPERTY (BounceAnimation, MaximumScale, float) + ANIMATION_DECLARE_PROPERTY (BounceAnimation, NBounce, unsigned int) + ANIMATION_DECLARE_PROPERTY (BounceAnimation, Stepper, animation::stepper::Stepper) + ANIMATION_DECLARE_READONLY_PROPERTY (BounceAnimation, Target, animation::Box ) + + private: + + struct Private; + std::unique_ptr priv; + }; + } +} diff --git a/animation/bounce/meson.build b/animation/bounce/meson.build new file mode 100644 index 0000000..4fccbad --- /dev/null +++ b/animation/bounce/meson.build @@ -0,0 +1,34 @@ +# /animation/bounce/meson.build +# +# Toplevel meson build file for libanimation. +# +# Copyright (C) 2017, 2018 Endless Mobile, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Build the libanimation library (bounce animation component). + +bounce_sources = files([ + 'bounce.cpp' +]) + +bounce_headers = files([ + 'bounce.h' +]) + +animation_sources += bounce_sources +animation_headers += bounce_headers + +install_headers(bounce_headers, subdir: join_paths(animation_headers_subdir, 'bounce')) diff --git a/animation/box_calculation.h b/animation/box_calculation.h new file mode 100644 index 0000000..8821dec --- /dev/null +++ b/animation/box_calculation.h @@ -0,0 +1,70 @@ +/* + * animation/box_calculation.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Utility functions to calculate points and box offsets. + */ +#pragma once + +#include + +namespace animation +{ + namespace box_calculation + { + inline animation::Point ComputeBoxCenterOffset (animation::Box const &box) + { + namespace agd = animation::geometry::dimension; + + return animation::Point ((agd::get <0> (box.bottomRight ()) - + agd::get <0> (box.topLeft ())) / 2.0, + (agd::get <1> (box.bottomRight ()) - + agd::get <1> (box.topLeft ())) / 2.0); + } + + inline animation::Point ComputeBoxCenter (animation::Box const &box) + { + namespace agd = animation::geometry::dimension; + + animation::Point topLeft (box.topLeft ()); + agd::pointwise_add (topLeft, ComputeBoxCenterOffset (box)); + return topLeft; + } + + inline animation::Point ComputeRotationAxisOffset (animation::Box const &box, + float u, + float v) + { + namespace agd = animation::geometry::dimension; + + return animation::Point ((agd::get <0> (box.bottomRight ()) - + agd::get <0> (box.topLeft ())) * u, + (agd::get <1> (box.bottomRight ()) - + agd::get <1> (box.topLeft ())) * v); + } + + inline animation::Point ComputeRotationAxis (animation::Box const &box, + float u, + float v) + { + namespace agd = animation::geometry::dimension; + + animation::Point topLeft (box.topLeft ()); + agd::pointwise_add (topLeft, ComputeRotationAxisOffset (box, u, v)); + return topLeft; + } + } +} diff --git a/animation/geometry.h b/animation/geometry.h index 51413d8..9a1fe65 100644 --- a/animation/geometry.h +++ b/animation/geometry.h @@ -367,12 +367,143 @@ namespace animation dimension::get <1> (p) >= y1 && dimension::get <1> (p) <= y2); } + + /** + * Vector4DModel: + * + * A detached 2D point or vector in space for a given data + * type T. This is a structure of two values. + * + * Vector4DModel implements the Dimension trait, meaning that it + * can be used with functions in the animation::geometry::dimension + * namespace. + */ + template + struct Vector4DModel + { + Vector4DModel (T x, T y, T z, T w) noexcept : + x (x), + y (y), + z (z), + w (w) + { + } + + Vector4DModel () noexcept : + x (0), + y (0), + z (0), + w (0) + { + } + + Vector4DModel (Vector4DModel const &v) noexcept : + x (v.x), + y (v.y), + z (v.z), + w (v.w) + { + } + + void swap (Vector4DModel &a, Vector4DModel &b) noexcept + { + std::swap (a.x, b.x); + std::swap (a.y, b.y); + std::swap (a.z, b.z); + std::swap (a.w, b.w); + } + + Vector4DModel & operator= (Vector4DModel other) noexcept + { + swap (*this, other); + + return *this; + } + + T x; + T y; + T z; + T w; + }; + + typedef Vector4DModel Vector4D; + + namespace dimension + { + template + struct Dimension > + { + typedef T data_type; + static const size_t dimensions = 4; + }; + + template + struct DimensionAccess , 0> + { + static inline T get (Vector4DModel const &p) + { + return p.x; + } + + static inline void + set (Vector4DModel &p, T const &value) + { + p.x = value; + } + }; + + template + struct DimensionAccess , 1> + { + static inline T get (Vector4DModel const &p) + { + return p.y; + } + + static inline void + set (Vector4DModel &p, T const &value) + { + p.y = value; + } + }; + + template + struct DimensionAccess , 2> + { + static inline T get (Vector4DModel const &p) + { + return p.z; + } + + static inline void + set (Vector4DModel &p, T const &value) + { + p.z = value; + } + }; + + template + struct DimensionAccess , 3> + { + static inline T get (Vector4DModel const &p) + { + return p.w; + } + + static inline void + set (Vector4DModel &p, T const &value) + { + p.w = value; + } + }; + } } /* Import animation::geometry::Point types into * animation namespace for compatibility. */ typedef animation::geometry::Point Point; typedef animation::geometry::Vector Vector; + typedef animation::geometry::Vector4D Vector4D; template using PointView = animation::geometry::PointView ; diff --git a/animation/geometry_traits.h b/animation/geometry_traits.h index 5791657..3b4e27b 100644 --- a/animation/geometry_traits.h +++ b/animation/geometry_traits.h @@ -377,5 +377,10 @@ namespace animation } } + template + inline bool operator== (T const &l, U const &r) + { + return dimension::equals (l, r); + } } } diff --git a/animation/glide/glide.cpp b/animation/glide/glide.cpp new file mode 100644 index 0000000..f4e4d49 --- /dev/null +++ b/animation/glide/glide.cpp @@ -0,0 +1,241 @@ +/* + * animation/glide/glide.cpp + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * An animation that causes a surface to glide onto screen, gently + * following an attenuating sine wave. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace agd = animation::geometry::dimension; +namespace abc = animation::box_calculation; +namespace ag = animation::glide; +namespace am = animation::math; +namespace atc = animation::transform_calculation; + +namespace +{ + inline float DegreesToRadians (float degrees) + { + return (M_PI / 180.0f) * degrees; + } + + /* This undoes perspective distortion */ + glm::mat4 CreatePerspectiveDistortionMatrix (unsigned int screenWidth) + { + float v = -1.0 / screenWidth; + + return glm::mat4 (glm::vec4 (1.0, 0.0, 0.0, 0.0), + glm::vec4 (0.0, 1.0, 0.0, 0.0), + glm::vec4 (0.0, 0.0, 0.0, 0.0), + glm::vec4 (0.0, 0.0, v, 1.0)); + } + + /* 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. */ + void ComputeGlideTransform (glm::mat4 &transform, + float progress, + float initialDistance, + float xRotationAngleDegrees, + float yRotationAngleDegrees, + float xAxisLocationUnit, + float yAxisLocationUnit, + unsigned int screenWidth, + animation::Box const &targetBox) + { + animation::Point rotationAxis (abc::ComputeRotationAxisOffset (targetBox, + xAxisLocationUnit, + yAxisLocationUnit)); + + auto centerMat = glm::translate (glm::mat4 (1.0f), + glm::vec3 (-1.0f * agd::get <0> (rotationAxis), + -1.0f * agd::get <1> (rotationAxis), + 0.0f)); + auto xRotationMat = glm::rotate (glm::mat4 (1.0f), + DegreesToRadians (xRotationAngleDegrees) * (1.0f - progress), + glm::vec3 (1.0f, 0.0f, 0.0f)); + auto yRotationMat = glm::rotate (glm::mat4 (1.0f), + DegreesToRadians (yRotationAngleDegrees) * (1.0f - progress), + glm::vec3 (0.0f, 1.0f, 0.0f)); + auto translationMat = glm::translate (glm::mat4 (1.0f), + glm::vec3 (0.0f, + 0.0f, + -1.0f * initialDistance * (1.0f - progress))); + auto invCenterMat = glm::translate (glm::mat4 (1.0f), + glm::vec3 (agd::get <0> (rotationAxis), + agd::get <1> (rotationAxis), + 0.0f)); + + transform = invCenterMat * + translationMat * + xRotationMat * + yRotationMat * + CreatePerspectiveDistortionMatrix (screenWidth) * + centerMat; + } +} + +namespace animation +{ + namespace glide + { + struct GlideAnimation::Private + { + Private (float initialDistance, + float xRotationAngleDegrees, + float yRotationAngleDegrees, + float xAxisLocationUnit, + float yAxisLocationUnit, + unsigned int screenWidth, + animation::Box const &target, + animation::stepper::Stepper const &stepper); + + float initialDistance; + float xRotationAngleDegrees; + float yRotationAngleDegrees; + float xAxisLocationUnit; + float yAxisLocationUnit; + unsigned int screenWidth; + animation::Box target; + + glm::mat4 transform; + float progress; + + animation::stepper::Stepper stepper; + }; + + GlideAnimation::Private::Private (float initialDistance, + float xRotationAngleDegrees, + float yRotationAngleDegrees, + float xAxisLocationUnit, + float yAxisLocationUnit, + unsigned int screenWidth, + animation::Box const &target, + animation::stepper::Stepper const &stepper) : + initialDistance (initialDistance), + xRotationAngleDegrees (xRotationAngleDegrees), + yRotationAngleDegrees (yRotationAngleDegrees), + xAxisLocationUnit (xAxisLocationUnit), + yAxisLocationUnit (yAxisLocationUnit), + screenWidth (screenWidth), + target (target), + transform (glm::mat4 (1.0)), + progress (stepper (0)), + stepper (stepper) + { + ComputeGlideTransform (transform, + progress, + initialDistance, + xRotationAngleDegrees, + yRotationAngleDegrees, + xAxisLocationUnit, + yAxisLocationUnit, + screenWidth, + target); + } + } +} + +std::array +ag::GlideAnimation::Extremes (std::array const &corners) const +{ + return std::array { + atc::TransformFlattened2DPointBy3DMatrix (corners[0], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[1], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[2], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[3], priv->transform) + }; +} + +float +ag::GlideAnimation::Progress () const +{ + return priv->progress; +} + +bool +ag::GlideAnimation::Step (unsigned int ms) +{ + priv->progress = am::clamp (priv->stepper (ms), 0.0f, 1.0f); + + ComputeGlideTransform (priv->transform, + priv->progress, + priv->initialDistance, + priv->xRotationAngleDegrees, + priv->yRotationAngleDegrees, + priv->xAxisLocationUnit, + priv->yAxisLocationUnit, + priv->screenWidth, + priv->target); + + return priv->progress != 0.0f && priv->progress != 1.0f; +} + +float * const +ag::GlideAnimation::Matrix () const +{ + return glm::value_ptr (priv->transform); +} + +ANIMATION_DEFINE_PROPERTY (ag::GlideAnimation, InitialDistance, float, priv->initialDistance) +ANIMATION_DEFINE_PROPERTY (ag::GlideAnimation, XRotationAngleDegrees, float, priv->xRotationAngleDegrees) +ANIMATION_DEFINE_PROPERTY (ag::GlideAnimation, YRotationAngleDegrees, float, priv->yRotationAngleDegrees) +ANIMATION_DEFINE_PROPERTY (ag::GlideAnimation, XAxisLocationUnit, float, priv->xAxisLocationUnit) +ANIMATION_DEFINE_PROPERTY (ag::GlideAnimation, YAxisLocationUnit, float, priv->yAxisLocationUnit) +ANIMATION_DEFINE_PROPERTY (ag::GlideAnimation, Stepper, animation::stepper::Stepper, priv->stepper) + +ag::GlideAnimation::GlideAnimation (float initialDistance, + float xRotationAngleDegrees, + float yRotationAngleDegrees, + float xAxisLocationUnit, + float yAxisLocationUnit, + unsigned int screenWidth, + animation::Box const &target, + animation::stepper::Stepper const &stepper) : + priv (new ag::GlideAnimation::Private (initialDistance, + xRotationAngleDegrees, + yRotationAngleDegrees, + xAxisLocationUnit, + yAxisLocationUnit, + screenWidth, + target, + stepper)) +{ +} + +ag::GlideAnimation::~GlideAnimation () +{ +} diff --git a/animation/glide/glide.h b/animation/glide/glide.h new file mode 100644 index 0000000..96a0d15 --- /dev/null +++ b/animation/glide/glide.h @@ -0,0 +1,70 @@ +/* + * animation/glide/glide.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * An animation that causes a surface to glide onto screen, gently + * following an attenuating sine wave. + */ + +#include +#include + +#include +#include +#include +#include + +#pragma once + +namespace animation +{ + namespace glide + { + class GlideAnimation : + public animation::transform::TransformAnimation + { + public: + + GlideAnimation (float initialDistance, + float xRotationAngleDegrees, + float yRotationAngleDegrees, + float xAxisLocationUnit, + float yAxisLocationUnit, + unsigned int screenWidth, + animation::Box const &target, + animation::stepper::Stepper const &stepper); + ~GlideAnimation (); + + float * const Matrix () const; + float Progress () const; + bool Step (unsigned int ms); + std::array Extremes (std::array const &corners) const; + + ANIMATION_DECLARE_PROPERTY (GlideAnimation, InitialDistance, float) + ANIMATION_DECLARE_PROPERTY (GlideAnimation, XRotationAngleDegrees, float) + ANIMATION_DECLARE_PROPERTY (GlideAnimation, YRotationAngleDegrees, float) + ANIMATION_DECLARE_PROPERTY (GlideAnimation, XAxisLocationUnit, float) + ANIMATION_DECLARE_PROPERTY (GlideAnimation, YAxisLocationUnit, float) + ANIMATION_DECLARE_PROPERTY (GlideAnimation, MaximumScale, float) + ANIMATION_DECLARE_PROPERTY (GlideAnimation, Stepper, animation::stepper::Stepper) + + private: + + struct Private; + std::unique_ptr priv; + }; + } +} diff --git a/animation/glide/meson.build b/animation/glide/meson.build new file mode 100644 index 0000000..5cf6104 --- /dev/null +++ b/animation/glide/meson.build @@ -0,0 +1,34 @@ +# /animation/glide/meson.build +# +# Toplevel meson build file for libanimation. +# +# Copyright (C) 2017, 2018 Endless Mobile, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Build the libanimation library (glide animation component). + +glide_sources = files([ + 'glide.cpp' +]) + +glide_headers = files([ + 'glide.h' +]) + +animation_sources += glide_sources +animation_headers += glide_headers + +install_headers(glide_headers, subdir: join_paths(animation_headers_subdir, 'glide')) diff --git a/animation/math.h b/animation/math.h new file mode 100644 index 0000000..d47ec9d --- /dev/null +++ b/animation/math.h @@ -0,0 +1,33 @@ +/* + * animation/math.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Math utility functions not availble elsewhere. + */ +#pragma once + +#include + +namespace animation +{ + namespace math + { + template T clamp (T const &value, T const &lower, T const &higher) + { + return std::fmin (higher, std::fmax (lower, value)); + } + } +} diff --git a/animation/meson.build b/animation/meson.build index 0a7d758..c13ca9a 100644 --- a/animation/meson.build +++ b/animation/meson.build @@ -24,14 +24,30 @@ animation_sources = [] animation_headers = [] animation_headers_subdir = 'animation' +subdir('bounce') +subdir('glide') +subdir('stepper') +subdir('transform') subdir('wobbly') +subdir('zoom') + +animation_toplevel_headers = files([ + 'box_calculation.h', + 'geometry.h', + 'geometry_traits.h', + 'math.h', + 'property.h', + 'transform_calculation.h' +]) + +animation_headers += animation_toplevel_headers animation_lib = shared_library( 'animation', animation_sources, soversion: api_version, install: true, - include_directories: [ animation_inc ] + include_directories: [ animation_inc, glm_inc ] ) animation_dep = declare_dependency( @@ -48,3 +64,5 @@ pkg.generate( libraries: animation_lib, install_dir: join_paths(get_option('libdir'), 'pkgconfig') ) + +install_headers(animation_toplevel_headers, subdir: animation_headers_subdir) diff --git a/animation/property.h b/animation/property.h new file mode 100644 index 0000000..b622dba --- /dev/null +++ b/animation/property.h @@ -0,0 +1,43 @@ +/* + * animation/property.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Properties that can be get and set, without a bunch of boilerplate. + */ + +#pragma once + +#define ANIMATION_DECLARE_READONLY_PROPERTY(klass, name, type) \ + type const & name () const ; + +#define ANIMATION_DEFINE_READONLY_PROPERTY(qualifier, name, type, location) \ + type const & qualifier::name() const \ + { \ + return location; \ + } + +#define ANIMATION_DECLARE_PROPERTY(klass, name, type) \ + ANIMATION_DECLARE_READONLY_PROPERTY(klass, name, type) \ + klass & name (type const &v); + +#define ANIMATION_DEFINE_PROPERTY(qualifier, name, type, location) \ + ANIMATION_DEFINE_READONLY_PROPERTY(qualifier, name, type, location) \ + qualifier & qualifier::name(type const &v) \ + { \ + location = v; \ + return *this; \ + } + diff --git a/animation/stepper/linear.h b/animation/stepper/linear.h new file mode 100644 index 0000000..a18096d --- /dev/null +++ b/animation/stepper/linear.h @@ -0,0 +1,41 @@ +/* + * animation/stepper/linear.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Definition for a linear stepping function - just adds to progress + * according to how long the animation is. + */ + +#include + +#pragma once + +namespace animation +{ + namespace stepper + { + inline std::function Linear (float length) { + float progress = 0.0; + + return [=](unsigned int ms) mutable -> float { + progress += ms / length; + return progress; + }; + } + } +} diff --git a/animation/stepper/meson.build b/animation/stepper/meson.build new file mode 100644 index 0000000..771d9f1 --- /dev/null +++ b/animation/stepper/meson.build @@ -0,0 +1,31 @@ +# /animation/stepper/meson.build +# +# Meson build file for libanimation stepper functions. +# +# Copyright (C) 2017, 2018 Endless Mobile, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Build the libanimation library (stepper animation component). + +stepper_headers = files([ + 'linear.h', + 'reverse.h', + 'stepper.h' +]) + +animation_headers += stepper_headers + +install_headers(stepper_headers, subdir: join_paths(animation_headers_subdir, 'stepper')) diff --git a/animation/stepper/reverse.h b/animation/stepper/reverse.h new file mode 100644 index 0000000..5deaaad --- /dev/null +++ b/animation/stepper/reverse.h @@ -0,0 +1,42 @@ +/* + * animation/stepper/reverse.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Definition for a reverse stepping function. Takes another stepping + * function and inverts its output. + */ + +#include + +#include + +#pragma once + +namespace animation +{ + namespace stepper + { + inline std::function Reverse (Stepper &&step) { + Stepper localStepper (std::move (step)); + + return [=](unsigned int ms) mutable -> float { + return 1.0f - localStepper (ms); + }; + } + } +} diff --git a/animation/stepper/stepper.h b/animation/stepper/stepper.h new file mode 100644 index 0000000..bcedac6 --- /dev/null +++ b/animation/stepper/stepper.h @@ -0,0 +1,35 @@ +/* + * animation/stepper/stepper.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Definition for a stepping function, taking an unsigned int of + * milliseconds passed and returning a floating point number + * between 0.0 and 1.0. + */ + +#include + +#pragma once + +namespace animation +{ + namespace stepper + { + typedef std::function Stepper; + } +} diff --git a/animation/third_party/glm b/animation/third_party/glm new file mode 160000 index 0000000..fe7c7b5 --- /dev/null +++ b/animation/third_party/glm @@ -0,0 +1 @@ +Subproject commit fe7c7b5ac15ba8d5c9c45984831dc2e830726b33 diff --git a/animation/transform/meson.build b/animation/transform/meson.build new file mode 100644 index 0000000..eb9d690 --- /dev/null +++ b/animation/transform/meson.build @@ -0,0 +1,13 @@ +# /animation/wobbly/meson.build +# +# Build the libanimation library (transform animation base class component). +# +# See /LICENCE.md for Copyright information. + +transform_headers = files([ + 'transform.h' +]) + +animation_headers += transform_headers + +install_headers(transform_headers, subdir: join_paths(animation_headers_subdir, 'transform')) diff --git a/animation/transform/transform.h b/animation/transform/transform.h new file mode 100644 index 0000000..f35acf5 --- /dev/null +++ b/animation/transform/transform.h @@ -0,0 +1,45 @@ +/* + * animation/transform/transform.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Interface definition for animations that output + * an affine transformation (4x4) for a 2D surface. + */ + +#include + +#include + +#pragma once + +namespace animation +{ + namespace transform + { + class TransformAnimation + { + public: + + virtual ~TransformAnimation() {}; + virtual float * const Matrix () const = 0; + virtual float Progress () const = 0; + virtual bool Step (unsigned int ms) = 0; + virtual std::array Extremes (std::array const &corners) const = 0; + }; + } +} diff --git a/animation/transform_calculation.h b/animation/transform_calculation.h new file mode 100644 index 0000000..41f7b6d --- /dev/null +++ b/animation/transform_calculation.h @@ -0,0 +1,39 @@ +/* + * animation/transform_calculation.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Utility functions with some helpful matrix transforms. + */ +#pragma once + +#include + +#include + +namespace animation +{ + namespace transform_calculation + { + inline animation::Vector4D TransformFlattened2DPointBy3DMatrix (animation::Point const &p, + glm::mat4 const &matrix) + { + namespace agd = animation::geometry::dimension; + + glm::vec4 t (matrix * glm::vec4 (agd::get <0> (p), agd::get <1> (p), 0.0, 1.0)); + return animation::Vector4D (t[0], t[1], t[2], t[3]); + } + } +} diff --git a/animation/zoom/meson.build b/animation/zoom/meson.build new file mode 100644 index 0000000..598b4b6 --- /dev/null +++ b/animation/zoom/meson.build @@ -0,0 +1,34 @@ +# /animation/zoom/meson.build +# +# Toplevel meson build file for libanimation. +# +# Copyright (C) 2017, 2018 Endless Mobile, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Build the libanimation library (zoom animation component). + +zoom_sources = files([ + 'zoom.cpp' +]) + +zoom_headers = files([ + 'zoom.h' +]) + +animation_sources += zoom_sources +animation_headers += zoom_headers + +install_headers(zoom_headers, subdir: join_paths(animation_headers_subdir, 'zoom')) diff --git a/animation/zoom/zoom.cpp b/animation/zoom/zoom.cpp new file mode 100644 index 0000000..ddc90e6 --- /dev/null +++ b/animation/zoom/zoom.cpp @@ -0,0 +1,213 @@ +/* + * animation/zoom/zoom.cpp + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Animation that causes a surface to zoom from one rectangle to another. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace agd = animation::geometry::dimension; +namespace abc = animation::box_calculation; +namespace am = animation::math; +namespace atc = animation::transform_calculation; +namespace az = animation::zoom; + +namespace +{ + animation::Box EnsureNonZeroArea (animation::Box const &box) + { + auto const &topLeft = box.topLeft(); + auto const &bottomRight = box.bottomRight(); + auto x1 = agd::get <0> (topLeft); + auto y1 = agd::get <1> (topLeft); + auto x2 = agd::get <0> (bottomRight); + auto y2 = agd::get <1> (bottomRight); + + return animation::Box (animation::Point (x1, y1), + animation::Point (x2 == x1 ? x2 + 1 : x2, + y2 == y1 ? y2 + 1 : y2)); + } + + /* 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. */ + void ComputeZoomTransform (glm::mat4 &transform, + float progress, + animation::Box const &from, + animation::Box const &to) + { + animation::Point const &fromTopLeft (from.topLeft ()); + animation::Point const &fromBottomRight (from.bottomRight ()); + animation::Point const &toTopLeft (to.topLeft ()); + animation::Point const &toBottomRight (to.bottomRight ()); + + auto fromWidth = agd::get <0> (fromBottomRight) - agd::get <0> (fromTopLeft); + auto fromHeight = agd::get <1> (fromBottomRight) - agd::get <1> (fromTopLeft); + + auto toWidth = agd::get <0> (toBottomRight) - agd::get <0> (toTopLeft); + auto toHeight = agd::get <1> (toBottomRight) - agd::get <1> (toTopLeft); + + animation::Point fromCenter (abc::ComputeBoxCenter (from)); + animation::Point toCenter (abc::ComputeBoxCenter (to)); + animation::Point toCenterOffset (abc::ComputeBoxCenterOffset (to)); + + /* Translate backwards from "to" to "from" according to the inverse of progress + * (eg, at progress == 1.0, there will be no translation from the natural point + * but at progress == 0.0 we translate all the way back from "to" to "from"). */ + animation::Point translation ((agd::get <0> (fromCenter) - agd::get <0> (toCenter)) * (1.0f - progress), + (agd::get <1> (fromCenter) - agd::get <1> (toCenter)) * (1.0f - progress)); + + /* Interpolate between the source and destination width */ + animation::Point scaleFactor (((toWidth * progress) + (fromWidth * (1.0 - progress))) / + toWidth, + ((toHeight * progress) + (fromHeight * (1.0 - progress))) / + toHeight); + + animation::Point invScaleFactor (1.0 / agd::get <0> (scaleFactor), + 1.0 / agd::get <1> (scaleFactor)); + + /* Remember that transformation are done back to front when postmultiplying. + * + * So we translate to the center first, then scale, then undo the translation + * then translate to the correct point along the animation. */ + auto centerMat = glm::translate (glm::mat4 (1.0), + glm::vec3 (-1.0 * agd::get <0> (toCenterOffset), + -1.0 * agd::get <1> (toCenterOffset), + 0.0)); + auto scaleMat = glm::scale (glm::mat4 (1.0), + glm::vec3 (agd::get <0> (scaleFactor), + agd::get <1> (scaleFactor), + 1.0)); + auto invCenterMat = glm::translate (glm::mat4 (1.0), + glm::vec3 (agd::get <0> (toCenterOffset), + agd::get <1> (toCenterOffset), + 0.0)); + auto translationMat = glm::translate (glm::mat4 (1.0), + glm::vec3 (agd::get <0> (translation), + agd::get <1> (translation), + 0.0)); + + transform = translationMat * invCenterMat * scaleMat * centerMat; + } +} + +namespace animation +{ + namespace zoom + { + struct ZoomAnimation::Private + { + Private (animation::Box const &from, + animation::Box const &to, + animation::stepper::Stepper const &stepper); + + animation::Box from; + animation::Box to; + + glm::mat4 transform; + float progress; + + animation::stepper::Stepper stepper; + }; + + ZoomAnimation::Private::Private (animation::Box const &from, + animation::Box const &to, + animation::stepper::Stepper const &stepper) : + from (EnsureNonZeroArea (from)), + to (EnsureNonZeroArea (to)), + transform (glm::mat4 (1.0)), + progress (stepper (0)), + stepper (stepper) + { + ComputeZoomTransform (transform, + progress, + this->from, + this->to); + } + } +} + +std::array +az::ZoomAnimation::Extremes (std::array const &corners) const +{ + return std::array { + atc::TransformFlattened2DPointBy3DMatrix (corners[0], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[1], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[2], priv->transform), + atc::TransformFlattened2DPointBy3DMatrix (corners[3], priv->transform) + }; +} + +float +az::ZoomAnimation::Progress () const +{ + return priv->progress; +} + +bool +az::ZoomAnimation::Step (unsigned int ms) +{ + priv->progress = am::clamp (priv->stepper (ms), 0.0f, 1.0f); + + ComputeZoomTransform (priv->transform, + priv->progress, + priv->from, + priv->to); + + return priv->progress != 0.0f && priv->progress != 1.0f; +} + +float * const +az::ZoomAnimation::Matrix () const +{ + return glm::value_ptr (priv->transform); +} + +ANIMATION_DEFINE_PROPERTY (az::ZoomAnimation, From, animation::Box , priv->from) +ANIMATION_DEFINE_READONLY_PROPERTY (az::ZoomAnimation, To, animation::Box , priv->to) +ANIMATION_DEFINE_PROPERTY (az::ZoomAnimation, Stepper, animation::stepper::Stepper, priv->stepper) + +az::ZoomAnimation::ZoomAnimation (animation::Box const &from, + animation::Box const &to, + animation::stepper::Stepper const &stepper) : + priv (new az::ZoomAnimation::Private (from, to, stepper)) +{ +} + +az::ZoomAnimation::~ZoomAnimation () +{ +} diff --git a/animation/zoom/zoom.h b/animation/zoom/zoom.h new file mode 100644 index 0000000..39328c1 --- /dev/null +++ b/animation/zoom/zoom.h @@ -0,0 +1,60 @@ +/* + * animation/zoom/zoom.h + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Animation that causes a surface to zoom from one rectangle to another. + */ + +#include +#include + +#include +#include +#include +#include + +#pragma once + +namespace animation +{ + namespace zoom + { + class ZoomAnimation : + public animation::transform::TransformAnimation + { + public: + + ZoomAnimation (animation::Box const &from, + animation::Box const &to, + animation::stepper::Stepper const &stepper); + ~ZoomAnimation (); + + float * const Matrix () const; + float Progress () const; + bool Step (unsigned int ms); + std::array Extremes (std::array const &corners) const; + + ANIMATION_DECLARE_PROPERTY (ZoomAnimation, From, animation::Box ) + ANIMATION_DECLARE_READONLY_PROPERTY (ZoomAnimation, To, animation::Box ) + ANIMATION_DECLARE_PROPERTY (ZoomAnimation, Stepper, animation::stepper::Stepper) + + private: + + struct Private; + std::unique_ptr priv; + }; + } +} diff --git a/matchers/mathematical_model_matcher.h b/matchers/mathematical_model_matcher.h index f3f74e1..01fc3f9 100644 --- a/matchers/mathematical_model_matcher.h +++ b/matchers/mathematical_model_matcher.h @@ -445,6 +445,59 @@ namespace animation namespace t = ::testing; namespace agd = ::animation::geometry::dimension; + template + struct AlmostEqTrait + { + typedef T ValueType; + + template + static bool apply (T const &lhs, + T const &rhs, + Comparator &&comparator) + { + return comparator (lhs, rhs); + } + }; + + template + class AlmostEqMatcher : + public t::MatcherInterface + { + public: + + AlmostEqMatcher (T const &value, float tolerance) : + value (value), + tolerance (tolerance) + { + } + + bool MatchAndExplain (T const &x, + t::MatchResultListener *listener) const + { + using namespace std::placeholders; + auto func = animation::testing::close_at_tolerance ::ValueType, typename AlmostEqTrait ::ValueType, typename AlmostEqTrait ::ValueType>; + return AlmostEqTrait ::apply (x, + value, + std::bind (func, _1, _2, tolerance)); + } + + void DescribeTo (std::ostream *os) const + { + *os << "almost equal to " << value << " (at tolerance " << tolerance << ")"; + } + + private: + + T value; + float tolerance; + }; + + template + t::Matcher AlmostEq (T const &value, float tolerance) + { + return t::MakeMatcher (new AlmostEqMatcher (value, tolerance)); + } + template class GeometricallyEqualMatcher : public t::MatcherInterface diff --git a/meson.build b/meson.build index aeb4227..dd3cb05 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,7 @@ if not gtest_dep.found() or not gtest_main_dep.found() or not gmock_dep.found() endif animation_inc = include_directories('.') +glm_inc = include_directories(join_paths('animation', 'third_party', 'glm')) tests_inc = include_directories('tests') subdir('animation') diff --git a/tests/bounce/bounce_animation_test.cpp b/tests/bounce/bounce_animation_test.cpp new file mode 100644 index 0000000..88558f5 --- /dev/null +++ b/tests/bounce/bounce_animation_test.cpp @@ -0,0 +1,204 @@ +/* + * tests/wobbly/bounce_animation_test.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Tests for the "bounce" animation. + */ +#include // for size_t +#include // for bind, __bind, _1 + +#include +#include +#include + +#include // for AtLeast +#include // for FunctionMocker, etc +#include // for AnythingMatcher, etc +#include // for EXPECT_CALL, etc +#include // for TEST_F, Test, Types, etc + +#include +#include +#include +#include + +#include + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Eq; +using ::testing::Test; + +namespace ab = animation::bounce; +namespace abc = animation::box_calculation; +namespace agd = animation::geometry::dimension; +namespace as = animation::stepper; + +namespace +{ + TEST (BounceAnimation, AnimationIncompleteBeforeLengthTimesteps) + { + ab::BounceAnimation anim (0.7f, + 1.5f, + 1, + animation::Box (animation::Point (0, 0), + animation::Point (100, 100)), + as::Linear (200)); + + EXPECT_TRUE (anim.Step (199)); + } + + TEST (BounceAnimation, AnimationCompleteAtLengthTimesteps) + { + ab::BounceAnimation anim (0.7f, + 1.5f, + 1, + animation::Box (animation::Point (0, 0), + animation::Point (100, 100)), + as::Linear (200)); + + EXPECT_FALSE (anim.Step (200)); + } + + TEST (BounceAnimation, AnimationStopsAtTargetBox) + { + auto target = animation::Box (animation::Point (100, 100), + animation::Point (200, 200)); + ab::BounceAnimation anim (0.7f, + 1.5f, + 1, + target, + as::Linear (200)); + + anim.Step (200); + + /* Apply to a shape at (0, 0) which is translated to (100, 100) */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (100, 100, 0))); + glm::vec4 tl (0, 0, 0, 1); + glm::vec4 br (100, 100, 0, 1); + + /* Apply transformation matrix to vectors */ + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should finish at target box */ + EXPECT_THAT (translation * transformation * tl, + Eq (glm::vec4 (agd::get <0> (target.topLeft ()), + agd::get <1> (target.topLeft ()), + 0, + 1))); + EXPECT_THAT (translation * transformation * br, + Eq (glm::vec4 (agd::get <0> (target.bottomRight ()), + agd::get <1> (target.bottomRight ()), + 0, + 1))); + } + + TEST (BounceAnimation, AnimationStartsAtTargetBoxScaledByInitialScale) + { + auto target = animation::Box (animation::Point (100, 100), + animation::Point (200, 200)); + auto width = 100.0f; + auto height = 100.0f; + auto initialScale = 0.5f; + ab::BounceAnimation anim (initialScale, + 1.5f, + 1, + target, + as::Linear (200)); + + animation::Point boxCenter (abc::ComputeBoxCenter (target)); + + animation::Box scaledBox ( + animation::Point (agd::get <0> (boxCenter) - (width / 2.0f) * initialScale, + agd::get <1> (boxCenter) - (height / 2.0f) * initialScale), + animation::Point (agd::get <0> (boxCenter) + (width / 2.0f) * initialScale, + agd::get <1> (boxCenter) + (height / 2.0f) * initialScale) + ); + + /* Apply to a shape at (0, 0) which is translated to (100, 100) */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (100, 100, 0))); + glm::vec4 tl (0, 0, 0, 1); + glm::vec4 br (100, 100, 0, 1); + + /* Apply transformation matrix to vectors */ + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should finish at target box */ + EXPECT_THAT (translation * transformation * tl, + Eq (glm::vec4 (agd::get <0> (scaledBox.topLeft ()), + agd::get <1> (scaledBox.topLeft ()), + 0, + 1))); + EXPECT_THAT (translation * transformation * br, + Eq (glm::vec4 (agd::get <0> (scaledBox.bottomRight ()), + agd::get <1> (scaledBox.bottomRight ()), + 0, + 1))); + } + + TEST (BounceAnimation, AtHalfwayPointBounceIsAtHighestAttenuatedScale) + { + auto target = animation::Box (animation::Point (100, 100), + animation::Point (200, 200)); + auto width = 100.0f; + auto height = 100.0f; + auto initialScale = 0.5f; + auto maximumScale = 1.5f; + auto progress = 0.5; + auto scaleFloor = (1.0f - initialScale) * progress; + + /* At 0.5f progress, we are at the top of the sine wave, so + * add that to the scale floor. */ + auto expectedScale = scaleFloor + (maximumScale - initialScale); + ab::BounceAnimation anim (initialScale, + maximumScale, + 1, + target, + as::Linear (200)); + anim.Step (100); + + animation::Point boxCenter (abc::ComputeBoxCenter (target)); + + animation::Box scaledBox ( + animation::Point (agd::get <0> (boxCenter) - (width / 2.0f) * expectedScale, + agd::get <1> (boxCenter) - (height / 2.0f) * expectedScale), + animation::Point (agd::get <0> (boxCenter) + (width / 2.0f) * expectedScale, + agd::get <1> (boxCenter) + (height / 2.0f) * expectedScale) + ); + + /* Apply to a shape at (0, 0) which is translated to (100, 100) */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (100, 100, 0))); + glm::vec4 tl (0, 0, 0, 1); + glm::vec4 br (100, 100, 0, 1); + + /* Apply transformation matrix to vectors */ + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should finish at target box */ + EXPECT_THAT (translation * transformation * tl, + Eq (glm::vec4 (agd::get <0> (scaledBox.topLeft ()), + agd::get <1> (scaledBox.topLeft ()), + 0, + 1))); + EXPECT_THAT (translation * transformation * br, + Eq (glm::vec4 (agd::get <0> (scaledBox.bottomRight ()), + agd::get <1> (scaledBox.bottomRight ()), + 0, + 1))); + } +} diff --git a/tests/glide/glide_animation_test.cpp b/tests/glide/glide_animation_test.cpp new file mode 100644 index 0000000..1359ead --- /dev/null +++ b/tests/glide/glide_animation_test.cpp @@ -0,0 +1,181 @@ +/* + * tests/wobbly/glide_animation_test.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Tests for the "glide" animation. + */ +#include // for size_t +#include // for bind, __bind, _1 + +#include +#include +#include + +#include // for AtLeast +#include // for FunctionMocker, etc +#include // for AnythingMatcher, etc +#include // for EXPECT_CALL, etc +#include // for TEST_F, Test, Types, etc + +#include +#include +#include + +#include +#include + +using ::animation::matchers::AlmostEq; +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Eq; +using ::testing::Not; +using ::testing::Test; + +namespace agd = animation::geometry::dimension; +namespace ag = animation::glide; +namespace as = animation::stepper; + +namespace animation +{ + namespace matchers + { + template <> + struct AlmostEqTrait + { + typedef float ValueType; + + template + static bool apply (glm::vec4 const &lhs, + glm::vec4 const &rhs, + Comparator &&comparator) + { + return comparator (lhs[0], rhs[0]) && + comparator (lhs[1], rhs[1]) && + comparator (lhs[2], rhs[2]) && + comparator (lhs[3], rhs[3]); + } + }; + } +} + +namespace +{ + static const unsigned int MockScreenWidth = 1000; + + TEST (GlideAnimation, AnimationIncompleteBeforeLengthTimesteps) + { + ag::GlideAnimation anim (0.5f, + 0.0f, + 20.0f, + 0.5f, + 0.0f, + 1000, + animation::Box (animation::Point (0, 0), + animation::Point (100, 100)), + as::Linear (200)); + + EXPECT_TRUE (anim.Step (199)); + } + + TEST (GlideAnimation, AnimationCompleteAtLengthTimesteps) + { + ag::GlideAnimation anim (0.5f, + 0.0f, + 20.0f, + 0.5f, + 0.0f, + 1000, + animation::Box (animation::Point (0, 0), + animation::Point (100, 100)), + as::Linear (200)); + + EXPECT_FALSE (anim.Step (200)); + } + + TEST (GlideAnimation, AnimationStopsAtTargetBox) + { + auto target = animation::Box (animation::Point (100, 100), + animation::Point (200, 200)); + ag::GlideAnimation anim (0.5f, + 0.0f, + 20.0f, + 0.5f, + 0.0f, + 1000, + target, + as::Linear (200)); + + anim.Step (200); + + /* Apply to a shape at (0, 0) which is translated to (100, 100) */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (100, 100, 0))); + glm::vec4 tl (translation * glm::vec4 (0, 0, 0, 1)); + glm::vec4 br (translation * glm::vec4 (100, 100, 0, 1)); + + /* Apply transformation matrix to vectors */ + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should finish at target box */ + EXPECT_THAT (transformation * tl, + AlmostEq (glm::vec4 (agd::get <0> (target.topLeft ()), + agd::get <1> (target.topLeft ()), + 0, + 1), + 0.002)); + EXPECT_THAT (transformation * br, + AlmostEq (glm::vec4 (agd::get <0> (target.bottomRight ()), + agd::get <1> (target.bottomRight ()), + 0, + 1), + 0.002)); + } + + TEST (GlideAnimation, AnimationDoesNotStartAtTargetBox) + { + auto target = animation::Box (animation::Point (100, 100), + animation::Point (200, 200)); + ag::GlideAnimation anim (0.5f, + 0.0f, + 20.0f, + 0.5f, + 0.0f, + 1000, + target, + as::Linear (200)); + + /* Apply to a shape at (0, 0) which is translated to (100, 100) */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (100, 100, 0))); + glm::vec4 tl (translation * glm::vec4 (0, 0, 0, 1)); + glm::vec4 br (translation * glm::vec4 (100, 100, 0, 1)); + + /* Apply transformation matrix to vectors */ + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should finish at target box */ + EXPECT_THAT (transformation * tl, + Not (Eq (glm::vec4 (agd::get <0> (target.topLeft ()), + agd::get <1> (target.topLeft ()), + 0, + 1)))); + EXPECT_THAT (transformation * br, + Not (Eq (glm::vec4 (agd::get <0> (target.bottomRight ()), + agd::get <1> (target.bottomRight ()), + 0, + 1)))); + } +} diff --git a/tests/glm_ostream_operators.h b/tests/glm_ostream_operators.h new file mode 100644 index 0000000..c3e7832 --- /dev/null +++ b/tests/glm_ostream_operators.h @@ -0,0 +1,66 @@ +/* + * tests/glm_ostream_operators.h + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * A simple helper to output the contents of glm types when + * tests fail. + */ +#pragma once + +#include +#include // for operator<<, setprecision +#include // for ostream +#include // for basic_ostream, char_traits, etc + +namespace +{ + namespace detail + { + template + struct ArrayDimensionPrinter + { + static std::ostream & Apply (std::ostream &lhs, + T const &array) + { + ArrayDimensionPrinter ::Apply (lhs, array); + return lhs << ", " << array[D]; + } + }; + + template + struct ArrayDimensionPrinter + { + static std::ostream & Apply (std::ostream &lhs, + T const &array) + { + return lhs << array[0]; + } + }; + } +} + +namespace glm +{ + inline std::ostream & operator<< (std::ostream &lhs, + glm::vec4 const &vector) + { + lhs << "vec4("; + ::detail::ArrayDimensionPrinter ::Apply (lhs, vector); + return lhs << ")"; + } +} diff --git a/tests/meson.build b/tests/meson.build index 9d59aa9..b4111aa 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -19,6 +19,9 @@ # Build the libanimation unit tests. animation_test_sources = [ + 'bounce/bounce_animation_test.cpp', + 'glide/glide_animation_test.cpp', + 'glm_ostream_operators.h', 'ostream_point_operator.h', 'wobbly/anchor_test.cpp', 'wobbly/constrainment_test.cpp', @@ -27,7 +30,8 @@ animation_test_sources = [ 'wobbly/mesh_interpolation_test.cpp', 'wobbly/model_test.cpp', 'wobbly/point_test.cpp', - 'wobbly/spring_test.cpp' + 'wobbly/spring_test.cpp', + 'zoom/zoom_animation_test.cpp' ] glib = dependency('glib-2.0') @@ -47,7 +51,7 @@ animation_test_executable = executable( animation_dep, animation_glib_dep ], - include_directories: [ tests_inc ] + include_directories: [ glm_inc, tests_inc ] ) test('animation_test', animation_test_executable) diff --git a/tests/ostream_point_operator.h b/tests/ostream_point_operator.h index a2cac5b..9705f2f 100644 --- a/tests/ostream_point_operator.h +++ b/tests/ostream_point_operator.h @@ -54,5 +54,21 @@ namespace animation agd::assign (point, p); return lhs << point; } + + inline std::ostream & + operator<< (std::ostream &lhs, Vector4D const &p) + { + namespace agd = animation::geometry::dimension; + + return lhs << std::setprecision (10) + << "x: " + << agd::get <0> (p) + << " y: " + << agd::get <1> (p) + << " z: " + << agd::get <2> (p) + << " w: " + << agd::get <3> (p); + } } } diff --git a/tests/zoom/zoom_animation_test.cpp b/tests/zoom/zoom_animation_test.cpp new file mode 100644 index 0000000..53ca387 --- /dev/null +++ b/tests/zoom/zoom_animation_test.cpp @@ -0,0 +1,167 @@ +/* + * tests/wobbly/zoom_animation_test.cpp + * + * Copyright 2018 Endless Mobile, Inc. + * + * libanimation is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * libanimation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with eos-companion-app-service. If not, see + * . + * + * Tests for the the zoom animation. + */ +#include // for size_t +#include // for bind, __bind, _1 + +#include +#include +#include + +#include // for AtLeast +#include // for FunctionMocker, etc +#include // for AnythingMatcher, etc +#include // for EXPECT_CALL, etc +#include // for TEST_F, Test, Types, etc + +#include +#include +#include + +#include +#include +#include +#include + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Eq; +using ::testing::Test; + +namespace am = animation::matchers; +namespace as = animation::stepper; +namespace az = animation::zoom; + +namespace +{ + TEST (ZoomAnimation, AnimationIncompleteBeforeLengthTimesteps) + { + az::ZoomAnimation anim (animation::Box (animation::Point (0, 0), + animation::Point (100, 100)), + animation::Box (animation::Point (100, 100), + animation::Point (200, 200)), + as::Linear (200)); + + EXPECT_TRUE (anim.Step (199)); + } + + TEST (ZoomAnimation, AnimationCompleteAfterLengthTimesteps) + { + az::ZoomAnimation anim (animation::Box (animation::Point (0, 0), + animation::Point (100, 100)), + animation::Box (animation::Point (100, 100), + animation::Point (200, 200)), + as::Linear (200)); + + EXPECT_FALSE (anim.Step (200)); + } + + TEST (ZoomAnimation, AnimatesToCorrectPositionAfterLengthTimesteps) + { + az::ZoomAnimation anim (animation::Box (animation::Point (100, 100), + animation::Point (200, 200)), + animation::Box (animation::Point (200, 200), + animation::Point (300, 300)), + as::Linear (200)); + anim.Step (200); + + /* Apply to a shape at (0, 0) */ + glm::vec4 tl (0, 0, 0, 1); + glm::vec4 br (100, 100, 0, 1); + + /* Apply transformation matrix to vectors, with existing + * translation to scene position */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (200, 200, 0))); + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should be about halfway */ + EXPECT_THAT (translation * transformation * tl, Eq (translation * tl)); + EXPECT_THAT (translation * transformation * br, Eq (translation * br)); + } + + TEST (ZoomAnimation, AnimatesToCorrectReversePositionAfterLengthTimesteps) + { + az::ZoomAnimation anim (animation::Box (animation::Point (100, 100), + animation::Point (150, 150)), + animation::Box (animation::Point (200, 200), + animation::Point (300, 300)), + as::Reverse (as::Linear (200))); + anim.Step (200); + + /* Apply to a shape at (0, 0) */ + glm::vec4 tl (0, 0, 0, 1); + glm::vec4 br (100, 100, 0, 1); + + /* Apply transformation matrix to vectors, with existing + * translation to scene position */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (200, 200, 0))); + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + EXPECT_THAT (translation * transformation * tl, Eq (glm::vec4 (100, 100, 0, 1))); + EXPECT_THAT (translation * transformation * br, Eq (glm::vec4 (150, 150, 0, 1))); + } + + TEST (ZoomAnimation, StartsAtCorrectPositionAtZeroTimesteps) + { + az::ZoomAnimation anim (animation::Box (animation::Point (100, 100), + animation::Point (200, 200)), + animation::Box (animation::Point (200, 200), + animation::Point (300, 300)), + as::Linear (200)); + + /* Apply to a shape at (0, 0) */ + glm::vec4 tl (0, 0, 0, 1); + glm::vec4 br (100, 100, 0, 1); + + /* Apply transformation matrix to vectors, with existing + * translation to scene position */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (200, 200, 0))); + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should be about halfway */ + EXPECT_THAT (translation * transformation * tl, Eq (glm::vec4 (100, 100, 0, 1))); + EXPECT_THAT (translation * transformation * br, Eq (glm::vec4 (200, 200, 0, 1))); + } + + TEST (ZoomAnimation, AtCorrectPositionAfterHalfwayPoint) + { + az::ZoomAnimation anim (animation::Box (animation::Point (100, 100), + animation::Point (200, 200)), + animation::Box (animation::Point (200, 200), + animation::Point (300, 300)), + as::Linear (200)); + + anim.Step (100); + + /* Apply to a shape at (0, 0) */ + glm::vec4 tl (0, 0, 0, 1); + glm::vec4 br (100, 100, 0, 1); + + /* Apply transformation matrix to vectors, with existing + * translation to scene position */ + glm::mat4 translation (glm::translate (glm::mat4 (1.0), glm::vec3 (200, 200, 0))); + glm::mat4 transformation (glm::make_mat4x4 (anim.Matrix ())); + + /* Should be about halfway */ + EXPECT_THAT (translation * transformation * tl, Eq (glm::vec4 (150, 150, 0, 1))); + EXPECT_THAT (translation * transformation * br, Eq (glm::vec4 (250, 250, 0, 1))); + } +}