The New MFC Animation API

Introduction

Microsoft Visual Studio 2010 Service Pack 1 includes a number of enhancements and new features for MFC developers. One of those changes is an animation API to make it easy for you to create animations in MFC applications. This article will briefly introduce this animation API.

The main parts of this new API are:

  • Animation transitions
  • Animation values
  • Animation controllers

Animation Transitions

The animation API uses transitions to animate values. The API comes with a number of predefined transitions:

  • CAccelerateDecelerateTransition: The animated value speeds up and then slows down again.
  • CConstantTransition: The animated value will be kept at its initial value during the whole transition.
  • CCubicTransition: The animated value will reach the target value with a specified velocity.
  • CDiscreteTransition: The animated value will jump from the initial value directly to the target value after a specified delay.
  • CInstantaneousTransition: The animated value immediately jumps to the target value. The duration is always zero.
  • CLinearTransition: The animated value will go linearly from its initial value to its target value over a specified duration.
  • CLinearTransitionFromSpeed: Is similar to CLinearTransition, but instead of specifying a duration, you have to specify a speed with which the animated value has to go from the initial value to the target value. The duration of the transition is calculated automatically based on the specified speed.
  • CSmoothStopTransition: The animated value will go from its initial value to its target value, but the transition will slow down towards the target value to reach the target with a velocity of zero.
  • CParabolicTransitionFromAcceleration: The animated value will reach its target value with a specified velocity and acceleration.
  • CReversalTransition: The transition direction will be changed smoothly over a specified duration. The final value of the animated value will be the same as the initial value.
  • CSinusoidalTransitionFromRange: The animated value will fluctuate between a specified minimum and maximum during the duration of the transition.
  • CSinusoidalTransitionFromVelocity: The animated value will oscillate around the initial value during the duration of the transition.

Most of the above predefined animation transitions are pretty straightforward to use. All of them require at least the duration of the transition and most of them require a target value. For example, the CAccelerateDecelerateTransition transition has the following constructor:

  CAccelerateDecelerateTransition(UI_ANIMATION_SECONDS duration,
  	DOUBLE finalValue,
  	DOUBLE accelerationRatio = 0.3,
  	DOUBLE decelerationRatio = 0.3)

The first parameter is the duration of the transition. It is the time that it will take to go from the start value to the target value. The second parameter is this target value. The next parameters are specific algorithmic parameters which have default values in this case.

CConstantTransition is special. It will keep the animation value at its initial value during the whole transition, so its constructor is simply as follows:

  CConstantTransition(UI_ANIMATION_SECONDS duration)

There is also a CCustomTransition that you can use if none of the above transitions deliver what you are looking for. It's a bit more complicated to use. You will have to derive your own class from CCustomInterpolator and implement the InterpolateValue method and possibly a few others.

The next section will discuss animation values and will give examples on how to actually use the above animation transitions. Note that you need to initialize COM before the Windows Animation API will work. You can do this by adding the following line in your InitInstance method:

  CoInitialize(0);
  
  And the following line in your ExitInstance method:
  CoUninitialize();
  
  Instead of using CoInitialize and CoUnitialize, you can simply use the following block in your InitInstance method:
  if (!AfxOleInit())
  {
  	AfxMessageBox(_T("AfxOleInit failed"));
  	return FALSE;
  }

Animation Values

The new API works by animating values. There are several classes that encapsulate specific values and which can be animated with certain transitions. The different animation value classes are as follows:

  • CAnimationValue: Animates a single value. This could be used to animate a transparency of an object or a rotation of an object.
  • CAnimationPoint: Animates a point. A point contains and X and Y coordinates. Both coordinates can be animated separately.
  • CAnimationSize: Animates a size. A size contains a width and height, both can be animated separately.
  • CAnimationColor: Animates a color. A color contains an RGB value. Each color component can be animated separately.
  • CAnimationRect: Animates a rectangle. A rectangle contains a left, top, right and bottom value and all of them can be animated separately.

Creating an animation value is pretty straightforward. Just create an instance of the animation value object you want, initialize it, add animation transitions to it and specify its parameters like the target value. For example, to define a color animation value, first define it as follows:

  CAnimationColor m_animClr1;

Then the following line will initialize the start color to red:

  m_animClr1 = RGB(255,0,0);

And finally assign transitions to each color component:

  m_animClr1.AddTransition(new CLinearTransition(2, 0),
  	new CLinearTransition(1, 255),
  	new CLinearTransition(0.5, 128));

The above line adds 3 transitions:

  • The red color component will go from 255 (=start value) to 0 over a period of 2 seconds.
  • The green color component will go from 0 (=start value) to 255 over a period of 1 seconds.
  • The blue color component will go from 0 (=start value) to 128 over a period of 0.5 seconds.

Similarly, a rectangle animation could be defined as follows:

  CAnimationRect m_animRect;
  m_animRect = CRect(0, 0, 100 ,100);
  m_animRect.AddTransition(new CAccelerateDecelerateTransition(2, 100),
  	new CAccelerateDecelerateTransition(2, 100),
  	new CAccelerateDecelerateTransition(2, 400),
  	new CAccelerateDecelerateTransition(2, 200));

