{"id":4953,"date":"2013-03-14T07:00:00","date_gmt":"2013-03-14T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/03\/14\/playing-with-the-windows-animation-manager-fixing-a-sample\/"},"modified":"2013-03-14T07:00:00","modified_gmt":"2013-03-14T07:00:00","slug":"playing-with-the-windows-animation-manager-fixing-a-sample","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130314-00\/?p=4953","title":{"rendered":"Playing with the Windows Animation Manager: Fixing a sample"},"content":{"rendered":"<p><P>\nWindows&nbsp;7 provides a component known as the\n<A HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd371981.aspx\">\nWindows Animation Manager<\/A>,\nknown to some people by its acronym WAM, pronounced &#8220;wham&#8221;.\nThere are\n<A HREF=\"http:\/\/archive.msdn.microsoft.com\/animationmanager\">\nsome nice sample programs for WAM on MSDN<\/A>,\nbut for some reason, the authors of the samples decided\nto animate the three color components of a resultant color.\n<\/P>\n<P>\nBecause apparently the authors of those sample programs\ncan look at a color and say,\n&#8220;Oh, clearly the red component of this color increases\ngradually at first, then speeds up its rate of increase,\nand then slows back down until it reaches its final value;\nwhile simultaneously the blue component is doing the opposite,\nbut over a shorter time span,\nand the green component is remaining fixed.&#8221;\n<\/P>\n<P>\nToday&#8217;s exercise is to fix the sample program so you can actually\n<I>see<\/I> and <I>understand<\/I> what WAM is doing,\nrather than just watching psychedelic colors change\nand saying,\n&#8220;Gee, that&#8217;s pretty.&#8221;\n<\/P>\n<P>\nBut first, some background:\n<\/P>\n<P>\nWindows Animation is a component which manipulates <I>variables<\/I>.\nA <I>variable<\/I> is a number which varies over time.\nYou tell Windows Animation things like\n&#8220;I would like you to animate this variable from 1 to 10 over\nthe next 7 seconds.&#8221;\nYou can then interrogate the variable for its current value,\nand it might say &#8220;Right now, the value is 6.&#8221;\n<\/P>\n<P>\nThe idea is that each of these variables is connected to some\nvisual property, like the position of an object.\nWhen you paint the object, you consult the current value of the\nvariable to find out where you should draw it.\n<\/P>\n<P>\nOne of the annoying bits about Windows Animation is that you have\nto set up a bunch of stuff just to get things started.\nYou need an <I>animation manager<\/I>,\nwhich is the object that runs the show.\nYou also need an <I>animation timer<\/I>\nwhose job is to tell the animation manager what time it is.\n(Under normal circumstances, you would use the default timer,\nwhich records real-world time,\nbut you might want to replace it with\na special timer for debugging that runs at half-speed,\nor maybe one which\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2009\/04\/07\/9534758.aspx\">\nvaries its speed based on how fast you clap<\/A>.)\n<\/P>\n<P>\nOkay, back to fixing the sample.\n<\/P>\n<P>\nStart with the\n<A HREF=\"http:\/\/archive.msdn.microsoft.com\/animationmanager\">\nTimer-Driven Animation<\/A>\nand make these changes:\n<\/P>\n<PRE>\n                \/\/ disable the initial animation\n                <FONT COLOR=\"red\"><STRIKE>\/\/ Fade in with Red<\/STRIKE>\n                <STRIKE>\/\/ hr = ChangeColor(COLOR_MAX, COLOR_MIN, COLOR_MIN);<\/STRIKE><\/FONT><\/p>\n<p>HRESULT CMainWindow::DrawBackground(\n    Graphics &amp;graphics,\n    const RectF &amp;rectPaint\n    )\n{\n    \/\/ Get the RGB animation variable values<\/p>\n<p>    INT32 red;\n    HRESULT hr = m_pAnimationVariableRed-&gt;GetIntegerValue(\n        &amp;red\n        );\n    if (SUCCEEDED(hr))\n    {\n        INT32 green;\n        hr = m_pAnimationVariableGreen-&gt;GetIntegerValue(\n            &amp;green\n            );\n        if (SUCCEEDED(hr))\n        {\n            INT32 blue;\n            hr = m_pAnimationVariableBlue-&gt;GetIntegerValue(\n                &amp;blue\n                );\n            if (SUCCEEDED(hr))\n            {\n                <FONT COLOR=\"blue\">\/\/ Replace the drawing code as follows\n                SolidBrush brushBackground(Color(255, 255, 255));\n                hr = HrFromStatus(graphics.FillRectangle(\n                    &amp;brushBackground,\n                    rectPaint\n                    ));<\/p>\n<p>                SolidBrush brushCircle(Color(0, 0, 0));\n                hr = HrFromStatus(graphics.FillEllipse(\n                    &amp;brushCircle,\n                    red, green, 10, 10\n                    ));<\/FONT>\n            }\n        }\n    }<\/p>\n<p>    return hr;\n}\n<\/PRE>\n<P>\nInstead of drawing a psychedelic background color,\nI draw a small\n<A HREF=\"http:\/\/www.piday.org\/\">\ncircle<\/A>\nusing the old <CODE>red<\/CODE> value\nas the x-coordinate, and the old <CODE>green<\/CODE> value\nas the y-coordinate.\nI didn&#8217;t rename the variables or get rid of the unused\n<CODE>blue<\/CODE> variable\nbecause I wanted to make as few changes as possible.\n<\/P>\n<P>\nRun this program, and click to make the circle move.\nObserve that when the circle moves, it starts slowly,\nthen accelerates, and then decelerates as it gets closer\nto its final location.\nWhat&#8217;s more, if you click while the circle is still moving,\nthe circle demonstrates <I>inertia<\/I> as it turns to\nhead toward its new target location.\n<\/P>\n<P>\nI bet you never noticed the acceleration, deceleration, or\ninertia\nin the original background-color version.\n<\/P>\n<P>\nWith a little bit of work, you can make the sample even more\ninteresting by making the circle go to <I>where you clicked<\/I>.\nIt looks like a lot of work when I spell it out below,\nbut most of it consists of <I>deleting<\/I> code.\n<\/P>\n<P>\nFirst, do a search\/replace and rename\n<CODE>m_pAnimationVariableRed<\/CODE> to\n<CODE>m_pAnimationVariableX<\/CODE>,\nand rename\n<CODE>m_pAnimationVariableGreen<\/CODE> to\n<CODE>m_pAnimationVariableY<\/CODE>.\nDelete\n<CODE>m_pAnimationVariableBlue<\/CODE> entirely,\nas well as any references to it.\nI decided to just bite the bullet and deal with the\nconsequences of renaming\/deleting variables.\n<\/P>\n<P>\nNow we can simplify the\n<CODE>CMain&shy;Window::Create&shy;Animation&shy;Variables<\/CODE>\nmethod so all it does is create the two coordinate variables.\n<PRE>\nHRESULT CMainWindow::CreateAnimationVariables()\n{\n    <FONT COLOR=\"blue\">HRESULT hr = m_pAnimationManager-&gt;CreateAnimationVariable(\n        0,\n        &amp;m_pAnimationVariableX\n        );\n    if (SUCCEEDED(hr))\n    {\n        hr = m_pAnimationManager-&gt;CreateAnimationVariable(\n            0,\n            &amp;m_pAnimationVariableY\n            );\n    }<\/FONT><\/p>\n<p>    return hr;\n}\n<\/PRE>\n<P>\nWe want the circle to move when you click the mouse,\nso let&#8217;s do that.\nDelete <CODE>CMain&shy;Window::On&shy;LButton&shy;Down<\/CODE>\nand change the window procedure so that clicks move the circle.\n<\/P>\n<PRE>\nLRESULT CALLBACK CMainWindow::WndProc(\n    HWND hwnd,\n    UINT uMsg,\n    WPARAM wParam,\n    LPARAM lParam\n    )\n{\n    &#8230;\n        case WM_LBUTTONDOWN:\n            {\n                pMainWindow-&gt;<FONT COLOR=\"blue\">ChangePos(\n                    (SHORT)LOWORD(lParam),\n                    (SHORT)HIWORD(lParam)\n                 <\/FONT>);\n            }\n            return MESSAGE_PROCESSED;\n    &#8230;\n}\n<\/PRE>\n<P>\nAnd rename the member function\n<CODE>Change&shy;Color<\/CODE> to\n<CODE>Change&shy;Pos<\/CODE>,\nand instead of taking red and green,\nhave it take x and y.\n<\/P>\n<PRE>\nHRESULT CMainWindow::<FONT COLOR=\"blue\">ChangePos(\n    INT x,\n    INT y<\/FONT>\n    )\n{\n    const UI_ANIMATION_SECONDS DURATION = 0.5;\n    const DOUBLE ACCELERATION_RATIO = 0.5;\n    const DOUBLE DECELERATION_RATIO = 0.5;<\/p>\n<p>    \/\/ Create a storyboard<\/p>\n<p>    IUIAnimationStoryboard *pStoryboard = NULL;\n    HRESULT hr = m_pAnimationManager-&gt;CreateStoryboard(\n        &amp;pStoryboard\n        );\n    if (SUCCEEDED(hr))\n    {\n        \/\/ Create transitions for the <FONT COLOR=\"blue\">position<\/FONT> animation variables<\/p>\n<p>        IUIAnimationTransition *pTransition<FONT COLOR=\"blue\">X<\/FONT>;\n        hr = m_pTransitionLibrary-&gt;CreateAccelerateDecelerateTransition(\n            DURATION,\n            <FONT COLOR=\"blue\">x<\/FONT>,\n            ACCELERATION_RATIO,\n            DECELERATION_RATIO,\n            &amp;pTransition<FONT COLOR=\"blue\">X<\/FONT>\n            );\n        if (SUCCEEDED(hr))\n        {\n            IUIAnimationTransition *pTransition<FONT COLOR=\"blue\">Y<\/FONT>;\n            hr = m_pTransitionLibrary-&gt;CreateAccelerateDecelerateTransition(\n                DURATION,\n                <FONT COLOR=\"blue\">y<\/FONT>,\n                ACCELERATION_RATIO,\n                DECELERATION_RATIO,\n                &amp;pTransition<FONT COLOR=\"blue\">Y<\/FONT>\n                );\n            <FONT COLOR=\"red\">\/\/ delete former &#8220;blue&#8221; transition<\/FONT>\n            if (SUCCEEDED(hr))\n            {\n                \/\/ Add transitions to the storyboard<\/p>\n<p>                hr = pStoryboard-&gt;AddTransition(\n                    m_pAnimationVariable<FONT COLOR=\"blue\">X<\/FONT>,\n                    pTransition<FONT COLOR=\"blue\">X<\/FONT>\n                    );\n                if (SUCCEEDED(hr))\n                {\n                    hr = pStoryboard-&gt;AddTransition(\n                        m_pAnimationVariable<FONT COLOR=\"blue\">Y<\/FONT>,\n                        pTransition<FONT COLOR=\"blue\">Y<\/FONT>\n                        );\n                    <FONT COLOR=\"red\">\/\/ delete former &#8220;blue&#8221; transition<\/FONT>\n                    if (SUCCEEDED(hr))\n                    {\n                        \/\/ Get the current time and schedule the storyboard for play\n                        UI_ANIMATION_SECONDS secondsNow;\n                        hr = m_pAnimationTimer-&gt;GetTime(\n                            &amp;secondsNow\n                            );\n                        if (SUCCEEDED(hr))\n                        {\n                            hr = pStoryboard-&gt;Schedule(\n                                secondsNow\n                                );\n                        }\n                    }\n                }<\/p>\n<p>                <FONT COLOR=\"red\">\/\/ delete former &#8220;blue&#8221; transition<\/FONT><\/p>\n<p>                pTransition<FONT COLOR=\"blue\">Y<\/FONT>-&gt;Release();\n            }<\/p>\n<p>            pTransition<FONT COLOR=\"blue\">X<\/FONT>-&gt;Release();\n        }<\/p>\n<p>        pStoryboard-&gt;Release();\n    }<\/p>\n<p>    return hr;\n}\n<\/PRE>\n<P>\nNow you can click the mouse on the client area,\nand the dot will chase it like a puppy.\n<\/P>\n<P>\nThe basic idea behind the Windows Animation Library\nis that for each property you want to animate,\nyou associate an animation variable,\nand when you want to perform the animation,\nyou create a transition for each variable describing\nhow you want the animation to proceed,\nput all the transitions into a storyboard,\nand then schedule the storyboard.\n<\/P>\n<P>\nOf course, you can build optimizations on top of the basic idea.\nFor example, you might not create the animation variable until\nthe first time you need to animate the property.\nAnother optimization is invalidating only the parts of the window\nthat need repainting,\nrather than invalidating the entire client area.\nYou can do this by registering a change handler on your variables:\nWhen the change handler notifies you that a value changed,\ninvalidate the old position and the new position.\nThis will erase the old location and draw at the new location.\n<\/P>\n<P>\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/03\/15\/10399700.aspx\">\nNext time<\/A>, I&#8217;ll build a program that animates a hundred objects,\njust for fun.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Windows&nbsp;7 provides a component known as the Windows Animation Manager, known to some people by its acronym WAM, pronounced &#8220;wham&#8221;. There are some nice sample programs for WAM on MSDN, but for some reason, the authors of the samples decided to animate the three color components of a resultant color. Because apparently the authors of [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-4953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Windows&nbsp;7 provides a component known as the Windows Animation Manager, known to some people by its acronym WAM, pronounced &#8220;wham&#8221;. There are some nice sample programs for WAM on MSDN, but for some reason, the authors of the samples decided to animate the three color components of a resultant color. Because apparently the authors of [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4953","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=4953"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4953\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=4953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=4953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=4953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}