Windows2003-3790/windows/advcore/duser/engine/ctrl/oldanimation.cpp
2020-09-30 16:53:55 +02:00

922 lines
25 KiB
C++

#include "stdafx.h"
#include "Ctrl.h"
#include "OldAnimation.h"
PRID OldAlphaAnimation::s_pridAlpha = 0;
PRID OldScaleAnimation::s_pridScale = 0;
PRID OldRectAnimation::s_pridRect = 0;
PRID OldRotateAnimation::s_pridRotate = 0;
static const GUID guidAlphaAnimation = { 0x41a2e2f2, 0xf262, 0x41ae, { 0x89, 0xda, 0xb7, 0x9c, 0x8f, 0xf5, 0x94, 0xbb } }; // {41A2E2F2-F262-41ae-89DA-B79C8FF594BB}
static const GUID guidScaleAnimation = { 0xa5b1df84, 0xb9c0, 0x4305, { 0xb9, 0x3a, 0x5b, 0x80, 0x31, 0x86, 0x70, 0x69 } }; // {A5B1DF84-B9C0-4305-B93A-5B8031867069}
static const GUID guidRectAnimation = { 0x8e41c241, 0x3cdf, 0x432e, { 0xa1, 0xae, 0xf, 0x7b, 0x59, 0xdc, 0x82, 0xb } }; // {8E41C241-3CDF-432e-A1AE-0F7B59DC820B}
static const GUID guidRotateAnimation = { 0x78f16dd5, 0xa198, 0x4cd2, { 0xb1, 0x78, 0x31, 0x61, 0x3e, 0x32, 0x12, 0x54 } }; // {78F16DD5-A198-4cd2-B178-31613E321254}
const IID * OldAlphaAnimation::s_rgpIID[] =
{
&__uuidof(IUnknown),
&__uuidof(IAnimation),
NULL
};
const IID * OldScaleAnimation::s_rgpIID[] =
{
&__uuidof(IUnknown),
&__uuidof(IAnimation),
NULL
};
const IID * OldRectAnimation::s_rgpIID[] =
{
&__uuidof(IUnknown),
&__uuidof(IAnimation),
NULL
};
const IID * OldRotateAnimation::s_rgpIID[] =
{
&__uuidof(IUnknown),
&__uuidof(IAnimation),
NULL
};
/***************************************************************************\
*****************************************************************************
*
* class OldAnimation
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
OldAnimation::~OldAnimation()
{
#if DEBUG_TRACECREATION
Trace("STOP Animation 0x%p @ %d (%d frames)\n", this, GetTickCount(), m_DEBUG_cUpdates);
#endif // DEBUG_TRACECREATION
//
// Ensure proper destruction
//
AssertMsg(m_hact == NULL, "Action should already be destroyed");
}
//------------------------------------------------------------------------------
HRESULT
OldAnimation::Create(
IN const GUID * pguid,
IN OUT PRID * pprid,
IN GANI_DESC * pDesc) // Animation information
{
if (pDesc->pipol != NULL) {
pDesc->pipol->AddRef();
m_pipol = pDesc->pipol;
}
if (pDesc->pcb != NULL) {
pDesc->pcb->AddRef();
m_pcb = pDesc->pcb;
}
GMA_ACTION gma;
ZeroMemory(&gma, sizeof(gma));
gma.cbSize = sizeof(gma);
gma.flDelay = pDesc->act.flDelay;
gma.flDuration = pDesc->act.flDuration;
gma.flPeriod = pDesc->act.flPeriod;
gma.cRepeat = pDesc->act.cRepeat;
gma.dwPause = pDesc->act.dwPause;
gma.pfnProc = RawActionProc;
gma.pvData = this;
m_hact = CreateAction(&gma);
if (m_hact == NULL) {
return (HRESULT) GetLastError();
}
HRESULT hr = OldExtension::Create(pDesc->hgadChange, pguid, pprid, OldExtension::oAsyncDestroy);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
//------------------------------------------------------------------------------
void
OldAnimation::Destroy(BOOL fFinal)
{
//
// Mark that we have already started the destruction process and don't need
// to start again. We only want to post the destruction message once.
//
if (m_fStartDestroy) {
return;
}
m_fStartDestroy = TRUE;
//
// Give the derived Animation a chance to cleanup
//
// Check that we are still the Animation attached to this Gadget. We need
// to remove this property immediately. We can not wait for a posted
// message to be processed because we may need to set it right now if we are
// creating a new Animation.
//
if (m_hgadSubject != NULL) {
OnComplete();
#if DBG
OldAnimation * paniExist = static_cast<OldAnimation *> (GetExtension(m_hgadSubject, m_pridListen));
if (paniExist != NULL) {
AssertMsg(paniExist == this, "Animations must match");
}
#endif // DBG
CleanupChangeGadget();
}
//
// Destroy the Animation
//
AssertMsg(!fFinal, "Object is already being destructed");
if (fFinal) {
OnAsyncDestroy();
} else {
PostAsyncDestroy();
}
}
//------------------------------------------------------------------------------
void
OldAnimation::OnAsyncDestroy()
{
AssertMsg(m_fStartDestroy, "Must call Destroy() to start the destruction process.");
AssertMsg(!m_fProcessing, "Should not be processing when start destruction");
AssertMsg(m_hgadSubject == NULL, "Animation should already have detached from Gadget");
HACTION hact = m_hact;
//
// Notify any callback that the Animation is finished
//
if (m_pcb != NULL) {
IAnimation * paniI = static_cast<IAnimation *> (this);
__try
{
m_pcb->OnComplete(paniI, m_time);
}
__except(StdExceptionFilter(GetExceptionInformation()))
{
ExitProcess(GetExceptionCode());
}
}
//
// Set everything to NULL now.
//
m_hact = NULL;
OldExtension::DeleteHandle();
//
// Stop the Action
//
if (hact != NULL) {
::DeleteHandle(hact);
hact = NULL;
}
//
// Release() our cached interfaces
//
SafeRelease(m_pipol);
SafeRelease(m_pcb);
}
//------------------------------------------------------------------------------
STDMETHODIMP_(void)
OldAnimation::SetFunction(IInterpolation * pipol)
{
AssertReadPtr(pipol);
SafeRelease(m_pipol);
pipol->AddRef();
m_pipol = pipol;
}
//------------------------------------------------------------------------------
STDMETHODIMP_(void)
OldAnimation::SetTime(IAnimation::ETime time)
{
GMA_ACTIONINFO mai;
//
// TODO: Need to save these values from the last time so that they are
// valid.
//
mai.hact = m_hact;
mai.pvData = this;
mai.flDuration = 0.0f;
m_time = time;
switch (time)
{
case IAnimation::tComplete:
// Don't do anything
return;
default:
case IAnimation::tAbort:
case IAnimation::tDestroy:
goto Done;
case IAnimation::tEnd:
mai.flProgress = 1.0f;
break;
case IAnimation::tReset:
mai.flProgress = 0.0f;
break;
}
mai.cEvent = 0;
mai.cPeriods = 0;
mai.fFinished = FALSE;
m_fProcessing = TRUE;
Action(&mai);
Assert(m_fProcessing);
m_fProcessing = FALSE;
Done:
if (m_pcb != NULL) {
IAnimation * paniI = static_cast<IAnimation *> (this);
m_pcb->OnSetTime(paniI, time);
}
::DeleteHandle(m_hact);
}
//------------------------------------------------------------------------------
STDMETHODIMP_(void)
OldAnimation::SetCallback(IAnimationCallback * pcb)
{
// pcb can be NULL
SafeRelease(m_pcb);
if (pcb != NULL) {
pcb->AddRef();
m_pcb = pcb;
}
}
//------------------------------------------------------------------------------
HRESULT
OldAnimation::GetInterface(HGADGET hgad, PRID prid, REFIID riid, void ** ppvUnk)
{
OldAnimation * paniExist = static_cast<OldAnimation *> (GetExtension(hgad, prid));
if (paniExist != NULL) {
if (IsEqualIID(riid, __uuidof(IAnimation))) {
paniExist->AddRef();
*ppvUnk = static_cast<IAnimation *> (paniExist);
return S_OK;
} else {
return paniExist->QueryInterface(riid, ppvUnk);
}
}
return DU_E_NOTFOUND; // This Animation doesn't exist on this Gadget.
}
//------------------------------------------------------------------------------
void
OldAnimation::CleanupChangeGadget()
{
Assert(m_hgadSubject != NULL);
Assert(m_pridListen != 0);
Verify(::RemoveGadgetProperty(m_hgadSubject, m_pridListen));
m_hgadSubject = NULL;
}
//------------------------------------------------------------------------------
void CALLBACK
OldAnimation::RawActionProc(
IN GMA_ACTIONINFO * pmai)
{
OldAnimation * pani = (OldAnimation *) pmai->pvData;
pani->AddRef();
Assert(!pani->m_fProcessing);
#if DBG
pani->m_DEBUG_cUpdates++;
#endif // DBG
#if DEBUG_TRACECREATION
Trace("START RawActionP 0x%p @ %d\n", pani, GetTickCount());
#endif // DEBUG_TRACECREATION
if ((!pani->m_fStartDestroy) && (pani->m_hgadSubject != NULL)) {
//
// This ActionProc will be called when the Action is being destroyed, so
// we only want to invoke the Action under certain circumstances.
//
switch (pani->m_time)
{
case tComplete:
case tEnd:
case tReset:
//
// All of these are valid to complete. If it isn't in this list, we
// don't want to execute it during a shutdown.
//
pani->m_fProcessing = TRUE;
pani->Action(pmai);
Assert(pani->m_fProcessing);
pani->m_fProcessing = FALSE;
break;
}
}
if (pmai->fFinished) {
pani->m_hact = NULL;
pani->Destroy(FALSE);
}
#if DEBUG_TRACECREATION
Trace("STOP RawActionP 0x%p @ %d\n", pani, GetTickCount());
#endif // DEBUG_TRACECREATION
Assert(!pani->m_fProcessing);
pani->Release();
}
//------------------------------------------------------------------------------
void
OldAnimation::OnRemoveExisting()
{
SetTime(IAnimation::tDestroy);
}
//------------------------------------------------------------------------------
void
OldAnimation::OnDestroyListener()
{
AddRef();
if (m_hgadListen != NULL) {
//
// TODO: Figure out when this case can actually occur. This means that
// the MessageGadget was destroyed, but the caller didn't go through
// OldAnimation::Destroy() to do it.
//
m_hgadListen = NULL;
Destroy(FALSE);
}
VerifyMsg(Release() > 0, "Must still have lock from beginning of function");
Release();
}
//------------------------------------------------------------------------------
void
OldAnimation::OnDestroySubject()
{
AddRef();
if (m_hgadSubject != NULL) {
CleanupChangeGadget();
//
// The Gadget that we are modifying is being destroyed, so we need
// to stop animating it.
//
m_time = IAnimation::tDestroy;
Destroy(FALSE);
}
Release();
}
/***************************************************************************\
*****************************************************************************
*
* class OldAlphaAnimation
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
OldAlphaAnimation::~OldAlphaAnimation()
{
Destroy(TRUE);
#if DEBUG_TRACECREATION
Trace("OldAlphaAnimation 0x%p destroyed\n", this);
#endif // DEBUG_TRACECREATION
}
//------------------------------------------------------------------------------
HRESULT
OldAlphaAnimation::Create(
IN GANI_DESC * pDesc)
{
HRESULT hr = OldAnimation::Create(&guidAlphaAnimation, &s_pridAlpha, pDesc);
if (FAILED(hr)) {
return hr;
}
//
// Get the information from the Gadget
//
GANI_ALPHADESC * pDescA = (GANI_ALPHADESC *) pDesc;
m_nOnComplete = pDescA->nOnComplete;
m_fPushToChildren = pDescA->fPushToChildren &&
(::GetGadget(m_hgadSubject, GG_TOPCHILD) != NULL);
BOOL fBuffered = TestFlag(::GetGadgetStyle(m_hgadSubject), GS_BUFFERED);
if (TestFlag(pDesc->nAniFlags, ANIF_USESTART)) {
m_flStart = pDescA->flStart;
} else {
if (fBuffered) {
//
// Gadget is already buffered, so use it current alpha value.
//
BUFFER_INFO bi;
ZeroMemory(&bi, sizeof(bi));
bi.cbSize = sizeof(bi);
bi.nMask = GBIM_ALPHA;
if (::GetGadgetBufferInfo(m_hgadSubject, &bi)) {
m_flStart = ((float) bi.bAlpha) / 255.0f;
} else {
m_flStart = 1.0f;
}
} else {
m_flStart = 1.0f;
}
}
if (m_fPushToChildren) {
//
// If we are currently alpha blended, we need to turn this off.
//
if (fBuffered) {
::SetGadgetStyle(m_hgadSubject, 0, GS_BUFFERED);
::SetGadgetStyle(m_hgadSubject, 0, GS_OPAQUE);
}
//
// Setup each direct child to be buffered for the alpha-blending
//
BYTE bAlpha = (BYTE) (m_flStart * 255.0f);
HGADGET hgadChild = ::GetGadget(m_hgadSubject, GG_TOPCHILD);
while (hgadChild != NULL) {
if (!::SetGadgetStyle(hgadChild, GS_BUFFERED | GS_OPAQUE, GS_BUFFERED | GS_OPAQUE)) {
return (HRESULT) GetLastError();
}
BUFFER_INFO bi;
bi.cbSize = sizeof(bi);
bi.nMask = GBIM_ALPHA;
bi.bAlpha = bAlpha;
if (!SetGadgetBufferInfo(hgadChild, &bi)) {
return (HRESULT) GetLastError();
}
hgadChild = ::GetGadget(hgadChild, GG_NEXT);
}
} else if (!fBuffered) {
//
// Need to mark the Gadget as being buffered to perform alpha effects
//
if (!::SetGadgetStyle(m_hgadSubject, GS_BUFFERED | GS_OPAQUE, GS_BUFFERED | GS_OPAQUE)) {
return (HRESULT) GetLastError();
}
}
m_flEnd = pDescA->flEnd;
#if DEBUG_TRACECREATION
Trace("OldAlphaAnimation 0x%p on 0x%p initialized\n", m_hgadSubject, this);
#endif // DEBUG_TRACECREATION
return S_OK;
}
//------------------------------------------------------------------------------
STDMETHODIMP_(UINT)
OldAlphaAnimation::GetID() const
{
return ANIMATION_ALPHA;
}
//------------------------------------------------------------------------------
void
OldAlphaAnimation::Action(GMA_ACTIONINFO * pmai)
{
float flPr = pmai->flProgress;
float flAlpha = m_pipol->Compute(flPr, m_flStart, m_flEnd);
BYTE bAlpha;
if (flAlpha < 0.0f) {
bAlpha = (BYTE) 0;
} else if (flAlpha > 1.0f) {
bAlpha = (BYTE) 255;
} else {
bAlpha = (BYTE) (flAlpha * 255.0f);
}
BUFFER_INFO bi;
bi.cbSize = sizeof(bi);
bi.nMask = GBIM_ALPHA;
bi.bAlpha = bAlpha;
if (m_fPushToChildren) {
HGADGET hgadChild = ::GetGadget(m_hgadSubject, GG_TOPCHILD);
while (hgadChild != NULL) {
SetGadgetStyle(hgadChild, GS_BUFFERED | GS_OPAQUE, GS_BUFFERED | GS_OPAQUE);
SetGadgetBufferInfo(hgadChild, &bi);
InvalidateGadget(hgadChild);
hgadChild = ::GetGadget(hgadChild, GG_NEXT);
}
} else {
SetGadgetStyle(m_hgadSubject, GS_BUFFERED | GS_OPAQUE, GS_BUFFERED | GS_OPAQUE);
SetGadgetBufferInfo(m_hgadSubject, &bi);
InvalidateGadget(m_hgadSubject);
}
}
//------------------------------------------------------------------------------
void
OldAlphaAnimation::OnComplete()
{
if (TestFlag(m_nOnComplete, GANI_ALPHACOMPLETE_OPTIMIZE)) {
if ((m_flEnd * 255.0f) >= 245) {
if (m_fPushToChildren) {
HGADGET hgadChild = ::GetGadget(m_hgadSubject, GG_TOPCHILD);
while (hgadChild != NULL) {
SetGadgetStyle(hgadChild, 0, GS_BUFFERED);
hgadChild = ::GetGadget(hgadChild, GG_NEXT);
}
} else {
SetGadgetStyle(m_hgadSubject, 0, GS_BUFFERED);
}
InvalidateGadget(m_hgadSubject);
}
}
}
/***************************************************************************\
*****************************************************************************
*
* class OldScaleAnimation
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
OldScaleAnimation::~OldScaleAnimation()
{
Destroy(TRUE);
#if DEBUG_TRACECREATION
Trace("OldScaleAnimation 0x%p destroyed\n", this);
#endif // DEBUG_TRACECREATION
}
//------------------------------------------------------------------------------
HRESULT
OldScaleAnimation::Create(
IN GANI_DESC * pDesc)
{
HRESULT hr = OldAnimation::Create(&guidScaleAnimation, &s_pridScale, pDesc);
if (FAILED(hr)) {
return hr;
}
//
// Get the information from the Gadget
//
GANI_SCALEDESC * pDescS = (GANI_SCALEDESC *) pDesc;
if (TestFlag(pDesc->nAniFlags, ANIF_USESTART)) {
m_flStart = pDescS->flStart;
} else {
float flX, flY;
if (!::GetGadgetScale(m_hgadSubject, &flX, &flY)) {
return (HRESULT) GetLastError();
}
m_flStart = flX;
}
m_flEnd = pDescS->flEnd;
m_al = pDescS->al;
RECT rcParent;
::GetGadgetRect(m_hgadSubject, &rcParent, SGR_PARENT);
m_ptStart.x = rcParent.left;
m_ptStart.y = rcParent.top;
m_sizeCtrl.cx = rcParent.right - rcParent.left;
m_sizeCtrl.cy = rcParent.bottom - rcParent.top;
#if DEBUG_TRACECREATION
Trace("OldScaleAnimation 0x%p on 0x%p initialized\n", m_hgadSubject, this);
#endif // DEBUG_TRACECREATION
return S_OK;
}
//------------------------------------------------------------------------------
STDMETHODIMP_(UINT)
OldScaleAnimation::GetID() const
{
return ANIMATION_SCALE;
}
//------------------------------------------------------------------------------
void
OldScaleAnimation::Action(GMA_ACTIONINFO * pmai)
{
float flPr = pmai->flProgress;
float flx = m_pipol->Compute(flPr, m_flStart, m_flEnd);
float fly = flx;
::SetGadgetScale(m_hgadSubject, flx, fly);
POINT ptNew;
ptNew.x = m_ptStart.x - (int) ((m_sizeCtrl.cx * flx - m_sizeCtrl.cx) / 2.0);
ptNew.y = m_ptStart.y - (int) ((m_sizeCtrl.cy * fly - m_sizeCtrl.cy) / 2.0);
::SetGadgetRect(m_hgadSubject, ptNew.x, ptNew.y, 0, 0, SGR_MOVE | SGR_PARENT);
}
/***************************************************************************\
*****************************************************************************
*
* class OldRectAnimation
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
OldRectAnimation::~OldRectAnimation()
{
Destroy(TRUE);
#if DEBUG_TRACECREATION
Trace("OldRectAnimation 0x%p destroyed\n", this);
#endif // DEBUG_TRACECREATION
}
//------------------------------------------------------------------------------
HRESULT
OldRectAnimation::Create(
IN GANI_DESC * pDesc)
{
HRESULT hr = OldAnimation::Create(&guidRectAnimation, &s_pridRect, pDesc);
if (FAILED(hr)) {
return hr;
}
//
// Get the information from the Gadget
//
GANI_RECTDESC * pDescR = (GANI_RECTDESC *) pDesc;
UINT nGetFlags = SGR_VALID_GET & pDescR->nChangeFlags;
if (nGetFlags == 0) {
return E_INVALIDARG;
}
if (TestFlag(pDesc->nAniFlags, ANIF_USESTART)) {
m_ptStart = pDescR->ptStart;
m_sizeStart = pDescR->sizeStart;
} else {
RECT rcGadget;
if (!::GetGadgetRect(m_hgadSubject, &rcGadget, nGetFlags)) {
return (HRESULT) GetLastError();
}
m_ptStart.x = rcGadget.left;
m_ptStart.y = rcGadget.top;
m_sizeStart.cx = rcGadget.right - rcGadget.left;
m_sizeStart.cy = rcGadget.bottom - rcGadget.top;
}
m_ptEnd = pDescR->ptEnd;
m_sizeEnd = pDescR->sizeEnd;
m_nChangeFlags = pDescR->nChangeFlags;
#if DEBUG_TRACECREATION
Trace("OldRectAnimation 0x%p on 0x%p initialized\n", m_hgadSubject, this);
#endif // DEBUG_TRACECREATION
return S_OK;
}
//------------------------------------------------------------------------------
STDMETHODIMP_(UINT)
OldRectAnimation::GetID() const
{
return ANIMATION_RECT;
}
//------------------------------------------------------------------------------
void
OldRectAnimation::Action(GMA_ACTIONINFO * pmai)
{
POINT ptNew;
SIZE sizeNew;
float flProgress = pmai->flProgress;
ptNew.x = Compute(m_pipol, flProgress, m_ptStart.x, m_ptEnd.x);
ptNew.y = Compute(m_pipol, flProgress, m_ptStart.y, m_ptEnd.y);
sizeNew.cx = Compute(m_pipol, flProgress, m_sizeStart.cx, m_sizeEnd.cx);
sizeNew.cy = Compute(m_pipol, flProgress, m_sizeStart.cy, m_sizeEnd.cy);
SetGadgetRect(m_hgadSubject, ptNew.x, ptNew.y, sizeNew.cx, sizeNew.cy, m_nChangeFlags);
}
/***************************************************************************\
*****************************************************************************
*
* class OldRotateAnimation
*
*****************************************************************************
\***************************************************************************/
//------------------------------------------------------------------------------
OldRotateAnimation::~OldRotateAnimation()
{
Destroy(TRUE);
#if DEBUG_TRACECREATION
Trace("OldRotateAnimation 0x%p destroyed\n", this);
#endif // DEBUG_TRACECREATION
}
//------------------------------------------------------------------------------
HRESULT
OldRotateAnimation::Create(
IN GANI_DESC * pDesc)
{
HRESULT hr = OldAnimation::Create(&guidRotateAnimation, &s_pridRotate, pDesc);
if (FAILED(hr)) {
return hr;
}
//
// Get the information from the Gadget
//
GANI_ROTATEDESC * pDescR = (GANI_ROTATEDESC *) pDesc;
if (TestFlag(pDesc->nAniFlags, ANIF_USESTART)) {
m_flStart = pDescR->flStart;
} else {
if (!::GetGadgetRotation(m_hgadSubject, &m_flStart)) {
return (HRESULT) GetLastError();
}
}
m_flEnd = pDescR->flEnd;
m_nDir = pDescR->nDir;
//
// Adjust the starting and ending angles so that we "move" in the correct
// direction. We do this by adding or subtracting full rotations depending
// on the "move" we are trying to accomplish.
//
switch (m_nDir)
{
case GANI_ROTATEDIRECTION_SHORT:
if (m_flStart < m_flEnd) {
while ((m_flEnd - m_flStart) > (float) PI) {
m_flStart += (float) (2 * PI);
}
} else {
while ((m_flStart - m_flEnd) > (float) PI) {
m_flStart -= (float) (2 * PI);
}
}
break;
case GANI_ROTATEDIRECTION_LONG:
if (m_flStart < m_flEnd) {
while ((m_flStart - m_flEnd) < (float) PI) {
m_flEnd -= (float) (2 * PI);
}
} else {
while ((m_flEnd - m_flStart) < (float) PI) {
m_flEnd += (float) (2 * PI);
}
}
break;
case GANI_ROTATEDIRECTION_CW:
while (m_flStart > m_flEnd) {
m_flEnd += (float) (2 * PI);
}
break;
case GANI_ROTATEDIRECTION_CCW:
while (m_flStart < m_flEnd) {
m_flStart += (float) (2 * PI);
}
break;
}
#if DEBUG_TRACECREATION
Trace("OldRotateAnimation 0x%p on 0x%p initialized\n", m_hgadSubject, this);
#endif // DEBUG_TRACECREATION
return S_OK;
}
//------------------------------------------------------------------------------
STDMETHODIMP_(UINT)
OldRotateAnimation::GetID() const
{
return ANIMATION_ROTATE;
}
//------------------------------------------------------------------------------
void
OldRotateAnimation::Action(GMA_ACTIONINFO * pmai)
{
float flProgress = pmai->flProgress;
float flAngleNew = Compute(m_pipol, flProgress, m_flStart, m_flEnd);
SetGadgetRotation(m_hgadSubject, flAngleNew);
}