animsand.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:55k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. // system
  36. #include <time.h>
  37. #include <math.h>
  38. // include
  39. #include "hxtypes.h"
  40. #include "hxwintyp.h"
  41. #include "hxcom.h"
  42. #include "hxxml.h"
  43. #include "smiltype.h"
  44. // pnmisc
  45. #include "hxwinver.h"
  46. // pncont
  47. #include "hxslist.h"
  48. // rnxmllib
  49. #include "hxxmlprs.h"
  50. // rmasmil
  51. #include "smlelem.h"
  52. #include "smlparse.h"
  53. #include "animattr.h"
  54. // smlrendr
  55. #include "smlrmlog.h"
  56. #include "animsand.h"
  57. // pndebug
  58. #include "hxheap.h"
  59. #include "debugout.h"
  60. #ifdef _DEBUG
  61. #undef HX_THIS_FILE
  62. static const char HX_THIS_FILE[] = __FILE__;
  63. #endif
  64. CAnimationSandwichLayer::CAnimationSandwichLayer(CSmilAnimateElement* pElement,
  65.                                                  UINT32               ulAttrName,
  66.                                                  CSmilParser*         pParser)
  67. {
  68.     MLOG_LEAKCHECK("CON CAnimationSandwichLayer this=0x%08xn", this);
  69.     m_pElement         = NULL;
  70.     m_ulAttrName       = kAttrNameUnknown;
  71.     m_pdPacedDist      = NULL;
  72.     m_pdPacedTime      = NULL;
  73.     m_bRecomputePace   = FALSE;
  74.     m_bFirstTime       = TRUE;
  75.     m_pSmilParser      = pParser;
  76.     m_ulLastTime       = 0;
  77.     m_ulDelay          = 0;
  78.     m_ulActiveDuration = 0;
  79.     if (pElement && pElement->m_pNode)
  80.     {
  81.         // Make sure the attribute name makes sense
  82.         // with this element. If this element
  83.         // is NOT an <animateMotion>, then we expect
  84.         // the attribute name in the element to match
  85.         // the passed-in attribute name. If this 
  86.         // element IS <animateMotion>, then the passed-in
  87.         // attribute should be either "left" or "top".
  88.         if ((pElement->m_pNode->m_tag == SMILAnimateMotion &&
  89.              (ulAttrName == kAttrNameLeft || ulAttrName == kAttrNameTop)) ||
  90.             (pElement->m_pNode->m_tag != SMILAnimateMotion &&
  91.              ulAttrName == (UINT32) pElement->m_ucAttributeName))
  92.         {
  93.             // Assign the members
  94.             m_pElement         = pElement;
  95.             m_ulAttrName       = ulAttrName;
  96.             m_ulDelay          = pElement->m_ulDelay;
  97.             m_ulActiveDuration = pElement->m_ulActiveDuration;
  98.             // Check if the "end" attribute constrains
  99.             // the active duration.
  100.             if (pElement->m_bEndOffsetSet)
  101.             {
  102.                 UINT32 ulEndMinusBegin = ((UINT32) pElement->m_lEndOffset) - m_ulDelay;
  103.                 if (ulEndMinusBegin < m_ulActiveDuration)
  104.                 {
  105.                     m_ulActiveDuration = ulEndMinusBegin;
  106.                 }
  107.             }
  108.             // If we are a paced animation, then we need to
  109.             // decide how we are going to compute the D()
  110.             // and T() functions.
  111.             if (pElement->m_ucCalcMode == kCalcModePaced)
  112.             {
  113.                 // Now we need to determine if these functions should be
  114.                 // re-computed every time. We need to do this IF any
  115.                 // attributes are relative.
  116.                 BOOL bSomeRelative = FALSE;
  117.                 for (UINT32 i = 0; i < pElement->m_ulNumValues; i++)
  118.                 {
  119.                     if (pElement->m_ppValue[i])
  120.                     {
  121.                         for (UINT32 j = 0; j < CAttr::kVectorSize; j++)
  122.                         {
  123.                             if (pElement->m_ppValue[i]->IsRelative(j))
  124.                             {
  125.                                 bSomeRelative = TRUE;
  126.                             }
  127.                         }
  128.                     }
  129.                 }
  130.                 if (bSomeRelative)
  131.                 {
  132.                     // We will have to recompute the functions
  133.                     // every time we evaluate
  134.                     m_bRecomputePace = TRUE;
  135.                 }
  136.             }
  137.         }
  138.     }
  139. }
  140. CAnimationSandwichLayer::~CAnimationSandwichLayer()
  141. {
  142.     MLOG_LEAKCHECK("DES CAnimationSandwichLayer this=0x%08xn", this);
  143.     HX_VECTOR_DELETE(m_pdPacedDist);
  144.     HX_VECTOR_DELETE(m_pdPacedTime);
  145. }
  146. const char* CAnimationSandwichLayer::GetAnimationElementID() const
  147. {
  148.     const char* pRet = NULL;
  149.     if (m_pElement &&
  150.         m_pElement->m_pNode)
  151.     {
  152.         pRet = (const char*) m_pElement->m_pNode->m_id;
  153.     }
  154.     return pRet;
  155. }
  156. const char* CAnimationSandwichLayer::GetTargetElementID() const
  157. {
  158.     const char* pRet = NULL;
  159.     if (m_pElement && m_pElement->m_pTargetElementID)
  160.     {
  161.         pRet = (const char*) *m_pElement->m_pTargetElementID;
  162.     }
  163.     return pRet;
  164. }
  165. SMILNodeTag CAnimationSandwichLayer::GetTargetElementTag() const
  166. {
  167.     SMILNodeTag eRet = SMILUnknown;
  168.     if (m_pElement)
  169.     {
  170.         eRet = m_pElement->m_eTargetElementTag;
  171.     }
  172.     return eRet;
  173. }
  174. SMILNodeTag CAnimationSandwichLayer::GetAnimationElementTag() const
  175. {
  176.     SMILNodeTag eRet = SMILUnknown;
  177.     if (m_pElement && m_pElement->m_pNode)
  178.     {
  179.         eRet = m_pElement->m_pNode->m_tag;
  180.     }
  181.     return eRet;
  182. }
  183. BOOL CAnimationSandwichLayer::IsActive(UINT32 ulTime) const
  184. {
  185.     BOOL bRet = FALSE;
  186.     if (m_pElement && ulTime >= m_ulDelay)
  187.     {
  188.         if (m_pElement->m_bIndefiniteActiveDuration ||
  189.             ulTime < m_ulDelay + m_ulActiveDuration)
  190.         {
  191.             // During the active duration - it's active
  192.             bRet = TRUE;
  193.         }
  194.     }
  195.     return bRet;
  196. }
  197. BOOL CAnimationSandwichLayer::IsFrozen(UINT32 ulTime) const
  198. {
  199.     BOOL bRet = FALSE;
  200.     if (m_pElement &&
  201.         (m_pElement->m_eActualFill == FillFreeze ||
  202.          m_pElement->m_eActualFill == FillHold))
  203.     {
  204.         if (!m_pElement->m_bIndefiniteActiveDuration)
  205.         {
  206.             if (ulTime >= m_ulDelay + m_ulActiveDuration)
  207.             {
  208.                 // XXXMEH - now that we are calculating a remove
  209.                 // time for every timed element, we should be able
  210.                 // to use the m_ulRemoveTime. However, let's keep
  211.                 // the old code around "just in case".
  212.                 if (m_pElement->m_ulRemoveTime == ((UINT32) -1))
  213.                 {
  214.                     UINT32 ulRemoveTime = 0;
  215.                     HX_RESULT rv = m_pSmilParser->computeRemoveTime(m_pElement->m_pNode->m_id,
  216.                                                                     ulRemoveTime);
  217.                     if (SUCCEEDED(rv))
  218.                     {
  219.                         m_pElement->m_ulRemoveTime = ulRemoveTime;
  220.                     }
  221.                 }
  222.                 if (ulTime <= m_pElement->m_ulRemoveTime)
  223.                 {
  224.                     bRet = TRUE;
  225.                 }
  226.             }
  227.         }
  228.     }
  229.     return bRet;
  230. }
  231. BOOL CAnimationSandwichLayer::IsActiveZeroBased(UINT32 ulTime) const
  232. {
  233.     BOOL bRet = FALSE;
  234.     if (m_pElement &&
  235.         (m_pElement->m_bIndefiniteActiveDuration ||
  236.          ulTime < m_ulActiveDuration))
  237.     {
  238.         // During the active duration - it's active
  239.         bRet = TRUE;
  240.     }
  241.     return bRet;
  242. }
  243. BOOL CAnimationSandwichLayer::IsFrozenZeroBased(UINT32 ulTime) const
  244. {
  245.     BOOL bRet = FALSE;
  246.     if (m_pElement &&
  247.         (m_pElement->m_eActualFill == FillFreeze ||
  248.          m_pElement->m_eActualFill == FillHold))
  249.     {
  250.         if (!m_pElement->m_bIndefiniteActiveDuration)
  251.         {
  252.             if (ulTime >= m_ulActiveDuration)
  253.             {
  254.                 if (ulTime <= (m_pElement->m_ulRemoveTime - m_ulDelay))
  255.                 {
  256.                     bRet = TRUE;
  257.                 }
  258.             }
  259.         }
  260.     }
  261.     return bRet;
  262. }
  263. BOOL CAnimationSandwichLayer::IsAdditive() const
  264. {
  265.     BOOL bRet = FALSE;
  266.     if (m_pElement)
  267.     {
  268.         if (m_pElement->m_ucAdditive == kAdditiveSum)
  269.         {
  270.             bRet = TRUE;
  271.         }
  272.     }
  273.     return bRet;
  274. }
  275. BOOL CAnimationSandwichLayer::IsToAnimation() const
  276. {
  277.     BOOL bRet = FALSE;
  278.     if (m_pElement &&
  279.         m_pElement->m_ucAnimationType == kAnimTypeTo)
  280.     {
  281.         bRet = TRUE;
  282.     }
  283.     return bRet;
  284. }
  285. CAttr CAnimationSandwichLayer::AnimationEffectFunction(UINT32 ulTime,
  286.                                                        CAttr* pUnder,
  287.                                                        CAttr* pDepend)
  288. {
  289.     CAttr cRet;
  290.     if (pUnder)
  291.     {
  292.         // Initialize to the underlying value
  293.         cRet = *pUnder;
  294.         // Compute the zero-based time
  295.         UINT32 ulT = ulTime - m_ulDelay; // XXXMEH - is this right?
  296.         // Compute the time after time manipulations
  297.         UINT32 ulTM = ComputeFilteredSimpleTime(ulT);
  298.         // Decide if we're active or frozen
  299.         if (IsActiveZeroBased(ulT))
  300.         {
  301.             // Evaluate the cumulative animation function at this time
  302.             cRet = CumulativeAnimationFunction(ulTM, pUnder, pDepend);
  303.             // Now we need to check if we need to fire a repeatEvent.
  304.             //
  305.             // Compute which iteration the last time was in
  306.             UINT32 ulLastIter = 0;
  307.             if (m_pElement->m_ulSimpleDuration)
  308.             {
  309.                 ulLastIter = m_ulLastTime / m_pElement->m_ulSimpleDuration;
  310.             }
  311.             // Compute which iteration we are currently in
  312.             UINT32 ulThisIter = 0;
  313.             if (m_pElement->m_ulSimpleDuration)
  314.             {
  315.                 ulThisIter = ulTM / m_pElement->m_ulSimpleDuration;
  316.             }
  317.             // If we are in different iterations, then we will
  318.             // assume that this is the first time in the new iteration
  319.             // and we will fire a "repeatEvent"
  320.             if (ulLastIter != ulThisIter &&
  321.                 m_pSmilParser)
  322.             {
  323.                 m_pSmilParser->tryToResolveBeginEndEvents("repeatEvent",
  324.                                                           m_pElement->m_pNode->m_id,
  325.                                                           ulTime);
  326.                 // XXXMEH - temporarily, we will also fire a "repeat(x)" event
  327.                 char szTmp[32]; /* Flawfinder: ignore */
  328.                 sprintf(szTmp, "repeat(%lu)", ulThisIter); /* Flawfinder: ignore */
  329.                 m_pSmilParser->tryToResolveBeginEndEvents((const char*) szTmp,
  330.                                                           m_pElement->m_pNode->m_id,
  331.                                                           ulTime);
  332.             }
  333.             // Save the last time
  334.             m_ulLastTime = ulTM;
  335.         }
  336.         else if (IsFrozenZeroBased(ulT))
  337.         {
  338.             // We are in the frozen period after the active duration
  339.             //
  340.             // Compute the remainder time
  341.             // XXXMEH - TODO - most of the time this "frozen time"
  342.             // calculation can be done once up front.
  343.             UINT32 ulModTime = 0;
  344.             // m_ulActiveDuration takes into speed modifications. We
  345.             // need to undo this before we compute the remainder time.
  346.             UINT32 ulNewAD = m_ulActiveDuration;
  347.             if (m_pElement->m_dSpeed != 1.0)
  348.             {
  349.                 double dNewAD = (double) ulNewAD * fabs(m_pElement->m_dSpeed);
  350.                 ulNewAD       = (UINT32) floor(dNewAD + 0.5);
  351.             }
  352.             // m_ulSimpleDuration does NOT take into account autoReverse,
  353.             // but m_ulActiveDuration does. So we need to add in the
  354.             // effect of autoReverse to m_ulSimpleDuration
  355.             UINT32 ulNewSD = m_pElement->m_ulSimpleDuration;
  356.             if (m_pElement->m_bAutoReverse)
  357.             {
  358.                 ulNewSD *= 2;
  359.             }
  360.             // Now we can compute the remainder time
  361.             if (ulNewSD)
  362.             {
  363.                 ulModTime = ulNewAD % ulNewSD;
  364.             }
  365.             // Now, our active duration an even multiple of simple duration?
  366.             if (ulModTime)
  367.             {
  368.                 // Active duration is NOT an even multiple of simple duration,
  369.                 // so we just evaluate the cumulative animation function
  370.                 // at the end of the active duration. Make sure
  371.                 // and pass the time through time manipulations.
  372.                 UINT32 ulADTM = ComputeFilteredSimpleTime(m_ulActiveDuration);
  373.                 cRet = CumulativeAnimationFunction(ulADTM, pUnder, pDepend);
  374.             }
  375.             else
  376.             {
  377.                 // Active duration IS an even multiple of simple duration
  378.                 //
  379.                 // Are we cumulative or not?
  380.                 if (m_pElement->m_ucAccumulate == kAccumulateNone)
  381.                 {
  382.                     // We are non-cumulative - simply evaluate at the
  383.                     // simple duration. First pass the simple duration
  384.                     // through time manipulations
  385.                     UINT32 ulSD = m_pElement->m_ulSimpleDuration;
  386.                     if (m_pElement->m_bAutoReverse)
  387.                     {
  388.                         ulSD *= 2;
  389.                     }
  390.                     if (m_pElement->m_dSpeed != 1.0 &&
  391.                         m_pElement->m_dSpeed != 0.0)
  392.                     {
  393.                         double dSDSpeed = (double) ulSD / fabs(m_pElement->m_dSpeed);
  394.                         ulSD = (UINT32) floor(dSDSpeed + 0.5);
  395.                     }
  396.                     UINT32 ulSDTM = ComputeFilteredSimpleTime(ulSD);
  397.                     cRet = SimpleAnimationFunction(ulSDTM, pUnder, pDepend);
  398.                 }
  399.                 else
  400.                 {
  401.                     // We ARE cumulative
  402.                     //
  403.                     // Compute the multiple
  404.                     UINT32 ulMult    = 1;
  405.                     UINT32 ulCumTime = 0;
  406.                     if (m_pElement->m_ulSimpleDuration)
  407.                     {
  408.                         if (m_pElement->m_bAutoReverse)
  409.                         {
  410.                             ulMult    = m_ulActiveDuration / (2 * m_pElement->m_ulSimpleDuration);
  411.                             ulCumTime = 2 * m_pElement->m_ulSimpleDuration * (ulMult - 1);
  412.                         }
  413.                         else
  414.                         {
  415.                             ulMult    = m_ulActiveDuration / m_pElement->m_ulSimpleDuration;
  416.                             ulCumTime = m_pElement->m_ulSimpleDuration * (ulMult - 1);
  417.                         }
  418.                     }
  419.                     // Compute the frozen value
  420.                     UINT32 ulCumTimeTM = ComputeFilteredSimpleTime(ulCumTime);
  421.                     CAttr cCum  = CumulativeAnimationFunction(ulCumTimeTM, pUnder, pDepend);
  422.                     UINT32 ulSDTM = 0;
  423.                     if (m_pElement->m_bAutoReverse)
  424.                     {
  425.                         ulSDTM = ComputeFilteredSimpleTime(2 * m_pElement->m_ulSimpleDuration);
  426.                     }
  427.                     else
  428.                     {
  429.                         ulSDTM = ComputeFilteredSimpleTime(m_pElement->m_ulSimpleDuration);
  430.                     }
  431.                     cRet = SimpleAnimationFunction(ulSDTM, pUnder, pDepend);
  432.                     cRet.Add(&cCum, pDepend);
  433.                 }
  434.             }
  435.             // Save the last time
  436.             m_ulLastTime = ulTM;
  437.         }
  438.     }
  439.     return cRet;
  440. }
  441. BOOL CAnimationSandwichLayer::HigherPriority(CAnimationSandwichLayer* pLayer)
  442. {
  443.     BOOL bRet = TRUE;
  444.     if (pLayer)
  445.     {
  446.         if (m_ulDelay > pLayer->m_ulDelay)
  447.         {
  448.             // We start later than pLayer, so we're higher priority
  449.             bRet = TRUE;
  450.         }
  451.         else if (m_ulDelay == pLayer->m_ulDelay)
  452.         {
  453.             // We start at the same time as pLayer, so the spec
  454.             // says we first have to look at sync relationships
  455.             if (m_pElement->m_BeginEventSourceID == pLayer->m_pElement->m_pNode->m_id)
  456.             {
  457.                 // pLayer is our syncbase, so we are higher priority
  458.                 bRet = TRUE;
  459.             }
  460.             else if (pLayer->m_pElement->m_BeginEventSourceID == m_pElement->m_pNode->m_id)
  461.             {
  462.                 // We are pLayer's syncbase, so pLayer is higher priority
  463.                 bRet = FALSE;
  464.             }
  465.             else
  466.             {
  467.                 // There is no sync relationship between us and pLayer,
  468.                 // so we have to look at lexical order. First look at
  469.                 // the line the tag starts
  470.                 if (m_pElement->m_pNode->m_ulTagStartLine >
  471.                     pLayer->m_pElement->m_pNode->m_ulTagStartLine)
  472.                 {
  473.                     // We start lexically later, so we are 
  474.                     // higher priority
  475.                     bRet = TRUE;
  476.                 }
  477.                 else if (m_pElement->m_pNode->m_ulTagStartLine ==
  478.                          pLayer->m_pElement->m_pNode->m_ulTagStartLine)
  479.                 {
  480.                     // We start on the same line, so look
  481.                     // at the starting column
  482.                     if (m_pElement->m_pNode->m_ulTagStartColumn >
  483.                         pLayer->m_pElement->m_pNode->m_ulTagStartColumn)
  484.                     {
  485.                         // We start lexically later, so we are 
  486.                         // higher priority
  487.                         bRet = TRUE;
  488.                     }
  489.                     else if (m_pElement->m_pNode->m_ulTagStartColumn ==
  490.                              pLayer->m_pElement->m_pNode->m_ulTagStartColumn)
  491.                     {
  492.                         // Huh? How can a different element start at
  493.                         // the same line and column that we do? Probably
  494.                         // bogus, so make an arbitrary choice
  495.                         bRet = TRUE;
  496.                     }
  497.                     else
  498.                     {
  499.                         // We start lexically earlier, so we are NOT
  500.                         // higher priority
  501.                         bRet = FALSE;
  502.                     }
  503.                 }
  504.                 else
  505.                 {
  506.                     // We start lexically earlier, so we are NOT
  507.                     // higher priority
  508.                     bRet = FALSE;
  509.                 }
  510.             }
  511.         }
  512.         else
  513.         {
  514.             // pLayer starts later than us, so it's higher priority
  515.             bRet = FALSE;
  516.         }
  517.     }
  518.     return bRet;
  519. }
  520. void CAnimationSandwichLayer::AdjustActiveDuration(UINT32 ulTime)
  521. {
  522.     if (ulTime >= m_ulDelay)
  523.     {
  524.         m_ulActiveDuration = ulTime - m_ulDelay;
  525.     }
  526. }
  527. CAttr CAnimationSandwichLayer::SimpleAnimationFunction(UINT32 ulTime,
  528.                                                        CAttr* pUnder,
  529.                                                        CAttr* pDepend)
  530. {
  531.     CAttr cRet;
  532.     if (pUnder)
  533.     {
  534.         // Initialize the return to the underlying value
  535.         cRet = *pUnder;
  536.         // Do we have an indefinite simple duration?
  537.         if (m_pElement->m_bIndefiniteSimpleDuration)
  538.         {
  539.             // Our simple duration is indefinite, so interpolation
  540.             // is not defined. We should set ourselves to value(0).
  541.             //
  542.             // What kind of animation are we?
  543.             if (m_pElement->m_pNode->m_tag == SMILSet)
  544.             {
  545.                 // If this is a set, then we know there is
  546.                 // only one values, so we need to just
  547.                 // set the value to m_ppValue[1]
  548.                 if (m_pElement->m_ppValue[1])
  549.                 {
  550.                     cRet = *m_pElement->m_ppValue[1];
  551.                 }
  552.             }
  553.             else if (m_pElement->m_ucAnimationType == kAnimTypeTo)
  554.             {
  555.                 // If this is a to-animation, then value(0)
  556.                 // is the underlying value.
  557.                 cRet = *pUnder;
  558.             }
  559.             else
  560.             {
  561.                 // Assign the value(0) if we have one
  562.                 if (m_pElement->m_ppValue[0])
  563.                 {
  564.                     cRet = *m_pElement->m_ppValue[0];
  565.                 }
  566.             }
  567.         }
  568.         else
  569.         {
  570.             // Our simple duration is not indefinite
  571.             //
  572.             // We are just defined over the simple duration
  573.             if (ulTime <= m_pElement->m_ulSimpleDuration)
  574.             {
  575.                 if (m_pElement->m_pNode->m_tag == SMILSet)
  576.                 {
  577.                     // If this is a set, then we know there is
  578.                     // only two values, so we need to just
  579.                     // set the value to m_ppValue[1]
  580.                     if (m_pElement->m_ppValue[1])
  581.                     {
  582.                         cRet = *m_pElement->m_ppValue[1];
  583.                     }
  584.                 }
  585.                 else
  586.                 {
  587.                     // What is our calcmode?
  588.                     if (m_pElement->m_ucCalcMode == kCalcModeDiscrete)
  589.                     {
  590.                         // Divide the interval into m_ulNumValues segments
  591.                         UINT32 ulIndex = m_pElement->m_ulNumValues;
  592.                         if (m_pElement->m_ulSimpleDuration)
  593.                         {
  594.                             ulIndex = m_pElement->m_ulNumValues * ulTime / m_pElement->m_ulSimpleDuration;
  595.                         }
  596.                         // Make sure that m_pElement->m_ulSimpleDuration maps
  597.                         // to index m_ulNumValues - 1 and not m_ulNumValues
  598.                         if (ulIndex >= m_pElement->m_ulNumValues)
  599.                         {
  600.                             ulIndex = m_pElement->m_ulNumValues - 1;
  601.                         }
  602.                         // If we are a "to" animation, then m_ppValue[0] is
  603.                         // a placeholder for the underlying value. Therefore,
  604.                         // if we are a "to" animation and have selected index 0,
  605.                         // then we need to replace it by the underlying value
  606.                         if (m_pElement->m_ucAnimationType == kAnimTypeTo &&
  607.                             ulIndex == 0)
  608.                         {
  609.                             cRet = *pUnder;
  610.                         }
  611.                         else if (m_pElement->m_ucAnimationType == kAnimTypeFromBy &&
  612.                                  ulIndex == 1)
  613.                         {
  614.                             // On a from-by animation, you are interpolating
  615.                             // between the from value and the sum of the from
  616.                             // and by values. m_ppValue[0] is the from value.
  617.                             // However, m_ppValue[1] is the by value, not the
  618.                             // sum of the from and by values. So if we have
  619.                             // chosen index 1, then we need to compute the sum
  620.                             // of the from and by values
  621.                             //
  622.                             if (m_pElement->m_ppValue[0] &&
  623.                                 m_pElement->m_ppValue[1])
  624.                             {
  625.                                 // First assign the from value
  626.                                 cRet = *m_pElement->m_ppValue[0];
  627.                                 // Then add the by value
  628.                                 cRet.Add(m_pElement->m_ppValue[1], pDepend);
  629.                             }
  630.                         }
  631.                         else
  632.                         {
  633.                             // Simply return the proper value
  634.                             if (m_pElement->m_ppValue[ulIndex])
  635.                             {
  636.                                 cRet = *m_pElement->m_ppValue[ulIndex];
  637.                             }
  638.                         }
  639.                     }
  640.                     else if (m_pElement->m_ucCalcMode == kCalcModeLinear ||
  641.                              (m_pElement->m_ucCalcMode == kCalcModePaced &&
  642.                               m_pElement->m_ulNumValues == 2))
  643.                     {
  644.                         // Is this a "to" animation?
  645.                         if (m_pElement->m_ucAnimationType == kAnimTypeTo)
  646.                         {
  647.                             // If we are a "to" animation, then we interpolate
  648.                             // between the underlying value and the "to" value,
  649.                             // which is (m_ppValue[1]).
  650.                             if (m_pElement->m_ppValue[1])
  651.                             {
  652.                                 // Do the interpolation
  653.                                 double t1 = 0.0;
  654.                                 double t2 = (double) m_pElement->m_ulSimpleDuration;
  655.                                 double t  = ulTime;
  656.                                 cRet.Interp(pUnder, t1, m_pElement->m_ppValue[1], t2, t, pDepend);
  657.                             }
  658.                         }
  659.                         else if (m_pElement->m_ucAnimationType == kAnimTypeFromBy)
  660.                         {
  661.                             // On a from-by animation, you are interpolating
  662.                             // between the from value and the sum of the from
  663.                             // and by values. m_ppValue[0] is the from value.
  664.                             // However, m_ppValue[1] is the by value, not the
  665.                             // sum of the from and by values. So we need to
  666.                             // compute the sum of the from and by values
  667.                             if (m_pElement->m_ppValue[0] &&
  668.                                 m_pElement->m_ppValue[1])
  669.                             {
  670.                                 CAttr cSum = *m_pElement->m_ppValue[0];
  671.                                 cSum.Add(m_pElement->m_ppValue[1], pDepend);
  672.                                 // Then we interpolate between m_ppValue[0] (the
  673.                                 // "from" value) and cSum (the sum of the "from"
  674.                                 // and "by" values).
  675.                                 double t1 = 0.0;
  676.                                 double t2 = (double) m_pElement->m_ulSimpleDuration;
  677.                                 double t  = (double) ulTime;
  678.                                 cRet.Interp(m_pElement->m_ppValue[0], t1, &cSum, t2, t, pDepend);
  679.                             }
  680.                         }
  681.                         else
  682.                         {
  683.                             // Divide the interval into m_ulNumValues-1 segments
  684.                             UINT32 ulIndex = m_pElement->m_ulNumValues - 1;
  685.                             if (m_pElement->m_ulSimpleDuration)
  686.                             {
  687.                                 ulIndex = (m_pElement->m_ulNumValues - 1) * ulTime / m_pElement->m_ulSimpleDuration;
  688.                             }
  689.                             // Now interpolate between this value and the next
  690.                             if (ulIndex + 1 < m_pElement->m_ulNumValues &&
  691.                                 m_pElement->m_ppValue[ulIndex] &&
  692.                                 m_pElement->m_ppValue[ulIndex + 1])
  693.                             {
  694.                                 // Do the interpolation
  695.                                 double t1 = ulIndex * m_pElement->m_ulSimpleDuration /
  696.                                             (m_pElement->m_ulNumValues - 1);
  697.                                 double t2 = (ulIndex + 1) * m_pElement->m_ulSimpleDuration /
  698.                                             (m_pElement->m_ulNumValues - 1);
  699.                                 double t  = ulTime;
  700.                                 cRet.Interp(m_pElement->m_ppValue[ulIndex],     t1,
  701.                                             m_pElement->m_ppValue[ulIndex + 1], t2,
  702.                                             t, pDepend);
  703.                             }
  704.                             else
  705.                             {
  706.                                 // The only way this can happen is if
  707.                                 // ulTime == m_pElement->m_ulSimpleDuration, so if this
  708.                                 // if the case, we need to return the un-interpolated
  709.                                 // value of m_ppValue[m_pElement->m_ulNumValues - 1]
  710.                                 if (m_pElement->m_ppValue[m_pElement->m_ulNumValues - 1])
  711.                                 {
  712.                                     cRet = *m_pElement->m_ppValue[m_pElement->m_ulNumValues - 1];
  713.                                 }
  714.                             }
  715.                         }
  716.                     }
  717.                     else if (m_pElement->m_ucCalcMode == kCalcModePaced)
  718.                     {
  719.                         // If we need to recompute the paced tables,
  720.                         // then do it now
  721.                         if (m_bRecomputePace ||
  722.                             (!m_bRecomputePace && m_bFirstTime))
  723.                         {
  724.                             RecomputePace(pDepend);
  725.                         }
  726.                         // Find out what index we're at
  727.                         double t = (double) ulTime;
  728.                         UINT32 i = 0;
  729.                         for (i = 0; i < m_pElement->m_ulNumValues - 1; i++)
  730.                         {
  731.                             if (t >= m_pdPacedTime[i] && t <= m_pdPacedTime[i + 1])
  732.                             {
  733.                                 break;
  734.                             }
  735.                         }
  736.                         if (i + 1 < m_pElement->m_ulNumValues)
  737.                         {
  738.                             // Do the interpolation
  739.                             cRet.Interp(m_pElement->m_ppValue[i],     m_pdPacedTime[i],
  740.                                         m_pElement->m_ppValue[i + 1], m_pdPacedTime[i + 1],
  741.                                         (double) ulTime, pDepend);
  742.                         }
  743.                     }
  744.                 }
  745.                 // Now we can clear the first time flag
  746.                 m_bFirstTime = FALSE;
  747.             }
  748.         }
  749.     }
  750.     return cRet;
  751. }
  752. CAttr CAnimationSandwichLayer::CumulativeAnimationFunction(UINT32 ulTime,
  753.                                                            CAttr* pUnder,
  754.                                                            CAttr* pDepend)
  755. {
  756.     CAttr cRet;
  757.     if (pUnder)
  758.     {
  759.         // Initialize to the underlying value
  760.         cRet = *pUnder;
  761.         // Are we cumulative or not?
  762.         if (m_pElement->m_ucAccumulate == kAccumulateSum)
  763.         {
  764.             // We are a cumulative animation
  765.             //
  766.             // Modulo the time by the simple duration
  767.             UINT32 ulModTime = 0;
  768.             if (m_pElement->m_ulSimpleDuration)
  769.             {
  770.                 ulModTime = ulTime % m_pElement->m_ulSimpleDuration;
  771.             }
  772.             // Evaluate the simple animation function at this time
  773.             CAttr cMod = SimpleAnimationFunction(ulModTime, pUnder, pDepend);
  774.             // Find the iteration
  775.             UINT32 ulIter = 0;
  776.             if (m_pElement->m_ulSimpleDuration)
  777.             {
  778.                 ulIter = ulTime / m_pElement->m_ulSimpleDuration;
  779.             }
  780.             if (ulIter)
  781.             {
  782.                 // Evaluate the animation at the simple duration
  783.                 cRet = SimpleAnimationFunction(m_pElement->m_ulSimpleDuration,
  784.                                                pUnder, pDepend);
  785.                 // Multiply by iteration value
  786.                 cRet.Mult((double) ulIter);
  787.                 // Add the simple animation result
  788.                 cRet.Add(&cMod, pDepend);
  789.             }
  790.             else
  791.             {
  792.                 // We're on the first iteration
  793.                 cRet = cMod;
  794.             }
  795.         }
  796.         else
  797.         {
  798.             // We are a non-cumulative animation
  799.             //
  800.             // Modulo the time by the simple duration
  801.             UINT32 ulModTime = 0;
  802.             if (m_pElement->m_ulSimpleDuration)
  803.             {
  804.                 ulModTime = ulTime % m_pElement->m_ulSimpleDuration;
  805.             }
  806.             // Evaluate the simple animation function at this time
  807.             cRet = SimpleAnimationFunction(ulModTime, pUnder, pDepend);
  808.         }
  809.     }
  810.     return cRet;
  811. }
  812. void CAnimationSandwichLayer::RecomputePace(CAttr* pDepend)
  813. {
  814.     if (!m_pdPacedDist)
  815.     {
  816.         m_pdPacedDist = new double [m_pElement->m_ulNumValues];
  817.         if (m_pdPacedDist)
  818.         {
  819.             memset((void*) m_pdPacedDist, 0, sizeof(double) *
  820.                    m_pElement->m_ulNumValues);
  821.         }
  822.     }
  823.     if (!m_pdPacedTime)
  824.     {
  825.         m_pdPacedTime = new double [m_pElement->m_ulNumValues];
  826.         if (m_pdPacedTime)
  827.         {
  828.             memset((void*) m_pdPacedTime, 0, sizeof(double) *
  829.                    m_pElement->m_ulNumValues);
  830.         }
  831.     }
  832.     if (m_pdPacedDist && m_pdPacedTime)
  833.     {
  834.         UINT32 i = 0;
  835.         // Compute D()
  836.         m_pdPacedDist[0] = 0.0;
  837.         for (i = 1; i < m_pElement->m_ulNumValues; i++)
  838.         {
  839.             m_pdPacedDist[i] = m_pdPacedDist[i - 1] +
  840.                                CAttr::Dist(m_pElement->m_ppValue[i - 1],
  841.                                            m_pElement->m_ppValue[i],
  842.                                            pDepend);
  843.         }
  844.         // Compute T()
  845.         double dTotal = m_pdPacedDist[m_pElement->m_ulNumValues - 1];
  846.         for (i = 0; i < m_pElement->m_ulNumValues; i++)
  847.         {
  848.             m_pdPacedTime[i] = m_pdPacedDist[i] * m_pElement->m_ulSimpleDuration / dTotal;
  849.         }
  850.     }
  851. }
  852. UINT32 CAnimationSandwichLayer::ComputeFilteredSimpleTime(UINT32 ulUnfilteredActiveTime)
  853. {
  854.     UINT32 ulRet = ulUnfilteredActiveTime;
  855.     if (m_pElement &&
  856.         (m_pElement->m_bAutoReverse       ||
  857.          m_pElement->m_dSpeed      != 1.0 ||
  858.          m_pElement->m_dAccelerate != 0.0 ||
  859.          m_pElement->m_dDecelerate != 0.0))
  860.     {
  861.         // Compute the duration of the acceleration phase
  862.         double dacc = ((double) m_pElement->m_ulSimpleDuration) *
  863.                       m_pElement->m_dAccelerate;
  864.         // Compute the duration of the deceleration phase
  865.         double ddec = ((double) m_pElement->m_ulSimpleDuration) *
  866.                       m_pElement->m_dDecelerate;
  867.         // Compute the active filtered time (which takes
  868.         // into account the speed attribute)
  869.         double dActiveFilteredTime = 0.0;
  870.         if (m_pElement->m_dSpeed > 0.0)
  871.         {
  872.             dActiveFilteredTime = ((double) ulUnfilteredActiveTime) *
  873.                                   m_pElement->m_dSpeed;
  874.         }
  875.         else
  876.         {
  877.             dActiveFilteredTime = ((double) m_pElement->m_ulADNoSpeed) -
  878.                                   (((double) ulUnfilteredActiveTime) *
  879.                                    fabs(m_pElement->m_dSpeed));
  880.         }
  881.         // Compute the unfiltered simple time
  882.         double dUnfilteredSimpleTime = dActiveFilteredTime;
  883.         double dDur                  = (double) m_pElement->m_ulSimpleDuration;
  884.         double dDurPrime             = dDur;
  885.         if (m_pElement->m_bAutoReverse)
  886.         {
  887.             dDurPrime *= 2.0;
  888.         }
  889.         // Is there any repeating behavior?
  890.         if (m_pElement->m_dRepeatCount == 1.0 &&
  891.             (m_pElement->m_ulRepeatDur  == ((UINT32) -1) ||
  892.              m_pElement->m_bRepeatDurIsIndefinite))
  893.         {
  894.             // No repeating behavior here, so unfiltered simple
  895.             // time is equal to active filtered time
  896.             dUnfilteredSimpleTime = dActiveFilteredTime;
  897.         }
  898.         else
  899.         {
  900.             // This animation repeats, so calcuate the
  901.             // remainder
  902.             if (dDurPrime != 0.0)
  903.             {
  904.                 dUnfilteredSimpleTime =
  905.                     dActiveFilteredTime -
  906.                     dDurPrime * floor(dActiveFilteredTime / dDurPrime);
  907.             }
  908.         }
  909.         // Account for autoReverse behavior
  910.         double dUnfilteredSimpleTimePrime = dUnfilteredSimpleTime;
  911.         if (m_pElement->m_bAutoReverse &&
  912.             dUnfilteredSimpleTime >= dDur)
  913.         {
  914.             dUnfilteredSimpleTimePrime = (2.0 * dDur) - dUnfilteredSimpleTime;
  915.         }
  916.         // Compute the decel begin time
  917.         double dDecelBegin = dDur - ddec;
  918.         // Compute the filtered simple time
  919.         double dFilteredSimpleTime = (double) dUnfilteredSimpleTimePrime;
  920.         double dRDenom             = 1.0 -
  921.                                      (m_pElement->m_dAccelerate / 2.0) - 
  922.                                      (m_pElement->m_dDecelerate / 2.0);
  923.         double dR = 1.0;
  924.         if (dRDenom != 0.0)
  925.         {
  926.             dR = 1.0 / dRDenom;
  927.         }
  928.         if (dUnfilteredSimpleTimePrime >= 0.0 &&
  929.             dUnfilteredSimpleTimePrime < dacc)
  930.         {
  931.             dFilteredSimpleTime = dUnfilteredSimpleTimePrime *
  932.                                   ComputeRunRate(dUnfilteredSimpleTimePrime,
  933.                                                  m_pElement->m_dAccelerate,
  934.                                                  m_pElement->m_dDecelerate,
  935.                                                  dDur) / 2.0;
  936.         }
  937.         else if (dUnfilteredSimpleTimePrime >= dacc &&
  938.                  dUnfilteredSimpleTimePrime <= dDecelBegin)
  939.         {
  940.             dFilteredSimpleTime = dR * (dUnfilteredSimpleTimePrime - (dacc / 2.0));
  941.         }
  942.         else if (dUnfilteredSimpleTimePrime > dDecelBegin &&
  943.                  dUnfilteredSimpleTimePrime <= dDur)
  944.         {
  945.             double tdec = dUnfilteredSimpleTime - dDecelBegin;
  946.             double pd   = 1.0;
  947.             if (ddec != 0.0)
  948.             {
  949.                 pd = tdec / ddec;
  950.             }
  951.             dFilteredSimpleTime = dR * (dDur - (dacc / 2.0) - ddec +
  952.                                         (tdec * (2.0 - pd) / 2.0));
  953.             // Make sure we don't ever round up to dDur if
  954.             // our input is less than dDur
  955.             if (dUnfilteredSimpleTimePrime < dDur &&
  956.                 dFilteredSimpleTime >= dDur - 0.5)
  957.             {
  958.                 dFilteredSimpleTime = dDur - 0.50000000001;
  959.             }
  960.         }
  961.         // Now round to nearest integer
  962.         ulRet = (UINT32) floor(dFilteredSimpleTime + 0.5);
  963.     }
  964.     return ulRet;
  965. }
  966. double CAnimationSandwichLayer::ComputeRunRate(double dT, double dAccel,
  967.                                                double dDecel, double dDur)
  968. {
  969.     double dRet = 1.0;
  970.     double dacc    = dDur * dAccel;
  971.     double ddec    = dDur * dDecel;
  972.     double dRDenom = 1.0 - (dAccel / 2.0) - (dDecel / 2.0);
  973.     if (dRDenom != 0.0)
  974.     {
  975.         double dR = 1.0 / dRDenom;
  976.         // Compute the decel begin time
  977.         double dDecBegin = dDur - ddec;
  978.         // Now compute the run rate
  979.         if (dT >= 0.0 && dT < dacc)
  980.         {
  981.             if (dacc != 0.0)
  982.             {
  983.                 dRet = dR * dT / dacc;
  984.             }
  985.         }
  986.         else if (dT >= dacc && dT <= dDecBegin)
  987.         {
  988.             dRet = dR;
  989.         }
  990.         else if (dT > dDecBegin && dT <= dDur)
  991.         {
  992.             if (ddec != 0.0)
  993.             {
  994.                 dRet = dR * (dDur - dT) / ddec;
  995.             }
  996.         }
  997.     }
  998.     return dRet;
  999. }
  1000. #if defined(XXXMEH_SPLINE_ANIMATION)
  1001. double CAnimationSandwichLayer::ComputeSpline(double t,  double t1, double t2,
  1002.                                               double v1, double v2, double x1,
  1003.                                               double y1, double x2, double y2)
  1004. {
  1005.     double dRet = 0.0;
  1006.     if (x1 >= 0.0 && x1 <= 1.0 &&
  1007.         y1 >= 0.0 && y1 <= 1.0 &&
  1008.         x2 >= 0.0 && x2 <= 1.0 &&
  1009.         y2 >= 0.0 && y2 <= 1.0)
  1010.     {
  1011.         if (t2 >= t1)
  1012.         {
  1013.             if (t >= t1)
  1014.             {
  1015.                 if (t <= t2)
  1016.                 {
  1017.                     if (t2 > t1)
  1018.                     {
  1019.                         // We compute the spline interpolation
  1020.                         // in the following steps:
  1021.                         // a) Scale the time down to unit time
  1022.                         // b) Get the output bezier time (still in unit time)
  1023.                         // c) Use this output time as the 
  1024.                         //    input time for linear interpolation.
  1025.                         //
  1026.                         // Scale the time to unit time
  1027.                         double dInUnitT = (t - t1) / (t2 - t1);
  1028.                         // Get the output bezier time
  1029.                         double dOutUnitT = ComputeBezierOutputTime(dUnitT, x1, y1, x2, y2);
  1030.                         // Do a sanity check on the output time
  1031.                         if (dOutUnitT < 0.0)
  1032.                         {
  1033.                             dOutUnitT = 0.0;
  1034.                             HX_ASSERT(FALSE && "Bad value returned from ComputeBezierOutputTime()");
  1035.                         }
  1036.                         else if (dOutUnitT > 1.0)
  1037.                         {
  1038.                             dOutUnitT = 1.0;
  1039.                             HX_ASSERT(FALSE && "Bad value returned from ComputeBezierOutputTime()");
  1040.                         }
  1041.                         // Use this time to linearly interpolate
  1042.                         dRet = v1 + (v2 - v1) * dOutUnitT;
  1043.                     }
  1044.                     else
  1045.                     {
  1046.                         // t1 is equal to t2. So this is a discontinuous
  1047.                         // interval, so by endpoint-exclusive logic [a,b),
  1048.                         // we choose v2 for the output value. This is not
  1049.                         // an input error, so we don't assert.
  1050.                         dRet = v2;
  1051.                     }
  1052.                 }
  1053.                 else
  1054.                 {
  1055.                     dRet = v2;
  1056.                     HX_ASSERT(FALSE && "ComputeSpline(): t is greater than t2 - v2 assigned");
  1057.                 }
  1058.             }
  1059.             else
  1060.             {
  1061.                 dRet = v1;
  1062.                 HX_ASSERT(FALSE && "ComputeSpline(): t is less than t1 - v1 assigned");
  1063.             }
  1064.         }
  1065.         else
  1066.         {
  1067.             HX_ASSERT(FALSE && "ComputeSpline(): t2 cannot be less than t1");
  1068.         }
  1069.     }
  1070.     else
  1071.     {
  1072.         HX_ASSERT(FALSE && "Illegal bezier control parameters in ComputeSpline()");
  1073.     }
  1074.     return dRet;
  1075. }
  1076. double CAnimationSandwichLayer::ComputeBezierOutputTime(double t,
  1077.                                                         double x1, double y1,
  1078.                                                         double x2, double y2)
  1079. {
  1080.     double dRet = 0.0;
  1081.     if (t  >= 0.0 && t  <= 1.0 &&
  1082.         x1 >= 0.0 && x1 <= 1.0 &&
  1083.         y1 >= 0.0 && y1 <= 1.0 &&
  1084.         x2 >= 0.0 && x2 <= 1.0 &&
  1085.         y2 >= 0.0 && y2 <= 1.0)
  1086.     {
  1087.         // We get the output bezier-curve-warped time
  1088.         // by doing the following:
  1089.         //
  1090.         // a) Find q where x(q) = t
  1091.         // b) Compute y(q)
  1092.         //
  1093.         // Find the q where x(q) = t
  1094.         double dQ = SolveForBezierT(t, x1, x2, BEZIER_TOLERANCE);
  1095.         // Do a sanity check on this value
  1096.         if (dQ < 0.0)
  1097.         {
  1098.             dQ = 0.0;
  1099.             HX_ASSERT(FALSE && "Bad value returned from SolveForBezierT()");
  1100.         }
  1101.         else if (dQ > 1.0)
  1102.         {
  1103.             dQ = 1.0;
  1104.             HX_ASSERT(FALSE && "Bad value returned from SolveForBezierT()");
  1105.         }
  1106.         // Compute y(q)
  1107.         dRet = ComputeBezier(dQ, y1, y2);
  1108.     }
  1109.     else
  1110.     {
  1111.         HX_ASSERT(FALSE && "Illegal input parameters in ComputeBezierOutputTime()");
  1112.     }
  1113.     return dRet;
  1114. }
  1115. double CAnimationSandwichLayer::SolveForBezierT(double x,  double x1,
  1116.                                                 double x2, double tol)
  1117. {
  1118.     double dRet = 0.0;
  1119.     if (x   >= 0.0 && x   <= 1.0 &&
  1120.         x1  >= 0.0 && x1  <= 1.0 &&
  1121.         x2  >= 0.0 && x2  <= 1.0 &&
  1122.         tol >  0.0 && tol <= 1.0)
  1123.     {
  1124.         double tL = 0.0;
  1125.         double xL = 0.0;
  1126.         double tR = 1.0;
  1127.         double xR = 1.0;
  1128.         double tM = 0.5;
  1129.         double xM = ComputeBezier(tM, x1, x2);
  1130.         UINT32 i  = 0;
  1131.         while (fabs(xM - x) > tol &&
  1132.                i < BEZIER_MAX_ITERATIONS)
  1133.         {
  1134.             // Is our computed mid-point smaller or
  1135.             // larger than our desired value?
  1136.             if (xM > x)
  1137.             {
  1138.                 // Take the left-hand interval
  1139.                 tR = tM;
  1140.             }
  1141.             else
  1142.             {
  1143.                 // Take the right-hand interval
  1144.                 tL = tM;
  1145.             }
  1146.             // Compute new mid-point
  1147.             tM = (tL + tR) / 2.0;
  1148.             // Compute new value
  1149.             xM = ComputeBezier(tM, x1, x2);
  1150.             // Increment the iteration count
  1151.             ++i;
  1152.         }
  1153.         // Set the return value
  1154.         dRet = tM;
  1155.         // Check if we blew our max iteration count
  1156.         if (i >= BEZIER_MAX_ITERATIONS)
  1157.         {
  1158.             HX_ASSERT(FALSE && "SolveForBezierT(): Could not get within tolerance in max iterations");
  1159.         }
  1160.     }
  1161.     else
  1162.     {
  1163.         HX_ASSERT(FALSE && "Illegal input parameters in SolveForBezierT()");
  1164.     }
  1165.     return dRet;
  1166. }
  1167. double CAnimationSandwichLayer::ComputeBezier(double t, double a1, double a2)
  1168. {
  1169.     double dRet = 0.0;
  1170.     if (t  >= 0.0 && t  <= 1.0 &&
  1171.         a1 >= 0.0 && a1 <= 1.0 &&
  1172.         a2 >= 0.0 && a2 <= 1.0)
  1173.     {
  1174.         double t2  = t * t;
  1175.         double t3  = t2 * t;
  1176.         double ti  = 1.0 - t;
  1177.         double ti2 = ti * ti;
  1178.         dRet       = 3.0 * t  * ti2 * a1 +
  1179.                      3.0 * t2 * ti  * a2 +
  1180.                      t3;
  1181.     }
  1182.     else
  1183.     {
  1184.         HX_ASSERT(FALSE && "Illegal input parameters in ComputeBezier()");
  1185.     }
  1186.     return dRet;
  1187. }
  1188. #endif // #if defined(XXXMEH_SPLINE_ANIMATION)
  1189. CAnimationSandwich::CAnimationSandwich(const char* pszTargetElementID,
  1190.                                        SMILNodeTag eTargetElementTag,
  1191.                                        UINT32      ulAttrName)
  1192. {
  1193.     MLOG_LEAKCHECK("CON CAnimationSandwich this=0x%08xn", this);
  1194.     m_pTargetElementID  = new CHXString(pszTargetElementID);
  1195.     m_eTargetElementTag = eTargetElementTag;
  1196.     m_ulAttrName        = ulAttrName;
  1197.     m_pLayerList        = NULL;
  1198. }
  1199. CAnimationSandwich::~CAnimationSandwich()
  1200. {
  1201.     MLOG_LEAKCHECK("DES CAnimationSandwich this=0x%08xn", this);
  1202.     ClearAllLayers();
  1203.     HX_DELETE(m_pTargetElementID);
  1204.     HX_DELETE(m_pLayerList);
  1205. }
  1206. void CAnimationSandwich::ClearAllLayers()
  1207. {
  1208.     if (m_pLayerList)
  1209.     {
  1210.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1211.         while (pos)
  1212.         {
  1213.             CAnimationSandwichLayer* pLayer = (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1214.             HX_DELETE(pLayer);
  1215.         }
  1216.         m_pLayerList->RemoveAll();
  1217.     }
  1218. }
  1219. const char* CAnimationSandwich::GetTargetElementID() const
  1220. {
  1221.     const char* pRet = NULL;
  1222.     if (m_pTargetElementID)
  1223.     {
  1224.         pRet = (const char*) *m_pTargetElementID;
  1225.     }
  1226.     return pRet;
  1227. }
  1228. HX_RESULT CAnimationSandwich::AddLayer(CAnimationSandwichLayer* pLayer)
  1229. {
  1230.     HX_RESULT retVal = HXR_OK;
  1231.     if (pLayer)
  1232.     {
  1233.         if (!m_pLayerList)
  1234.         {
  1235.             m_pLayerList = new CHXSimpleList();
  1236.         }
  1237.         if (m_pLayerList)
  1238.         {
  1239.             BOOL         bAdded = FALSE;
  1240.             LISTPOSITION pos    = m_pLayerList->GetHeadPosition();
  1241.             while (pos)
  1242.             {
  1243.                 CAnimationSandwichLayer* pListLayer = (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
  1244.                 if (pListLayer->HigherPriority(pLayer))
  1245.                 {
  1246.                     // The current layer in the list is higher priority
  1247.                     // than the layer we want to add, so we must insert
  1248.                     // ourselves BEFORE this layer
  1249.                     m_pLayerList->InsertBefore(pos, (void*) pLayer);
  1250.                     // Set the flag
  1251.                     bAdded = TRUE;
  1252.                     // Now jump out of the loop
  1253.                     break;
  1254.                 }
  1255.                 m_pLayerList->GetNext(pos);
  1256.             }
  1257.             // If we didn't add ourselves, then that
  1258.             // means we are the highest priority, so 
  1259.             // add ourselves to the tail of the list
  1260.             if (!bAdded)
  1261.             {
  1262.                 m_pLayerList->AddTail((void*) pLayer);
  1263.             }
  1264.         }
  1265.         else
  1266.         {
  1267.             retVal = HXR_OUTOFMEMORY;
  1268.         }
  1269.     }
  1270.     return retVal;
  1271. }
  1272. void CAnimationSandwich::RemoveLayer(const char* pszAnimID)
  1273. {
  1274.     if (pszAnimID && m_pLayerList)
  1275.     {
  1276.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1277.         while (pos)
  1278.         {
  1279.             CAnimationSandwichLayer* pLayer =
  1280.                 (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
  1281.             if (pLayer &&
  1282.                 pLayer->GetAnimationElementID() &&
  1283.                 !strcmp(pszAnimID, pLayer->GetAnimationElementID()))
  1284.             {
  1285.                 // We need to remove this layer
  1286.                 //
  1287.                 // First remove it from the list
  1288.                 pos = m_pLayerList->RemoveAt(pos);
  1289.                 // Next delete the object itself
  1290.                 HX_DELETE(pLayer);
  1291.             }
  1292.             else
  1293.             {
  1294.                 m_pLayerList->GetNext(pos);
  1295.             }
  1296.         }
  1297.     }
  1298. }
  1299. void CAnimationSandwich::FreezeLayers(const char* pszAnimID, UINT32 ulCurTime)
  1300. {
  1301.     if (pszAnimID && m_pLayerList)
  1302.     {
  1303.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1304.         while (pos)
  1305.         {
  1306.             CAnimationSandwichLayer* pLayer =
  1307.                 (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1308.             if (pLayer &&
  1309.                 pLayer->GetAnimationElementID() &&
  1310.                 !strcmp(pszAnimID, pLayer->GetAnimationElementID()) &&
  1311.                 pLayer->IsActive(ulCurTime))
  1312.             {
  1313.                 // We need to freeze this layer. We do this
  1314.                 // by adjusting the layer's m_ulActiveDuration
  1315.                 // such that pLayer->m_ulDelay + pLayer->m_ulActiveDuration
  1316.                 // is equal to the current time.
  1317.                 pLayer->AdjustActiveDuration(ulCurTime);
  1318.             }
  1319.         }
  1320.     }
  1321. }
  1322. CAttr CAnimationSandwich::GetValue(UINT32 ulTime, CAttr* pUnder, CAttr* pDepend)
  1323. {
  1324.     CAttr cRet;
  1325.     if (pUnder)
  1326.     {
  1327.         // Initialize the running value
  1328.         CAttr cUnder(*pUnder);
  1329.         // Now run through the layers
  1330.         if (m_pLayerList)
  1331.         {
  1332.             LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1333.             while (pos)
  1334.             {
  1335.                 CAnimationSandwichLayer* pLayer =
  1336.                     (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1337.                 if (pLayer &&
  1338.                     (pLayer->IsActive(ulTime) ||
  1339.                      pLayer->IsFrozen(ulTime)))
  1340.                 {
  1341.                     // Evaluate this layer
  1342.                     CAttr cRes = pLayer->AnimationEffectFunction(ulTime, &cUnder, pDepend);
  1343.                     // Now we either have to replace OR add
  1344.                     if (pLayer->IsAdditive() &&
  1345.                         !pLayer->IsToAnimation())
  1346.                     {
  1347.                         cUnder.Add(&cRes, pDepend);
  1348.                     }
  1349.                     else
  1350.                     {
  1351.                         cUnder = cRes;
  1352.                     }
  1353.                 }
  1354.             }
  1355.         }
  1356.         // Now set the return value
  1357.         cRet = cUnder;
  1358.     }
  1359.     return cRet;
  1360. }
  1361. UINT32 CAnimationSandwich::GetNumLayers() const
  1362. {
  1363.     UINT32 ulRet = 0;
  1364.     if (m_pLayerList)
  1365.     {
  1366.         ulRet = m_pLayerList->GetCount();
  1367.     }
  1368.     return ulRet;
  1369. }
  1370. void CAnimationSandwich::AdjustLayers(UINT32 ulTime)
  1371. {
  1372.     if (m_pLayerList)
  1373.     {
  1374.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1375.         while (pos)
  1376.         {
  1377.             CAnimationSandwichLayer* pLayer = (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
  1378.             if (!pLayer->IsActive(ulTime) &&
  1379.                 !pLayer->IsFrozen(ulTime))
  1380.             {
  1381.                 // We need to remove this layer
  1382.                 //
  1383.                 // First remove it from the list
  1384.                 pos = m_pLayerList->RemoveAt(pos);
  1385.                 // Next delete the object itself
  1386.                 HX_DELETE(pLayer);
  1387.             }
  1388.             else
  1389.             {
  1390.                 m_pLayerList->GetNext(pos);
  1391.             }
  1392.         }
  1393.     }
  1394. }
  1395. BOOL CAnimationSandwich::MatchingSandwich(CSmilAnimateElement* pAnim)
  1396. {
  1397.     BOOL bRet = FALSE;
  1398.     if (pAnim &&
  1399.         pAnim->m_pTargetElementID &&
  1400.         m_pTargetElementID &&
  1401.         *pAnim->m_pTargetElementID == *m_pTargetElementID)
  1402.     {
  1403.         // We know that this animate element has the
  1404.         // same target element ID as we do. Now we 
  1405.         // need to check if it has the same attributeName.
  1406.         // If the animate element is an <animateMotion>, then
  1407.         // our sandwich could be either left or top. If the
  1408.         // animate element is not <animateMotion>, then the
  1409.         // attributeName has to match exactly.
  1410.         if (pAnim->m_pNode &&
  1411.             pAnim->m_pNode->m_tag == SMILAnimateMotion)
  1412.         {
  1413.             if (m_ulAttrName == kAttrNameLeft ||
  1414.                 m_ulAttrName == kAttrNameTop)
  1415.             {
  1416.                 bRet = TRUE;
  1417.             }
  1418.         }
  1419.         else
  1420.         {
  1421.             UINT32 ulAttrName = pAnim->m_ucAttributeName;
  1422.             if (ulAttrName == m_ulAttrName)
  1423.             {
  1424.                 bRet = TRUE;
  1425.             }
  1426.         }
  1427.     }
  1428.     return bRet;
  1429. }
  1430. BOOL CAnimationSandwich::AtLeastOneActiveLayer(UINT32 ulTime)
  1431. {
  1432.     BOOL bRet = FALSE;
  1433.     if (m_pLayerList &&
  1434.         m_pLayerList->GetCount() > 0)
  1435.     {
  1436.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1437.         while (pos)
  1438.         {
  1439.             CAnimationSandwichLayer* pLayer =
  1440.                 (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1441.             if (pLayer && pLayer->IsActive(ulTime))
  1442.             {
  1443.                 bRet = TRUE;
  1444.                 break;
  1445.             }
  1446.         }
  1447.     }
  1448.     return bRet;
  1449. }
  1450. CSmilAnimateInfo::CSmilAnimateInfo()
  1451. {
  1452.     m_pSandwich = NULL;
  1453.     m_pUnder    = NULL;
  1454.     m_pDepend   = NULL;
  1455. }
  1456. CSmilAnimateInfo::~CSmilAnimateInfo()
  1457. {
  1458.     HX_DELETE(m_pSandwich);
  1459.     HX_DELETE(m_pUnder);
  1460.     HX_DELETE(m_pDepend);
  1461. }