CompositionProToolkit v0.6 Released!

cpt_banner

Well, it has been almost 6 months since my last post. I have been busy working on a few apps and learning a few new technologies. In the meantime, Windows 10 Creators update was released, Build 2017 happened and Microsoft introduced the Fluent Design System (a much needed feature for Windows 10 UX). The Windows Composition team also open sourced the Expression Builder code which allows you to define the expressions in ExpressionAnimations in a more intuitive way.

A couple of weeks ago, I felt it was time to revisit my code in CompositionProToolkit and update it to the latest Windows SDK features. CompositionProToolkit version 0.5.x releases were more biased towards Win2d. So I decided to dedicate version 0.6 to the CompositionProToolkit.Expressions namespace.

cpte_banner

I had a look at the Expression Builder code to understand its features. It helps the developers to create type-safe expressions using ExpressionNode (and its derivatives). I was wondering if there was a way to modify the authoring feature in such a way that the ExpressionNode (and its derivatives) remain hidden from view to the developer and s/he may use a more simpler way to specify the expression with type-safety (using Lambda expressions).

It was then I realized the code in CompositionProToolkit.Expressions namespace did not support creation of expression templates.

I realized that there was a huge scope of improvement in the CompositionProToolkit.Expressions namespace and it was possible to introduce templates within the lambda expressions.

Thus, I am happy to announce that with the release of CompositionProToolkit v0.6, Expression parsing is more robust now. A lot of extension methods have been added to help the developer minimize the code written to create animations.

Defining the ExpressionAnimation and KeyFrameAnimation

The following extension methods have been defined on the Compositor to create the appropriate ExpressionAnimation object.

public static ExpressionAnimation CreateColorExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateQuaternionExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateScalarExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateVector2ExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateVector3ExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateVector4ExpressionAnimation(this Compositor compositor);
public static ExpressionAnimation CreateMatrix4x4ExpressionAnimation(this Compositor compositor);

The following extension method is defined for the Compositor to create a KeyFrameAnimation object for the appropriate animating property

public static KeyFrameAnimation GenerateColorKeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateQuaternionKeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateScalarKeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateVector2KeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateVector3KeyFrameAnimation(this Compositor compositor);
public static KeyFrameAnimation GenerateVector4KeyFrameAnimation(this Compositor compositor);

After creating the ExpressionAnimation object you can set its Expression property with the appropriate Expression.

The following extension methods allow StartAnimation to be called directly using an ExpressionAnimation or a KeyFrameAnimation object.

public static void StartAnimation(this CompositionObject compositionObject,
    Expression expression, KeyFrameAnimation keyframeAnimation);
public static void StartAnimation(this CompositionObject compositionObject,
    Expression expression, ExpressionAnimation expressionAnimation);

Using CompositionPropertySet within the Expression

In order to use a CompositionPropertySet within the Expression the following GetXXX extension methods have been defined

public static bool GetBoolean(this CompositionPropertySet propertySet, string key);
public static Color GetColor(this CompositionPropertySet propertySet, string key);
public static Matrix3x2 GetMatrix3x2(this CompositionPropertySet propertySet, string key);
public static Matrix4x4 GetMatrix4x4(this CompositionPropertySet propertySet, string key);
public static Quaternion GetQuaternion(this CompositionPropertySet propertySet, string key);
public static float GetScalar(this CompositionPropertySet propertySet, string key);
public static Vector2 GetVector2(this CompositionPropertySet propertySet, string key);
public static Vector3 GetVector3(this CompositionPropertySet propertySet, string key);
public static Vector4 GetVector4(this CompositionPropertySet propertySet, string key);

Expression Targets and Templates

It is now possible to use the new operator inside expressions. You can also define Expression Targets and Expression Templates within the Expression.

Expression Targets allow you to access the composition object (on which the expression animation is executed) within the expression.

Expression Templates allow you to reuse an expression by connecting them to different references (thus creating separate animations). It is similar to the way C# Generics allows you to define a class template and reuse the template for different types.

Here is an example

var visual = _compositor.CreateSpriteVisual();
visual.Offset = new Vector3(20, 30, 40);
visual.Size = new Vector2(200, 100);

var delta = new Vector3(50);

var offsetAnimation = _compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression = 
    c => new VisualReference("myVisual").CenterPoint + new Vector3(10, 20, 30) + delta;
offsetAnimation.SetReference("myVisual", visual);

visual.StartAnimation(() => visual.CenterPoint, offsetAnimation);

var visual2 = _compositor.CreateSpriteVisual();
visual2.Offset = new Vector3(10, 10, 10);
visual2.Size = new Vector2(100, 100);

offsetAnimation.SetReference("myVisual", visual2);
offsetAnimation.SetReference("delta", new Vector3(100));

visual2.StartAnimation(() => visual2.CenterPoint, offsetAnimation);

Using Arrays in Expression

You can use an Array of objects deriving from CompositionObject within your Expression.

Example

var visual1 = compositor.CreateSpriteVisual();
...
var visual2 = compositor.CreateSpriteVisual();
...
var visualArray = new Visual[] { visual1, visual2 };

var offsetAnimation = compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression = c => visualArray[0].Offset + new Vector(20);

visualArray[1].StartAnimation(() => visualArray[1].Offset, offsetAnimation);

Using List<> in Expression

You can use a List<> of objects deriving from CompositionObject within your Expression.

Example

var visual1 = compositor.CreateSpriteVisual();
...
var visual2 = compositor.CreateSpriteVisual();
...
var visualList = new List { visual1, visual2 };

var offsetAnimation = compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression = c => visualList[0].Offset + new Vector(20);

visualList[1].StartAnimation(() => visualList[1].Offset, offsetAnimation);

Using Dictionary<,> in Expression

You can use a Dictionary<TKey, TValue> within your Expression.

TKey can be of types – int, float, double or string.

TValue should be an object deriving from CompositionObject.

Example

var visual1 = compositor.CreateSpriteVisual();
...
var visual2 = compositor.CreateSpriteVisual();
...
var visualDictionary = new Dictionary<string, Visual> 
    {
        ["first"] = visual1, 
        ["second"] = visual2 
    };

var offsetAnimation = compositor.CreateVector3ExpressionAnimation();
offsetAnimation.Expression = c => visualDictionary["first"].Offset + new Vector(20);

visualDictionary["second"].StartAnimation(() => visualDictionary["second"], offsetAnimation);

Custom Cubic Bezier Easing Functions

The following extension methods have been added to Compositor to create predefined CubicBezierEasingFunctions (these custom cubic bezier easing functions are based on the Robert Penner’s Easing Equations and the values are obtained from Ceaser CSS Easing Animation Tool )

public static CubicBezierEasingFunction CreateEaseInBackEasingFunction();
public static CubicBezierEasingFunction CreateEaseInCircleEasingFunction();
public static CubicBezierEasingFunction CreateEaseInCubicEasingFunction();
public static CubicBezierEasingFunction CreateEaseInExponentialFunction();
public static CubicBezierEasingFunction CreateEaseInQuadraticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInQuarticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInQuinticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInSineEasingFunction();

public static CubicBezierEasingFunction CreateEaseOutBackEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutCircleEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutCubicEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutExponentialFunction();
public static CubicBezierEasingFunction CreateEaseOutQuadraticEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutQuarticEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutQuinticEasingFunction();
public static CubicBezierEasingFunction CreateEaseOutSineEasingFunction();

public static CubicBezierEasingFunction CreateEaseInOutBackEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutCircleEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutCubicEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutExponentialFunction();
public static CubicBezierEasingFunction CreateEaseInOutQuadraticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutQuarticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutQuinticEasingFunction();
public static CubicBezierEasingFunction CreateEaseInOutSineEasingFunction();

DeviceLostHelper

CompositionProToolkit now uses the DeviceLostHelper class (provided in the WindowsUIDevLabs Sample Gallery application) to watch for CanvasDevice and it raises an appropriate event when the device is lost.

Project structure and Nuget

CompositionProToolkit v0.6 also revamps the project structure. The CompositionProToolkit.Ref project has been discarded and the CompositionDeviceHelper project has been added. It is a C++/CX project which encapsulates the DeviceLostHelper class.

The CompositionProToolkit.nuspec has also been updated. Now it includes the XML documentation file to provide better Intellisense support when using CompositionProToolkit in your code. I had some issues creating a single Nuget package targeting x86, x64 & ARM – which internally contained a UWP library and a Windows Runtime Component. There is no clear documentation provided for this scenario. I had to refer through numerous blogs and forum posts to finally get the nuget structure right. I will write in more detail about this in my next blog post.

Source Code, Nuget & Documentation

Happy Coding!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s