This animation starts with a rectangle with upper-left coordinate (0, 0) and lower-right coordinate (100, 100). The transitions will animate this rectangle to an upper-left coordinate (100, 100) and a lower-right coordinate (400, 200) over a period of 2 seconds using an acceleration-deceleration transition.

Inside your WM_PAINT handler, you will use the animated values from your animation variables to do your drawing. For example:

  int x1, y1, x2, y2;
  m_animRect.GetLeft().GetValue(x1);
  m_animRect.GetTop().GetValue(y1);
  m_animRect.GetRight().GetValue(x2);
  m_animRect.GetBottom().GetValue(y2);
  COLORREF clr;
  m_animClr1.GetValue(clr);
  pDC->FillSolidRect(x1, y1, x2-x1, y2-y1, clr);

The above code is first querying the animated rectangle about its current animated coordinates and the animated color variable about its current color value. After that it simply draws a rectangle with those coordinates and color.

Working with the other animation value classes is pretty similar.



The New MFC Animation API

Animation Controller

Now that you have learned about animation transitions and animations values, it's time to learn how it all fits together. The CAnimationController class is the central part of the animation API. It will keep track of all animation values and animation transitions. You simply create one as a member variable in your class as follows:

  CAnimationController m_animCtrl;

The next step is to link it with your target window in which you want to draw the animation:

  m_animCtrl.SetRelatedWnd(this);

You are not required to link an animation controller with a window. Linking it will tell the animation API to send WM_PAINT messages to the specified window during the animation which makes it easier for you to redraw a frame of your animation. If you do not link the animation controller with a window, you will have to manually invalidate your window at appropriate intervals to redraw it. In this example we want the animation controller to send WM_PAINT message periodically, so you also need to tell it to use an animation timer:

  m_animCtrl.EnableAnimationTimerEventHandler();

Now it's time to link your animation values with the animation controller so it can take control of them:

  CAnimationGroup* pGroup = m_animCtrl.AddAnimationObject(&m_animRect);
  m_animCtrl.AddAnimationObject(&m_animClr1);
  pGroup->m_bAutodestroyAnimationObjects = FALSE;

The first line will add the m_animRect animation value to the controller. Because this is the first animation value added to the controller, the controller will create a new animation group and will return a pointer to this group. The second line will add the m_animClr1 color animation value. Because you are not specifying any animation group, the controller will add m_animClr1 to the same animation group as m_animRect . The last line tells the animation controller to not automatically delete the linked animation values. This is done in this case because our animation values are member variables of our class. Instead of defining animation values as member variables, you could create an animation value using operator new, link it with the animation controller in a specific group and tell the animation controller to automatically delete objects when that animation group is destroyed. This makes it easier to manage dynamically created animation variables.

After all this, the animation controller is linked with certain animation values and each animation value is linked with certain animation transitions. Now it's time to start the animation and this is simply done with the following line:

  m_animCtrl.AnimateGroup(0);

This function required the ID of the group that you want to animate. If you didn't specify your own group ID earlier while adding your animation variables to the controller, the default group ID 0 will be used. You can add an animation variable to a specific group by setting the ID on the animation variable as follows:

  m_animClr1.SetID(0, 1);
  m_animCtrl.AddAnimationObject(&m_animClr1);

The first line will set the group ID of m_animClr1 to 1 and the second line will add the animation variable to the controller which will then create a new group with ID 1. If you want to start this group, you need the following line:

  m_animCtrl.AnimateGroup(1);

That's it, when you run the application you will see that a rectangle is changing color, position and size with a smooth animation transition. The initial look of the window is as follows:

[animation1.jpg]
Figure 1

After the smooth animation, the window will look as follows:

[animation2.jpg]
Figure 2

See the attached demo project to see it all working together.

Conclusion

This article serves as a brief introduction to the animation API. The API includes some more advanced functionality like event handlers. For example, you could configure an event handler that will be called each time the status of the animation controller changes or each time a value of an animation value changes.





About the Author

Marc Gregoire

Marc graduated from the Catholic University Leuven, Belgium, with a degree in "Burgerlijk ingenieur in de computer wetenschappen" (equivalent to Master of Science in Engineering in Computer Science) in 2003. In 2004 he got the cum laude degree of Master In Artificial Intelligence at the same university. In 2005 he started working for a big software consultancy company. His main expertise is C/C++ and specifically Microsoft VC++ and the MFC framework. Next to C/C++, he also likes C# and uses PHP for creating webpages. Besides his main interest for Windows development, he also has experience in developing C++ programs running 24x7 on Linux platforms and in developing critical 2G,3G software running on Solaris for big telecom operators.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

  • Not long ago, security was viewed as one of the biggest obstacles to widespread adoption of cloud-based deployments for enterprise software solutions. However, the combination of advancing technology and an increasing variety of threats that companies must guard against is rapidly turning the tide. Cloud vendors typically offer a much higher level of data center and virtual system security than most organizations can or will build out on their own. Read this white paper to learn the five ways that cloud …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds