animsand.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:55k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- // system
- #include <time.h>
- #include <math.h>
- // include
- #include "hxtypes.h"
- #include "hxwintyp.h"
- #include "hxcom.h"
- #include "hxxml.h"
- #include "smiltype.h"
- // pnmisc
- #include "hxwinver.h"
- // pncont
- #include "hxslist.h"
- // rnxmllib
- #include "hxxmlprs.h"
- // rmasmil
- #include "smlelem.h"
- #include "smlparse.h"
- #include "animattr.h"
- // smlrendr
- #include "smlrmlog.h"
- #include "animsand.h"
- // pndebug
- #include "hxheap.h"
- #include "debugout.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- CAnimationSandwichLayer::CAnimationSandwichLayer(CSmilAnimateElement* pElement,
- UINT32 ulAttrName,
- CSmilParser* pParser)
- {
- MLOG_LEAKCHECK("CON CAnimationSandwichLayer this=0x%08xn", this);
- m_pElement = NULL;
- m_ulAttrName = kAttrNameUnknown;
- m_pdPacedDist = NULL;
- m_pdPacedTime = NULL;
- m_bRecomputePace = FALSE;
- m_bFirstTime = TRUE;
- m_pSmilParser = pParser;
- m_ulLastTime = 0;
- m_ulDelay = 0;
- m_ulActiveDuration = 0;
- if (pElement && pElement->m_pNode)
- {
- // Make sure the attribute name makes sense
- // with this element. If this element
- // is NOT an <animateMotion>, then we expect
- // the attribute name in the element to match
- // the passed-in attribute name. If this
- // element IS <animateMotion>, then the passed-in
- // attribute should be either "left" or "top".
- if ((pElement->m_pNode->m_tag == SMILAnimateMotion &&
- (ulAttrName == kAttrNameLeft || ulAttrName == kAttrNameTop)) ||
- (pElement->m_pNode->m_tag != SMILAnimateMotion &&
- ulAttrName == (UINT32) pElement->m_ucAttributeName))
- {
- // Assign the members
- m_pElement = pElement;
- m_ulAttrName = ulAttrName;
- m_ulDelay = pElement->m_ulDelay;
- m_ulActiveDuration = pElement->m_ulActiveDuration;
- // Check if the "end" attribute constrains
- // the active duration.
- if (pElement->m_bEndOffsetSet)
- {
- UINT32 ulEndMinusBegin = ((UINT32) pElement->m_lEndOffset) - m_ulDelay;
- if (ulEndMinusBegin < m_ulActiveDuration)
- {
- m_ulActiveDuration = ulEndMinusBegin;
- }
- }
- // If we are a paced animation, then we need to
- // decide how we are going to compute the D()
- // and T() functions.
- if (pElement->m_ucCalcMode == kCalcModePaced)
- {
- // Now we need to determine if these functions should be
- // re-computed every time. We need to do this IF any
- // attributes are relative.
- BOOL bSomeRelative = FALSE;
- for (UINT32 i = 0; i < pElement->m_ulNumValues; i++)
- {
- if (pElement->m_ppValue[i])
- {
- for (UINT32 j = 0; j < CAttr::kVectorSize; j++)
- {
- if (pElement->m_ppValue[i]->IsRelative(j))
- {
- bSomeRelative = TRUE;
- }
- }
- }
- }
- if (bSomeRelative)
- {
- // We will have to recompute the functions
- // every time we evaluate
- m_bRecomputePace = TRUE;
- }
- }
- }
- }
- }
- CAnimationSandwichLayer::~CAnimationSandwichLayer()
- {
- MLOG_LEAKCHECK("DES CAnimationSandwichLayer this=0x%08xn", this);
- HX_VECTOR_DELETE(m_pdPacedDist);
- HX_VECTOR_DELETE(m_pdPacedTime);
- }
- const char* CAnimationSandwichLayer::GetAnimationElementID() const
- {
- const char* pRet = NULL;
- if (m_pElement &&
- m_pElement->m_pNode)
- {
- pRet = (const char*) m_pElement->m_pNode->m_id;
- }
- return pRet;
- }
- const char* CAnimationSandwichLayer::GetTargetElementID() const
- {
- const char* pRet = NULL;
- if (m_pElement && m_pElement->m_pTargetElementID)
- {
- pRet = (const char*) *m_pElement->m_pTargetElementID;
- }
- return pRet;
- }
- SMILNodeTag CAnimationSandwichLayer::GetTargetElementTag() const
- {
- SMILNodeTag eRet = SMILUnknown;
- if (m_pElement)
- {
- eRet = m_pElement->m_eTargetElementTag;
- }
- return eRet;
- }
- SMILNodeTag CAnimationSandwichLayer::GetAnimationElementTag() const
- {
- SMILNodeTag eRet = SMILUnknown;
- if (m_pElement && m_pElement->m_pNode)
- {
- eRet = m_pElement->m_pNode->m_tag;
- }
- return eRet;
- }
- BOOL CAnimationSandwichLayer::IsActive(UINT32 ulTime) const
- {
- BOOL bRet = FALSE;
- if (m_pElement && ulTime >= m_ulDelay)
- {
- if (m_pElement->m_bIndefiniteActiveDuration ||
- ulTime < m_ulDelay + m_ulActiveDuration)
- {
- // During the active duration - it's active
- bRet = TRUE;
- }
- }
- return bRet;
- }
- BOOL CAnimationSandwichLayer::IsFrozen(UINT32 ulTime) const
- {
- BOOL bRet = FALSE;
- if (m_pElement &&
- (m_pElement->m_eActualFill == FillFreeze ||
- m_pElement->m_eActualFill == FillHold))
- {
- if (!m_pElement->m_bIndefiniteActiveDuration)
- {
- if (ulTime >= m_ulDelay + m_ulActiveDuration)
- {
- // XXXMEH - now that we are calculating a remove
- // time for every timed element, we should be able
- // to use the m_ulRemoveTime. However, let's keep
- // the old code around "just in case".
- if (m_pElement->m_ulRemoveTime == ((UINT32) -1))
- {
- UINT32 ulRemoveTime = 0;
- HX_RESULT rv = m_pSmilParser->computeRemoveTime(m_pElement->m_pNode->m_id,
- ulRemoveTime);
- if (SUCCEEDED(rv))
- {
- m_pElement->m_ulRemoveTime = ulRemoveTime;
- }
- }
- if (ulTime <= m_pElement->m_ulRemoveTime)
- {
- bRet = TRUE;
- }
- }
- }
- }
- return bRet;
- }
- BOOL CAnimationSandwichLayer::IsActiveZeroBased(UINT32 ulTime) const
- {
- BOOL bRet = FALSE;
- if (m_pElement &&
- (m_pElement->m_bIndefiniteActiveDuration ||
- ulTime < m_ulActiveDuration))
- {
- // During the active duration - it's active
- bRet = TRUE;
- }
- return bRet;
- }
- BOOL CAnimationSandwichLayer::IsFrozenZeroBased(UINT32 ulTime) const
- {
- BOOL bRet = FALSE;
- if (m_pElement &&
- (m_pElement->m_eActualFill == FillFreeze ||
- m_pElement->m_eActualFill == FillHold))
- {
- if (!m_pElement->m_bIndefiniteActiveDuration)
- {
- if (ulTime >= m_ulActiveDuration)
- {
- if (ulTime <= (m_pElement->m_ulRemoveTime - m_ulDelay))
- {
- bRet = TRUE;
- }
- }
- }
- }
- return bRet;
- }
- BOOL CAnimationSandwichLayer::IsAdditive() const
- {
- BOOL bRet = FALSE;
- if (m_pElement)
- {
- if (m_pElement->m_ucAdditive == kAdditiveSum)
- {
- bRet = TRUE;
- }
- }
- return bRet;
- }
- BOOL CAnimationSandwichLayer::IsToAnimation() const
- {
- BOOL bRet = FALSE;
- if (m_pElement &&
- m_pElement->m_ucAnimationType == kAnimTypeTo)
- {
- bRet = TRUE;
- }
- return bRet;
- }
- CAttr CAnimationSandwichLayer::AnimationEffectFunction(UINT32 ulTime,
- CAttr* pUnder,
- CAttr* pDepend)
- {
- CAttr cRet;
- if (pUnder)
- {
- // Initialize to the underlying value
- cRet = *pUnder;
- // Compute the zero-based time
- UINT32 ulT = ulTime - m_ulDelay; // XXXMEH - is this right?
- // Compute the time after time manipulations
- UINT32 ulTM = ComputeFilteredSimpleTime(ulT);
- // Decide if we're active or frozen
- if (IsActiveZeroBased(ulT))
- {
- // Evaluate the cumulative animation function at this time
- cRet = CumulativeAnimationFunction(ulTM, pUnder, pDepend);
- // Now we need to check if we need to fire a repeatEvent.
- //
- // Compute which iteration the last time was in
- UINT32 ulLastIter = 0;
- if (m_pElement->m_ulSimpleDuration)
- {
- ulLastIter = m_ulLastTime / m_pElement->m_ulSimpleDuration;
- }
- // Compute which iteration we are currently in
- UINT32 ulThisIter = 0;
- if (m_pElement->m_ulSimpleDuration)
- {
- ulThisIter = ulTM / m_pElement->m_ulSimpleDuration;
- }
- // If we are in different iterations, then we will
- // assume that this is the first time in the new iteration
- // and we will fire a "repeatEvent"
- if (ulLastIter != ulThisIter &&
- m_pSmilParser)
- {
- m_pSmilParser->tryToResolveBeginEndEvents("repeatEvent",
- m_pElement->m_pNode->m_id,
- ulTime);
- // XXXMEH - temporarily, we will also fire a "repeat(x)" event
- char szTmp[32]; /* Flawfinder: ignore */
- sprintf(szTmp, "repeat(%lu)", ulThisIter); /* Flawfinder: ignore */
- m_pSmilParser->tryToResolveBeginEndEvents((const char*) szTmp,
- m_pElement->m_pNode->m_id,
- ulTime);
- }
- // Save the last time
- m_ulLastTime = ulTM;
- }
- else if (IsFrozenZeroBased(ulT))
- {
- // We are in the frozen period after the active duration
- //
- // Compute the remainder time
- // XXXMEH - TODO - most of the time this "frozen time"
- // calculation can be done once up front.
- UINT32 ulModTime = 0;
- // m_ulActiveDuration takes into speed modifications. We
- // need to undo this before we compute the remainder time.
- UINT32 ulNewAD = m_ulActiveDuration;
- if (m_pElement->m_dSpeed != 1.0)
- {
- double dNewAD = (double) ulNewAD * fabs(m_pElement->m_dSpeed);
- ulNewAD = (UINT32) floor(dNewAD + 0.5);
- }
- // m_ulSimpleDuration does NOT take into account autoReverse,
- // but m_ulActiveDuration does. So we need to add in the
- // effect of autoReverse to m_ulSimpleDuration
- UINT32 ulNewSD = m_pElement->m_ulSimpleDuration;
- if (m_pElement->m_bAutoReverse)
- {
- ulNewSD *= 2;
- }
- // Now we can compute the remainder time
- if (ulNewSD)
- {
- ulModTime = ulNewAD % ulNewSD;
- }
- // Now, our active duration an even multiple of simple duration?
- if (ulModTime)
- {
- // Active duration is NOT an even multiple of simple duration,
- // so we just evaluate the cumulative animation function
- // at the end of the active duration. Make sure
- // and pass the time through time manipulations.
- UINT32 ulADTM = ComputeFilteredSimpleTime(m_ulActiveDuration);
- cRet = CumulativeAnimationFunction(ulADTM, pUnder, pDepend);
- }
- else
- {
- // Active duration IS an even multiple of simple duration
- //
- // Are we cumulative or not?
- if (m_pElement->m_ucAccumulate == kAccumulateNone)
- {
- // We are non-cumulative - simply evaluate at the
- // simple duration. First pass the simple duration
- // through time manipulations
- UINT32 ulSD = m_pElement->m_ulSimpleDuration;
- if (m_pElement->m_bAutoReverse)
- {
- ulSD *= 2;
- }
- if (m_pElement->m_dSpeed != 1.0 &&
- m_pElement->m_dSpeed != 0.0)
- {
- double dSDSpeed = (double) ulSD / fabs(m_pElement->m_dSpeed);
- ulSD = (UINT32) floor(dSDSpeed + 0.5);
- }
- UINT32 ulSDTM = ComputeFilteredSimpleTime(ulSD);
- cRet = SimpleAnimationFunction(ulSDTM, pUnder, pDepend);
- }
- else
- {
- // We ARE cumulative
- //
- // Compute the multiple
- UINT32 ulMult = 1;
- UINT32 ulCumTime = 0;
- if (m_pElement->m_ulSimpleDuration)
- {
- if (m_pElement->m_bAutoReverse)
- {
- ulMult = m_ulActiveDuration / (2 * m_pElement->m_ulSimpleDuration);
- ulCumTime = 2 * m_pElement->m_ulSimpleDuration * (ulMult - 1);
- }
- else
- {
- ulMult = m_ulActiveDuration / m_pElement->m_ulSimpleDuration;
- ulCumTime = m_pElement->m_ulSimpleDuration * (ulMult - 1);
- }
- }
- // Compute the frozen value
- UINT32 ulCumTimeTM = ComputeFilteredSimpleTime(ulCumTime);
- CAttr cCum = CumulativeAnimationFunction(ulCumTimeTM, pUnder, pDepend);
- UINT32 ulSDTM = 0;
- if (m_pElement->m_bAutoReverse)
- {
- ulSDTM = ComputeFilteredSimpleTime(2 * m_pElement->m_ulSimpleDuration);
- }
- else
- {
- ulSDTM = ComputeFilteredSimpleTime(m_pElement->m_ulSimpleDuration);
- }
- cRet = SimpleAnimationFunction(ulSDTM, pUnder, pDepend);
- cRet.Add(&cCum, pDepend);
- }
- }
- // Save the last time
- m_ulLastTime = ulTM;
- }
- }
- return cRet;
- }
- BOOL CAnimationSandwichLayer::HigherPriority(CAnimationSandwichLayer* pLayer)
- {
- BOOL bRet = TRUE;
- if (pLayer)
- {
- if (m_ulDelay > pLayer->m_ulDelay)
- {
- // We start later than pLayer, so we're higher priority
- bRet = TRUE;
- }
- else if (m_ulDelay == pLayer->m_ulDelay)
- {
- // We start at the same time as pLayer, so the spec
- // says we first have to look at sync relationships
- if (m_pElement->m_BeginEventSourceID == pLayer->m_pElement->m_pNode->m_id)
- {
- // pLayer is our syncbase, so we are higher priority
- bRet = TRUE;
- }
- else if (pLayer->m_pElement->m_BeginEventSourceID == m_pElement->m_pNode->m_id)
- {
- // We are pLayer's syncbase, so pLayer is higher priority
- bRet = FALSE;
- }
- else
- {
- // There is no sync relationship between us and pLayer,
- // so we have to look at lexical order. First look at
- // the line the tag starts
- if (m_pElement->m_pNode->m_ulTagStartLine >
- pLayer->m_pElement->m_pNode->m_ulTagStartLine)
- {
- // We start lexically later, so we are
- // higher priority
- bRet = TRUE;
- }
- else if (m_pElement->m_pNode->m_ulTagStartLine ==
- pLayer->m_pElement->m_pNode->m_ulTagStartLine)
- {
- // We start on the same line, so look
- // at the starting column
- if (m_pElement->m_pNode->m_ulTagStartColumn >
- pLayer->m_pElement->m_pNode->m_ulTagStartColumn)
- {
- // We start lexically later, so we are
- // higher priority
- bRet = TRUE;
- }
- else if (m_pElement->m_pNode->m_ulTagStartColumn ==
- pLayer->m_pElement->m_pNode->m_ulTagStartColumn)
- {
- // Huh? How can a different element start at
- // the same line and column that we do? Probably
- // bogus, so make an arbitrary choice
- bRet = TRUE;
- }
- else
- {
- // We start lexically earlier, so we are NOT
- // higher priority
- bRet = FALSE;
- }
- }
- else
- {
- // We start lexically earlier, so we are NOT
- // higher priority
- bRet = FALSE;
- }
- }
- }
- else
- {
- // pLayer starts later than us, so it's higher priority
- bRet = FALSE;
- }
- }
- return bRet;
- }
- void CAnimationSandwichLayer::AdjustActiveDuration(UINT32 ulTime)
- {
- if (ulTime >= m_ulDelay)
- {
- m_ulActiveDuration = ulTime - m_ulDelay;
- }
- }
- CAttr CAnimationSandwichLayer::SimpleAnimationFunction(UINT32 ulTime,
- CAttr* pUnder,
- CAttr* pDepend)
- {
- CAttr cRet;
- if (pUnder)
- {
- // Initialize the return to the underlying value
- cRet = *pUnder;
- // Do we have an indefinite simple duration?
- if (m_pElement->m_bIndefiniteSimpleDuration)
- {
- // Our simple duration is indefinite, so interpolation
- // is not defined. We should set ourselves to value(0).
- //
- // What kind of animation are we?
- if (m_pElement->m_pNode->m_tag == SMILSet)
- {
- // If this is a set, then we know there is
- // only one values, so we need to just
- // set the value to m_ppValue[1]
- if (m_pElement->m_ppValue[1])
- {
- cRet = *m_pElement->m_ppValue[1];
- }
- }
- else if (m_pElement->m_ucAnimationType == kAnimTypeTo)
- {
- // If this is a to-animation, then value(0)
- // is the underlying value.
- cRet = *pUnder;
- }
- else
- {
- // Assign the value(0) if we have one
- if (m_pElement->m_ppValue[0])
- {
- cRet = *m_pElement->m_ppValue[0];
- }
- }
- }
- else
- {
- // Our simple duration is not indefinite
- //
- // We are just defined over the simple duration
- if (ulTime <= m_pElement->m_ulSimpleDuration)
- {
- if (m_pElement->m_pNode->m_tag == SMILSet)
- {
- // If this is a set, then we know there is
- // only two values, so we need to just
- // set the value to m_ppValue[1]
- if (m_pElement->m_ppValue[1])
- {
- cRet = *m_pElement->m_ppValue[1];
- }
- }
- else
- {
- // What is our calcmode?
- if (m_pElement->m_ucCalcMode == kCalcModeDiscrete)
- {
- // Divide the interval into m_ulNumValues segments
- UINT32 ulIndex = m_pElement->m_ulNumValues;
- if (m_pElement->m_ulSimpleDuration)
- {
- ulIndex = m_pElement->m_ulNumValues * ulTime / m_pElement->m_ulSimpleDuration;
- }
- // Make sure that m_pElement->m_ulSimpleDuration maps
- // to index m_ulNumValues - 1 and not m_ulNumValues
- if (ulIndex >= m_pElement->m_ulNumValues)
- {
- ulIndex = m_pElement->m_ulNumValues - 1;
- }
- // If we are a "to" animation, then m_ppValue[0] is
- // a placeholder for the underlying value. Therefore,
- // if we are a "to" animation and have selected index 0,
- // then we need to replace it by the underlying value
- if (m_pElement->m_ucAnimationType == kAnimTypeTo &&
- ulIndex == 0)
- {
- cRet = *pUnder;
- }
- else if (m_pElement->m_ucAnimationType == kAnimTypeFromBy &&
- ulIndex == 1)
- {
- // On a from-by animation, you are interpolating
- // between the from value and the sum of the from
- // and by values. m_ppValue[0] is the from value.
- // However, m_ppValue[1] is the by value, not the
- // sum of the from and by values. So if we have
- // chosen index 1, then we need to compute the sum
- // of the from and by values
- //
- if (m_pElement->m_ppValue[0] &&
- m_pElement->m_ppValue[1])
- {
- // First assign the from value
- cRet = *m_pElement->m_ppValue[0];
- // Then add the by value
- cRet.Add(m_pElement->m_ppValue[1], pDepend);
- }
- }
- else
- {
- // Simply return the proper value
- if (m_pElement->m_ppValue[ulIndex])
- {
- cRet = *m_pElement->m_ppValue[ulIndex];
- }
- }
- }
- else if (m_pElement->m_ucCalcMode == kCalcModeLinear ||
- (m_pElement->m_ucCalcMode == kCalcModePaced &&
- m_pElement->m_ulNumValues == 2))
- {
- // Is this a "to" animation?
- if (m_pElement->m_ucAnimationType == kAnimTypeTo)
- {
- // If we are a "to" animation, then we interpolate
- // between the underlying value and the "to" value,
- // which is (m_ppValue[1]).
- if (m_pElement->m_ppValue[1])
- {
- // Do the interpolation
- double t1 = 0.0;
- double t2 = (double) m_pElement->m_ulSimpleDuration;
- double t = ulTime;
- cRet.Interp(pUnder, t1, m_pElement->m_ppValue[1], t2, t, pDepend);
- }
- }
- else if (m_pElement->m_ucAnimationType == kAnimTypeFromBy)
- {
- // On a from-by animation, you are interpolating
- // between the from value and the sum of the from
- // and by values. m_ppValue[0] is the from value.
- // However, m_ppValue[1] is the by value, not the
- // sum of the from and by values. So we need to
- // compute the sum of the from and by values
- if (m_pElement->m_ppValue[0] &&
- m_pElement->m_ppValue[1])
- {
- CAttr cSum = *m_pElement->m_ppValue[0];
- cSum.Add(m_pElement->m_ppValue[1], pDepend);
- // Then we interpolate between m_ppValue[0] (the
- // "from" value) and cSum (the sum of the "from"
- // and "by" values).
- double t1 = 0.0;
- double t2 = (double) m_pElement->m_ulSimpleDuration;
- double t = (double) ulTime;
- cRet.Interp(m_pElement->m_ppValue[0], t1, &cSum, t2, t, pDepend);
- }
- }
- else
- {
- // Divide the interval into m_ulNumValues-1 segments
- UINT32 ulIndex = m_pElement->m_ulNumValues - 1;
- if (m_pElement->m_ulSimpleDuration)
- {
- ulIndex = (m_pElement->m_ulNumValues - 1) * ulTime / m_pElement->m_ulSimpleDuration;
- }
- // Now interpolate between this value and the next
- if (ulIndex + 1 < m_pElement->m_ulNumValues &&
- m_pElement->m_ppValue[ulIndex] &&
- m_pElement->m_ppValue[ulIndex + 1])
- {
- // Do the interpolation
- double t1 = ulIndex * m_pElement->m_ulSimpleDuration /
- (m_pElement->m_ulNumValues - 1);
- double t2 = (ulIndex + 1) * m_pElement->m_ulSimpleDuration /
- (m_pElement->m_ulNumValues - 1);
- double t = ulTime;
- cRet.Interp(m_pElement->m_ppValue[ulIndex], t1,
- m_pElement->m_ppValue[ulIndex + 1], t2,
- t, pDepend);
- }
- else
- {
- // The only way this can happen is if
- // ulTime == m_pElement->m_ulSimpleDuration, so if this
- // if the case, we need to return the un-interpolated
- // value of m_ppValue[m_pElement->m_ulNumValues - 1]
- if (m_pElement->m_ppValue[m_pElement->m_ulNumValues - 1])
- {
- cRet = *m_pElement->m_ppValue[m_pElement->m_ulNumValues - 1];
- }
- }
- }
- }
- else if (m_pElement->m_ucCalcMode == kCalcModePaced)
- {
- // If we need to recompute the paced tables,
- // then do it now
- if (m_bRecomputePace ||
- (!m_bRecomputePace && m_bFirstTime))
- {
- RecomputePace(pDepend);
- }
- // Find out what index we're at
- double t = (double) ulTime;
- UINT32 i = 0;
- for (i = 0; i < m_pElement->m_ulNumValues - 1; i++)
- {
- if (t >= m_pdPacedTime[i] && t <= m_pdPacedTime[i + 1])
- {
- break;
- }
- }
- if (i + 1 < m_pElement->m_ulNumValues)
- {
- // Do the interpolation
- cRet.Interp(m_pElement->m_ppValue[i], m_pdPacedTime[i],
- m_pElement->m_ppValue[i + 1], m_pdPacedTime[i + 1],
- (double) ulTime, pDepend);
- }
- }
- }
- // Now we can clear the first time flag
- m_bFirstTime = FALSE;
- }
- }
- }
- return cRet;
- }
- CAttr CAnimationSandwichLayer::CumulativeAnimationFunction(UINT32 ulTime,
- CAttr* pUnder,
- CAttr* pDepend)
- {
- CAttr cRet;
- if (pUnder)
- {
- // Initialize to the underlying value
- cRet = *pUnder;
- // Are we cumulative or not?
- if (m_pElement->m_ucAccumulate == kAccumulateSum)
- {
- // We are a cumulative animation
- //
- // Modulo the time by the simple duration
- UINT32 ulModTime = 0;
- if (m_pElement->m_ulSimpleDuration)
- {
- ulModTime = ulTime % m_pElement->m_ulSimpleDuration;
- }
- // Evaluate the simple animation function at this time
- CAttr cMod = SimpleAnimationFunction(ulModTime, pUnder, pDepend);
- // Find the iteration
- UINT32 ulIter = 0;
- if (m_pElement->m_ulSimpleDuration)
- {
- ulIter = ulTime / m_pElement->m_ulSimpleDuration;
- }
- if (ulIter)
- {
- // Evaluate the animation at the simple duration
- cRet = SimpleAnimationFunction(m_pElement->m_ulSimpleDuration,
- pUnder, pDepend);
- // Multiply by iteration value
- cRet.Mult((double) ulIter);
- // Add the simple animation result
- cRet.Add(&cMod, pDepend);
- }
- else
- {
- // We're on the first iteration
- cRet = cMod;
- }
- }
- else
- {
- // We are a non-cumulative animation
- //
- // Modulo the time by the simple duration
- UINT32 ulModTime = 0;
- if (m_pElement->m_ulSimpleDuration)
- {
- ulModTime = ulTime % m_pElement->m_ulSimpleDuration;
- }
- // Evaluate the simple animation function at this time
- cRet = SimpleAnimationFunction(ulModTime, pUnder, pDepend);
- }
- }
- return cRet;
- }
- void CAnimationSandwichLayer::RecomputePace(CAttr* pDepend)
- {
- if (!m_pdPacedDist)
- {
- m_pdPacedDist = new double [m_pElement->m_ulNumValues];
- if (m_pdPacedDist)
- {
- memset((void*) m_pdPacedDist, 0, sizeof(double) *
- m_pElement->m_ulNumValues);
- }
- }
- if (!m_pdPacedTime)
- {
- m_pdPacedTime = new double [m_pElement->m_ulNumValues];
- if (m_pdPacedTime)
- {
- memset((void*) m_pdPacedTime, 0, sizeof(double) *
- m_pElement->m_ulNumValues);
- }
- }
- if (m_pdPacedDist && m_pdPacedTime)
- {
- UINT32 i = 0;
- // Compute D()
- m_pdPacedDist[0] = 0.0;
- for (i = 1; i < m_pElement->m_ulNumValues; i++)
- {
- m_pdPacedDist[i] = m_pdPacedDist[i - 1] +
- CAttr::Dist(m_pElement->m_ppValue[i - 1],
- m_pElement->m_ppValue[i],
- pDepend);
- }
- // Compute T()
- double dTotal = m_pdPacedDist[m_pElement->m_ulNumValues - 1];
- for (i = 0; i < m_pElement->m_ulNumValues; i++)
- {
- m_pdPacedTime[i] = m_pdPacedDist[i] * m_pElement->m_ulSimpleDuration / dTotal;
- }
- }
- }
- UINT32 CAnimationSandwichLayer::ComputeFilteredSimpleTime(UINT32 ulUnfilteredActiveTime)
- {
- UINT32 ulRet = ulUnfilteredActiveTime;
- if (m_pElement &&
- (m_pElement->m_bAutoReverse ||
- m_pElement->m_dSpeed != 1.0 ||
- m_pElement->m_dAccelerate != 0.0 ||
- m_pElement->m_dDecelerate != 0.0))
- {
- // Compute the duration of the acceleration phase
- double dacc = ((double) m_pElement->m_ulSimpleDuration) *
- m_pElement->m_dAccelerate;
- // Compute the duration of the deceleration phase
- double ddec = ((double) m_pElement->m_ulSimpleDuration) *
- m_pElement->m_dDecelerate;
- // Compute the active filtered time (which takes
- // into account the speed attribute)
- double dActiveFilteredTime = 0.0;
- if (m_pElement->m_dSpeed > 0.0)
- {
- dActiveFilteredTime = ((double) ulUnfilteredActiveTime) *
- m_pElement->m_dSpeed;
- }
- else
- {
- dActiveFilteredTime = ((double) m_pElement->m_ulADNoSpeed) -
- (((double) ulUnfilteredActiveTime) *
- fabs(m_pElement->m_dSpeed));
- }
- // Compute the unfiltered simple time
- double dUnfilteredSimpleTime = dActiveFilteredTime;
- double dDur = (double) m_pElement->m_ulSimpleDuration;
- double dDurPrime = dDur;
- if (m_pElement->m_bAutoReverse)
- {
- dDurPrime *= 2.0;
- }
- // Is there any repeating behavior?
- if (m_pElement->m_dRepeatCount == 1.0 &&
- (m_pElement->m_ulRepeatDur == ((UINT32) -1) ||
- m_pElement->m_bRepeatDurIsIndefinite))
- {
- // No repeating behavior here, so unfiltered simple
- // time is equal to active filtered time
- dUnfilteredSimpleTime = dActiveFilteredTime;
- }
- else
- {
- // This animation repeats, so calcuate the
- // remainder
- if (dDurPrime != 0.0)
- {
- dUnfilteredSimpleTime =
- dActiveFilteredTime -
- dDurPrime * floor(dActiveFilteredTime / dDurPrime);
- }
- }
- // Account for autoReverse behavior
- double dUnfilteredSimpleTimePrime = dUnfilteredSimpleTime;
- if (m_pElement->m_bAutoReverse &&
- dUnfilteredSimpleTime >= dDur)
- {
- dUnfilteredSimpleTimePrime = (2.0 * dDur) - dUnfilteredSimpleTime;
- }
- // Compute the decel begin time
- double dDecelBegin = dDur - ddec;
- // Compute the filtered simple time
- double dFilteredSimpleTime = (double) dUnfilteredSimpleTimePrime;
- double dRDenom = 1.0 -
- (m_pElement->m_dAccelerate / 2.0) -
- (m_pElement->m_dDecelerate / 2.0);
- double dR = 1.0;
- if (dRDenom != 0.0)
- {
- dR = 1.0 / dRDenom;
- }
- if (dUnfilteredSimpleTimePrime >= 0.0 &&
- dUnfilteredSimpleTimePrime < dacc)
- {
- dFilteredSimpleTime = dUnfilteredSimpleTimePrime *
- ComputeRunRate(dUnfilteredSimpleTimePrime,
- m_pElement->m_dAccelerate,
- m_pElement->m_dDecelerate,
- dDur) / 2.0;
- }
- else if (dUnfilteredSimpleTimePrime >= dacc &&
- dUnfilteredSimpleTimePrime <= dDecelBegin)
- {
- dFilteredSimpleTime = dR * (dUnfilteredSimpleTimePrime - (dacc / 2.0));
- }
- else if (dUnfilteredSimpleTimePrime > dDecelBegin &&
- dUnfilteredSimpleTimePrime <= dDur)
- {
- double tdec = dUnfilteredSimpleTime - dDecelBegin;
- double pd = 1.0;
- if (ddec != 0.0)
- {
- pd = tdec / ddec;
- }
- dFilteredSimpleTime = dR * (dDur - (dacc / 2.0) - ddec +
- (tdec * (2.0 - pd) / 2.0));
- // Make sure we don't ever round up to dDur if
- // our input is less than dDur
- if (dUnfilteredSimpleTimePrime < dDur &&
- dFilteredSimpleTime >= dDur - 0.5)
- {
- dFilteredSimpleTime = dDur - 0.50000000001;
- }
- }
- // Now round to nearest integer
- ulRet = (UINT32) floor(dFilteredSimpleTime + 0.5);
- }
- return ulRet;
- }
- double CAnimationSandwichLayer::ComputeRunRate(double dT, double dAccel,
- double dDecel, double dDur)
- {
- double dRet = 1.0;
- double dacc = dDur * dAccel;
- double ddec = dDur * dDecel;
- double dRDenom = 1.0 - (dAccel / 2.0) - (dDecel / 2.0);
- if (dRDenom != 0.0)
- {
- double dR = 1.0 / dRDenom;
- // Compute the decel begin time
- double dDecBegin = dDur - ddec;
- // Now compute the run rate
- if (dT >= 0.0 && dT < dacc)
- {
- if (dacc != 0.0)
- {
- dRet = dR * dT / dacc;
- }
- }
- else if (dT >= dacc && dT <= dDecBegin)
- {
- dRet = dR;
- }
- else if (dT > dDecBegin && dT <= dDur)
- {
- if (ddec != 0.0)
- {
- dRet = dR * (dDur - dT) / ddec;
- }
- }
- }
- return dRet;
- }
- #if defined(XXXMEH_SPLINE_ANIMATION)
- double CAnimationSandwichLayer::ComputeSpline(double t, double t1, double t2,
- double v1, double v2, double x1,
- double y1, double x2, double y2)
- {
- double dRet = 0.0;
- if (x1 >= 0.0 && x1 <= 1.0 &&
- y1 >= 0.0 && y1 <= 1.0 &&
- x2 >= 0.0 && x2 <= 1.0 &&
- y2 >= 0.0 && y2 <= 1.0)
- {
- if (t2 >= t1)
- {
- if (t >= t1)
- {
- if (t <= t2)
- {
- if (t2 > t1)
- {
- // We compute the spline interpolation
- // in the following steps:
- // a) Scale the time down to unit time
- // b) Get the output bezier time (still in unit time)
- // c) Use this output time as the
- // input time for linear interpolation.
- //
- // Scale the time to unit time
- double dInUnitT = (t - t1) / (t2 - t1);
- // Get the output bezier time
- double dOutUnitT = ComputeBezierOutputTime(dUnitT, x1, y1, x2, y2);
- // Do a sanity check on the output time
- if (dOutUnitT < 0.0)
- {
- dOutUnitT = 0.0;
- HX_ASSERT(FALSE && "Bad value returned from ComputeBezierOutputTime()");
- }
- else if (dOutUnitT > 1.0)
- {
- dOutUnitT = 1.0;
- HX_ASSERT(FALSE && "Bad value returned from ComputeBezierOutputTime()");
- }
- // Use this time to linearly interpolate
- dRet = v1 + (v2 - v1) * dOutUnitT;
- }
- else
- {
- // t1 is equal to t2. So this is a discontinuous
- // interval, so by endpoint-exclusive logic [a,b),
- // we choose v2 for the output value. This is not
- // an input error, so we don't assert.
- dRet = v2;
- }
- }
- else
- {
- dRet = v2;
- HX_ASSERT(FALSE && "ComputeSpline(): t is greater than t2 - v2 assigned");
- }
- }
- else
- {
- dRet = v1;
- HX_ASSERT(FALSE && "ComputeSpline(): t is less than t1 - v1 assigned");
- }
- }
- else
- {
- HX_ASSERT(FALSE && "ComputeSpline(): t2 cannot be less than t1");
- }
- }
- else
- {
- HX_ASSERT(FALSE && "Illegal bezier control parameters in ComputeSpline()");
- }
- return dRet;
- }
- double CAnimationSandwichLayer::ComputeBezierOutputTime(double t,
- double x1, double y1,
- double x2, double y2)
- {
- double dRet = 0.0;
- if (t >= 0.0 && t <= 1.0 &&
- x1 >= 0.0 && x1 <= 1.0 &&
- y1 >= 0.0 && y1 <= 1.0 &&
- x2 >= 0.0 && x2 <= 1.0 &&
- y2 >= 0.0 && y2 <= 1.0)
- {
- // We get the output bezier-curve-warped time
- // by doing the following:
- //
- // a) Find q where x(q) = t
- // b) Compute y(q)
- //
- // Find the q where x(q) = t
- double dQ = SolveForBezierT(t, x1, x2, BEZIER_TOLERANCE);
- // Do a sanity check on this value
- if (dQ < 0.0)
- {
- dQ = 0.0;
- HX_ASSERT(FALSE && "Bad value returned from SolveForBezierT()");
- }
- else if (dQ > 1.0)
- {
- dQ = 1.0;
- HX_ASSERT(FALSE && "Bad value returned from SolveForBezierT()");
- }
- // Compute y(q)
- dRet = ComputeBezier(dQ, y1, y2);
- }
- else
- {
- HX_ASSERT(FALSE && "Illegal input parameters in ComputeBezierOutputTime()");
- }
- return dRet;
- }
- double CAnimationSandwichLayer::SolveForBezierT(double x, double x1,
- double x2, double tol)
- {
- double dRet = 0.0;
- if (x >= 0.0 && x <= 1.0 &&
- x1 >= 0.0 && x1 <= 1.0 &&
- x2 >= 0.0 && x2 <= 1.0 &&
- tol > 0.0 && tol <= 1.0)
- {
- double tL = 0.0;
- double xL = 0.0;
- double tR = 1.0;
- double xR = 1.0;
- double tM = 0.5;
- double xM = ComputeBezier(tM, x1, x2);
- UINT32 i = 0;
- while (fabs(xM - x) > tol &&
- i < BEZIER_MAX_ITERATIONS)
- {
- // Is our computed mid-point smaller or
- // larger than our desired value?
- if (xM > x)
- {
- // Take the left-hand interval
- tR = tM;
- }
- else
- {
- // Take the right-hand interval
- tL = tM;
- }
- // Compute new mid-point
- tM = (tL + tR) / 2.0;
- // Compute new value
- xM = ComputeBezier(tM, x1, x2);
- // Increment the iteration count
- ++i;
- }
- // Set the return value
- dRet = tM;
- // Check if we blew our max iteration count
- if (i >= BEZIER_MAX_ITERATIONS)
- {
- HX_ASSERT(FALSE && "SolveForBezierT(): Could not get within tolerance in max iterations");
- }
- }
- else
- {
- HX_ASSERT(FALSE && "Illegal input parameters in SolveForBezierT()");
- }
- return dRet;
- }
- double CAnimationSandwichLayer::ComputeBezier(double t, double a1, double a2)
- {
- double dRet = 0.0;
- if (t >= 0.0 && t <= 1.0 &&
- a1 >= 0.0 && a1 <= 1.0 &&
- a2 >= 0.0 && a2 <= 1.0)
- {
- double t2 = t * t;
- double t3 = t2 * t;
- double ti = 1.0 - t;
- double ti2 = ti * ti;
- dRet = 3.0 * t * ti2 * a1 +
- 3.0 * t2 * ti * a2 +
- t3;
- }
- else
- {
- HX_ASSERT(FALSE && "Illegal input parameters in ComputeBezier()");
- }
- return dRet;
- }
- #endif // #if defined(XXXMEH_SPLINE_ANIMATION)
- CAnimationSandwich::CAnimationSandwich(const char* pszTargetElementID,
- SMILNodeTag eTargetElementTag,
- UINT32 ulAttrName)
- {
- MLOG_LEAKCHECK("CON CAnimationSandwich this=0x%08xn", this);
- m_pTargetElementID = new CHXString(pszTargetElementID);
- m_eTargetElementTag = eTargetElementTag;
- m_ulAttrName = ulAttrName;
- m_pLayerList = NULL;
- }
- CAnimationSandwich::~CAnimationSandwich()
- {
- MLOG_LEAKCHECK("DES CAnimationSandwich this=0x%08xn", this);
- ClearAllLayers();
- HX_DELETE(m_pTargetElementID);
- HX_DELETE(m_pLayerList);
- }
- void CAnimationSandwich::ClearAllLayers()
- {
- if (m_pLayerList)
- {
- LISTPOSITION pos = m_pLayerList->GetHeadPosition();
- while (pos)
- {
- CAnimationSandwichLayer* pLayer = (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
- HX_DELETE(pLayer);
- }
- m_pLayerList->RemoveAll();
- }
- }
- const char* CAnimationSandwich::GetTargetElementID() const
- {
- const char* pRet = NULL;
- if (m_pTargetElementID)
- {
- pRet = (const char*) *m_pTargetElementID;
- }
- return pRet;
- }
- HX_RESULT CAnimationSandwich::AddLayer(CAnimationSandwichLayer* pLayer)
- {
- HX_RESULT retVal = HXR_OK;
- if (pLayer)
- {
- if (!m_pLayerList)
- {
- m_pLayerList = new CHXSimpleList();
- }
- if (m_pLayerList)
- {
- BOOL bAdded = FALSE;
- LISTPOSITION pos = m_pLayerList->GetHeadPosition();
- while (pos)
- {
- CAnimationSandwichLayer* pListLayer = (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
- if (pListLayer->HigherPriority(pLayer))
- {
- // The current layer in the list is higher priority
- // than the layer we want to add, so we must insert
- // ourselves BEFORE this layer
- m_pLayerList->InsertBefore(pos, (void*) pLayer);
- // Set the flag
- bAdded = TRUE;
- // Now jump out of the loop
- break;
- }
- m_pLayerList->GetNext(pos);
- }
- // If we didn't add ourselves, then that
- // means we are the highest priority, so
- // add ourselves to the tail of the list
- if (!bAdded)
- {
- m_pLayerList->AddTail((void*) pLayer);
- }
- }
- else
- {
- retVal = HXR_OUTOFMEMORY;
- }
- }
- return retVal;
- }
- void CAnimationSandwich::RemoveLayer(const char* pszAnimID)
- {
- if (pszAnimID && m_pLayerList)
- {
- LISTPOSITION pos = m_pLayerList->GetHeadPosition();
- while (pos)
- {
- CAnimationSandwichLayer* pLayer =
- (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
- if (pLayer &&
- pLayer->GetAnimationElementID() &&
- !strcmp(pszAnimID, pLayer->GetAnimationElementID()))
- {
- // We need to remove this layer
- //
- // First remove it from the list
- pos = m_pLayerList->RemoveAt(pos);
- // Next delete the object itself
- HX_DELETE(pLayer);
- }
- else
- {
- m_pLayerList->GetNext(pos);
- }
- }
- }
- }
- void CAnimationSandwich::FreezeLayers(const char* pszAnimID, UINT32 ulCurTime)
- {
- if (pszAnimID && m_pLayerList)
- {
- LISTPOSITION pos = m_pLayerList->GetHeadPosition();
- while (pos)
- {
- CAnimationSandwichLayer* pLayer =
- (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
- if (pLayer &&
- pLayer->GetAnimationElementID() &&
- !strcmp(pszAnimID, pLayer->GetAnimationElementID()) &&
- pLayer->IsActive(ulCurTime))
- {
- // We need to freeze this layer. We do this
- // by adjusting the layer's m_ulActiveDuration
- // such that pLayer->m_ulDelay + pLayer->m_ulActiveDuration
- // is equal to the current time.
- pLayer->AdjustActiveDuration(ulCurTime);
- }
- }
- }
- }
- CAttr CAnimationSandwich::GetValue(UINT32 ulTime, CAttr* pUnder, CAttr* pDepend)
- {
- CAttr cRet;
- if (pUnder)
- {
- // Initialize the running value
- CAttr cUnder(*pUnder);
- // Now run through the layers
- if (m_pLayerList)
- {
- LISTPOSITION pos = m_pLayerList->GetHeadPosition();
- while (pos)
- {
- CAnimationSandwichLayer* pLayer =
- (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
- if (pLayer &&
- (pLayer->IsActive(ulTime) ||
- pLayer->IsFrozen(ulTime)))
- {
- // Evaluate this layer
- CAttr cRes = pLayer->AnimationEffectFunction(ulTime, &cUnder, pDepend);
- // Now we either have to replace OR add
- if (pLayer->IsAdditive() &&
- !pLayer->IsToAnimation())
- {
- cUnder.Add(&cRes, pDepend);
- }
- else
- {
- cUnder = cRes;
- }
- }
- }
- }
- // Now set the return value
- cRet = cUnder;
- }
- return cRet;
- }
- UINT32 CAnimationSandwich::GetNumLayers() const
- {
- UINT32 ulRet = 0;
- if (m_pLayerList)
- {
- ulRet = m_pLayerList->GetCount();
- }
- return ulRet;
- }
- void CAnimationSandwich::AdjustLayers(UINT32 ulTime)
- {
- if (m_pLayerList)
- {
- LISTPOSITION pos = m_pLayerList->GetHeadPosition();
- while (pos)
- {
- CAnimationSandwichLayer* pLayer = (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
- if (!pLayer->IsActive(ulTime) &&
- !pLayer->IsFrozen(ulTime))
- {
- // We need to remove this layer
- //
- // First remove it from the list
- pos = m_pLayerList->RemoveAt(pos);
- // Next delete the object itself
- HX_DELETE(pLayer);
- }
- else
- {
- m_pLayerList->GetNext(pos);
- }
- }
- }
- }
- BOOL CAnimationSandwich::MatchingSandwich(CSmilAnimateElement* pAnim)
- {
- BOOL bRet = FALSE;
- if (pAnim &&
- pAnim->m_pTargetElementID &&
- m_pTargetElementID &&
- *pAnim->m_pTargetElementID == *m_pTargetElementID)
- {
- // We know that this animate element has the
- // same target element ID as we do. Now we
- // need to check if it has the same attributeName.
- // If the animate element is an <animateMotion>, then
- // our sandwich could be either left or top. If the
- // animate element is not <animateMotion>, then the
- // attributeName has to match exactly.
- if (pAnim->m_pNode &&
- pAnim->m_pNode->m_tag == SMILAnimateMotion)
- {
- if (m_ulAttrName == kAttrNameLeft ||
- m_ulAttrName == kAttrNameTop)
- {
- bRet = TRUE;
- }
- }
- else
- {
- UINT32 ulAttrName = pAnim->m_ucAttributeName;
- if (ulAttrName == m_ulAttrName)
- {
- bRet = TRUE;
- }
- }
- }
- return bRet;
- }
- BOOL CAnimationSandwich::AtLeastOneActiveLayer(UINT32 ulTime)
- {
- BOOL bRet = FALSE;
- if (m_pLayerList &&
- m_pLayerList->GetCount() > 0)
- {
- LISTPOSITION pos = m_pLayerList->GetHeadPosition();
- while (pos)
- {
- CAnimationSandwichLayer* pLayer =
- (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
- if (pLayer && pLayer->IsActive(ulTime))
- {
- bRet = TRUE;
- break;
- }
- }
- }
- return bRet;
- }
- CSmilAnimateInfo::CSmilAnimateInfo()
- {
- m_pSandwich = NULL;
- m_pUnder = NULL;
- m_pDepend = NULL;
- }
- CSmilAnimateInfo::~CSmilAnimateInfo()
- {
- HX_DELETE(m_pSandwich);
- HX_DELETE(m_pUnder);
- HX_DELETE(m_pDepend);
- }