Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1235 lines
32 KiB

  1. #include "stdafx.h"
  2. #include "Ctrl.h"
  3. #include "Sequence.h"
  4. #if ENABLE_MSGTABLE_API
  5. /***************************************************************************\
  6. *****************************************************************************
  7. *
  8. * Global Functions
  9. *
  10. *****************************************************************************
  11. \***************************************************************************/
  12. //------------------------------------------------------------------------------
  13. inline BOOL
  14. IsSameTime(float flA, float flB)
  15. {
  16. float flDelta = flA - flB;
  17. return ((flDelta < 0.005f) && (flDelta > -0.005f));
  18. }
  19. /***************************************************************************\
  20. *****************************************************************************
  21. *
  22. * class DuSequence
  23. *
  24. *****************************************************************************
  25. \***************************************************************************/
  26. /***************************************************************************\
  27. *
  28. * DuSequence::ApiOnEvent
  29. *
  30. * ApiOnEvent() processes events.
  31. *
  32. \***************************************************************************/
  33. HRESULT
  34. DuSequence::ApiOnEvent(EventMsg * pmsg)
  35. {
  36. if (pmsg->nMsg == GM_DESTROY) {
  37. GMSG_DESTROY * pmsgD = static_cast<GMSG_DESTROY *>(pmsg);
  38. switch (GET_EVENT_DEST(pmsgD))
  39. {
  40. case GMF_DIRECT:
  41. //
  42. // We are being destroyed.
  43. //
  44. Stop();
  45. return DU_S_COMPLETE;
  46. case GMF_EVENT:
  47. //
  48. // Our Subject is being destroyed
  49. //
  50. Stop();
  51. return DU_S_PARTIAL;
  52. }
  53. }
  54. return SListener::ApiOnEvent(pmsg);
  55. }
  56. /***************************************************************************\
  57. *
  58. * DuSequence::ApiGetLength
  59. *
  60. * ApiGetLength() returns the length of a sequence, not including the initial
  61. * delay.
  62. *
  63. \***************************************************************************/
  64. HRESULT
  65. DuSequence::ApiGetLength(Sequence::GetLengthMsg * pmsg)
  66. {
  67. int cItems = m_arSeqData.GetSize();
  68. if (cItems <= 0) {
  69. pmsg->flLength = 0.0f;
  70. } else {
  71. pmsg->flLength = m_arSeqData[cItems - 1].flTime;
  72. }
  73. return S_OK;
  74. }
  75. /***************************************************************************\
  76. *
  77. * DuSequence::ApiGetDelay
  78. *
  79. * ApiGetDelay() returns the delay to wait before starting the sequence.
  80. *
  81. \***************************************************************************/
  82. HRESULT
  83. DuSequence::ApiGetDelay(Sequence::GetDelayMsg * pmsg)
  84. {
  85. pmsg->flDelay = m_flDelay;
  86. return S_OK;
  87. }
  88. /***************************************************************************\
  89. *
  90. * DuSequence::ApiSetDelay
  91. *
  92. * ApiSetDelay() changes the delay to wait before starting the sequence.
  93. *
  94. \***************************************************************************/
  95. HRESULT
  96. DuSequence::ApiSetDelay(Sequence::SetDelayMsg * pmsg)
  97. {
  98. if (pmsg->flDelay < 0.0f) {
  99. PromptInvalid("Can not set a delay time in the past");
  100. return E_INVALIDARG;
  101. }
  102. if (IsPlaying()) {
  103. PromptInvalid("Sequence is busy");
  104. return DU_E_BUSY;
  105. }
  106. m_flDelay = pmsg->flDelay;
  107. return S_OK;
  108. }
  109. /***************************************************************************\
  110. *
  111. * DuSequence::ApiGetFlow
  112. *
  113. * ApiGetFlow() returns the Flow being used through-out the sequence to
  114. * modify a given Subject.
  115. *
  116. \***************************************************************************/
  117. HRESULT
  118. DuSequence::ApiGetFlow(Sequence::GetFlowMsg * pmsg)
  119. {
  120. SafeAddRef(m_pflow);
  121. pmsg->pflow = m_pflow;
  122. return S_OK;
  123. }
  124. /***************************************************************************\
  125. *
  126. * DuSequence::ApiSetFlow
  127. *
  128. * ApiSetFlow() changes the Flow being used through-out the sequence to
  129. * modify a given Subject.
  130. *
  131. \***************************************************************************/
  132. HRESULT
  133. DuSequence::ApiSetFlow(Sequence::SetFlowMsg * pmsg)
  134. {
  135. if (IsPlaying()) {
  136. PromptInvalid("Sequence is busy");
  137. return DU_E_BUSY;
  138. }
  139. SafeRelease(m_pflow);
  140. SafeAddRef(pmsg->pflow);
  141. m_pflow = pmsg->pflow;
  142. return S_OK;
  143. }
  144. /***************************************************************************\
  145. *
  146. * DuSequence::ApiGetFramePause
  147. *
  148. * ApiGetFramePause() returns the default "dwPause" value used for
  149. * Animations during playback.
  150. *
  151. \***************************************************************************/
  152. HRESULT
  153. DuSequence::ApiGetFramePause(Sequence::GetFramePauseMsg * pmsg)
  154. {
  155. pmsg->dwPause = m_dwFramePause;
  156. return S_OK;
  157. }
  158. /***************************************************************************\
  159. *
  160. * DuSequence::ApiSetFramePause
  161. *
  162. * ApiSetFramePause() changes the default "dwPause" value used for
  163. * Animations during playback.
  164. *
  165. \***************************************************************************/
  166. HRESULT
  167. DuSequence::ApiSetFramePause(Sequence::SetFramePauseMsg * pmsg)
  168. {
  169. if (IsPlaying()) {
  170. PromptInvalid("Sequence is busy");
  171. return DU_E_BUSY;
  172. }
  173. m_dwFramePause = pmsg->dwPause;
  174. return S_OK;
  175. }
  176. /***************************************************************************\
  177. *
  178. * DuSequence::ApiGetKeyFrameCount
  179. *
  180. * ApiGetKeyFrameCount() return the number of KeyFrames used in the sequence.
  181. *
  182. \***************************************************************************/
  183. HRESULT
  184. DuSequence::ApiGetKeyFrameCount(Sequence::GetKeyFrameCountMsg * pmsg)
  185. {
  186. pmsg->cFrames = m_arSeqData.GetSize();
  187. return S_OK;
  188. }
  189. /***************************************************************************\
  190. *
  191. * DuSequence::ApiAddKeyFrame
  192. *
  193. * ApiAddKeyFrame() adds a new KeyFrame at the specified time. If a KeyFrame
  194. * already exists at the given time, that KeyFrame will be returned.
  195. *
  196. \***************************************************************************/
  197. HRESULT
  198. DuSequence::ApiAddKeyFrame(Sequence::AddKeyFrameMsg * pmsg)
  199. {
  200. if (pmsg->flTime < 0.0f) {
  201. PromptInvalid("Can not set a delay time in the past");
  202. return E_INVALIDARG;
  203. }
  204. if (IsPlaying()) {
  205. PromptInvalid("Sequence is busy");
  206. return DU_E_BUSY;
  207. }
  208. //
  209. // Search the sequence to determine what slot to insert the new data in. We
  210. // want to keep all time in order.
  211. //
  212. int cItems = m_arSeqData.GetSize();
  213. int idxAdd = cItems;
  214. for (int idx = 0; idx < cItems; idx++) {
  215. if (IsSameTime(m_arSeqData[idx].flTime, pmsg->flTime)) {
  216. pmsg->idxKeyFrame = idx;
  217. return S_OK;
  218. }
  219. if (m_arSeqData[idx].flTime > pmsg->flTime) {
  220. idxAdd = idx;
  221. }
  222. }
  223. //
  224. // Add a new KeyFrame at this time
  225. //
  226. SeqData data;
  227. data.flTime = pmsg->flTime;
  228. data.pkf = NULL;
  229. data.pipol = NULL;
  230. if (!m_arSeqData.InsertAt(idxAdd, data)) {
  231. return E_OUTOFMEMORY;
  232. }
  233. pmsg->idxKeyFrame = idxAdd;
  234. return S_OK;
  235. }
  236. /***************************************************************************\
  237. *
  238. * DuSequence::ApiRemoveKeyFrame
  239. *
  240. * ApiRemoveKeyFrame() removes the specified KeyFrame.
  241. *
  242. \***************************************************************************/
  243. HRESULT
  244. DuSequence::ApiRemoveKeyFrame(Sequence::RemoveKeyFrameMsg * pmsg)
  245. {
  246. if ((pmsg->idxKeyFrame < 0) || (pmsg->idxKeyFrame >= m_arSeqData.GetSize())) {
  247. PromptInvalid("Invalid KeyFrame");
  248. return E_INVALIDARG;
  249. }
  250. if (IsPlaying()) {
  251. PromptInvalid("Sequence is busy");
  252. return DU_E_BUSY;
  253. }
  254. SeqData & data = m_arSeqData[pmsg->idxKeyFrame];
  255. ClientFree(data.pkf);
  256. SafeRelease(data.pipol);
  257. m_arSeqData.RemoveAt(pmsg->idxKeyFrame);
  258. return S_OK;
  259. }
  260. /***************************************************************************\
  261. *
  262. * DuSequence::ApiRemoveAllKeyFrames
  263. *
  264. * ApiRemoveAllKeyFrames() removes all KeyFrames.
  265. *
  266. \***************************************************************************/
  267. HRESULT
  268. DuSequence::ApiRemoveAllKeyFrames(Sequence::RemoveAllKeyFramesMsg * pmsg)
  269. {
  270. UNREFERENCED_PARAMETER(pmsg);
  271. if (IsPlaying()) {
  272. PromptInvalid("Sequence is busy");
  273. return DU_E_BUSY;
  274. }
  275. RemoveAllKeyFrames();
  276. return S_OK;
  277. }
  278. /***************************************************************************\
  279. *
  280. * DuSequence::ApiFindKeyFrame
  281. *
  282. * ApiFindKeyFrame() finds the KeyFrame at the given time.
  283. *
  284. \***************************************************************************/
  285. HRESULT
  286. DuSequence::ApiFindKeyFrame(Sequence::FindKeyFrameMsg * pmsg)
  287. {
  288. FindAtTime(pmsg->flTime, &pmsg->idxKeyFrame);
  289. return S_OK;
  290. }
  291. /***************************************************************************\
  292. *
  293. * DuSequence::ApiGetTime
  294. *
  295. * ApiGetTime() returns the time at a given KeyFrame.
  296. *
  297. \***************************************************************************/
  298. HRESULT
  299. DuSequence::ApiGetTime(Sequence::GetTimeMsg * pmsg)
  300. {
  301. if ((pmsg->idxKeyFrame < 0) || (pmsg->idxKeyFrame >= m_arSeqData.GetSize())) {
  302. PromptInvalid("Invalid KeyFrame");
  303. return E_INVALIDARG;
  304. }
  305. pmsg->flTime = m_arSeqData[pmsg->idxKeyFrame].flTime;
  306. return S_OK;
  307. }
  308. /***************************************************************************\
  309. *
  310. * DuSequence::ApiSetTime
  311. *
  312. * ApiSetTime() changes the time of a given KeyFrame. This function will
  313. * reorder keyframes to maintain proper time order.
  314. *
  315. \***************************************************************************/
  316. HRESULT
  317. DuSequence::ApiSetTime(Sequence::SetTimeMsg * pmsg)
  318. {
  319. if ((pmsg->idxKeyFrame < 0) || (pmsg->idxKeyFrame >= m_arSeqData.GetSize())) {
  320. PromptInvalid("Invalid KeyFrame");
  321. return E_INVALIDARG;
  322. }
  323. if (pmsg->flTime < 0.0f) {
  324. PromptInvalid("Can not set a delay time in the past");
  325. return E_INVALIDARG;
  326. }
  327. if (IsPlaying()) {
  328. PromptInvalid("Sequence is busy");
  329. return DU_E_BUSY;
  330. }
  331. m_arSeqData[pmsg->idxKeyFrame].flTime = pmsg->flTime;
  332. //
  333. // We have changed the time of one of the KeyFrames, so we need to re-sort.
  334. //
  335. SortKeyFrames();
  336. return S_OK;
  337. }
  338. /***************************************************************************\
  339. *
  340. * DuSequence::ApiGetKeyFrame
  341. *
  342. * ApiGetKeyFrame() returns Flow-specific data at a given KeyFrame.
  343. *
  344. \***************************************************************************/
  345. HRESULT
  346. DuSequence::ApiGetKeyFrame(Sequence::GetKeyFrameMsg * pmsg)
  347. {
  348. if ((pmsg->idxKeyFrame < 0) || (pmsg->idxKeyFrame >= m_arSeqData.GetSize())) {
  349. PromptInvalid("Invalid KeyFrame");
  350. return E_INVALIDARG;
  351. }
  352. SeqData & data = m_arSeqData[pmsg->idxKeyFrame];
  353. if (data.pkf == NULL) {
  354. PromptInvalid("KeyFrame has not been set");
  355. return E_INVALIDARG;
  356. }
  357. if (pmsg->pkf->cbSize < data.pkf->cbSize) {
  358. PromptInvalid("cbSize is not large enough to store KeyFrame");
  359. return E_INVALIDARG;
  360. }
  361. CopyMemory(pmsg->pkf, data.pkf, data.pkf->cbSize);
  362. return S_OK;
  363. }
  364. /***************************************************************************\
  365. *
  366. * DuSequence::ApiSetKeyFrame
  367. *
  368. * ApiSetKeyFrame() changes Flow-specific data at a given KeyFrame.
  369. *
  370. \***************************************************************************/
  371. HRESULT
  372. DuSequence::ApiSetKeyFrame(Sequence::SetKeyFrameMsg * pmsg)
  373. {
  374. if ((pmsg->idxKeyFrame < 0) || (pmsg->idxKeyFrame >= m_arSeqData.GetSize())) {
  375. PromptInvalid("Invalid KeyFrame");
  376. return E_INVALIDARG;
  377. }
  378. if (pmsg->pkfSrc->cbSize <= 0) {
  379. PromptInvalid("cbSize must be set");
  380. return E_INVALIDARG;
  381. }
  382. if (IsPlaying()) {
  383. PromptInvalid("Sequence is busy");
  384. return DU_E_BUSY;
  385. }
  386. //
  387. // Copy and store the KeyFrame
  388. //
  389. int cbAlloc = pmsg->pkfSrc->cbSize;
  390. DUser::KeyFrame * pkfCopy = reinterpret_cast<DUser::KeyFrame *> (ClientAlloc(cbAlloc));
  391. if (pkfCopy == NULL) {
  392. return E_OUTOFMEMORY;
  393. }
  394. SeqData & data = m_arSeqData[pmsg->idxKeyFrame];
  395. ClientFree(data.pkf);
  396. CopyMemory(pkfCopy, pmsg->pkfSrc, cbAlloc);
  397. data.pkf = pkfCopy;
  398. return S_OK;
  399. }
  400. /***************************************************************************\
  401. *
  402. * DuSequence::ApiGetInterpolation
  403. *
  404. * ApiGetInterpolation() returns the Interpolation used to move to the next
  405. * keyframe.
  406. *
  407. \***************************************************************************/
  408. HRESULT
  409. DuSequence::ApiGetInterpolation(Sequence::GetInterpolationMsg * pmsg)
  410. {
  411. if ((pmsg->idxKeyFrame < 0) || (pmsg->idxKeyFrame >= m_arSeqData.GetSize())) {
  412. PromptInvalid("Invalid KeyFrame");
  413. return E_INVALIDARG;
  414. }
  415. SeqData & data = m_arSeqData[pmsg->idxKeyFrame];
  416. SafeAddRef(data.pipol);
  417. pmsg->pipol = data.pipol;
  418. return S_OK;
  419. }
  420. /***************************************************************************\
  421. *
  422. * DuSequence::ApiSetInterpolation
  423. *
  424. * ApiSetInterpolation() changes the Interpolation used to move to the next
  425. * keyframe.
  426. *
  427. \***************************************************************************/
  428. HRESULT
  429. DuSequence::ApiSetInterpolation(Sequence::SetInterpolationMsg * pmsg)
  430. {
  431. if ((pmsg->idxKeyFrame < 0) || (pmsg->idxKeyFrame >= m_arSeqData.GetSize())) {
  432. PromptInvalid("Invalid KeyFrame");
  433. return E_INVALIDARG;
  434. }
  435. if (IsPlaying()) {
  436. PromptInvalid("Sequence is busy");
  437. return DU_E_BUSY;
  438. }
  439. //
  440. // Copy and store the KeyFrame
  441. //
  442. SeqData & data = m_arSeqData[pmsg->idxKeyFrame];
  443. SafeRelease(data.pipol);
  444. SafeAddRef(pmsg->pipol);
  445. data.pipol = pmsg->pipol;
  446. return S_OK;
  447. }
  448. /***************************************************************************\
  449. *
  450. * DuSequence::Play
  451. *
  452. * ApiPlay() executes the Animation sequence for the given Visual. A
  453. * Sequence only supports animating a single Visual at a given time.
  454. * Multiple sequences may be created to animate multiple Visuals
  455. * simultaneously.
  456. *
  457. \***************************************************************************/
  458. HRESULT
  459. DuSequence::ApiPlay(Sequence::PlayMsg * pmsg)
  460. {
  461. Assert(DEBUG_IsProperTimeOrder());
  462. //
  463. // Setup for animation:
  464. // - Validate all information is filled in.
  465. // - Ensure no existing Animation.
  466. // - Determine parameters for Animation.
  467. //
  468. HRESULT hr = CheckComplete();
  469. if (FAILED(hr)) {
  470. return hr;
  471. }
  472. Stop();
  473. AssertMsg(m_arAniData.GetSize() == 0, "Must not have pending Animations");
  474. //
  475. // Setup for Animation
  476. // - Attach as a Listener
  477. // - Allocate information necessary to create the Animations.
  478. // - Add a reference to allow the Sequence to fully play.
  479. //
  480. hr = pmsg->pgvSubject->AddHandlerG(GM_DESTROY, GetStub());
  481. if (FAILED(hr)) {
  482. return hr;
  483. }
  484. m_pgvSubject = pmsg->pgvSubject;
  485. int cItems = m_arSeqData.GetSize();
  486. if (cItems == 0) {
  487. return S_OK;
  488. }
  489. if (!m_arAniData.SetSize(cItems - 1)) {
  490. return E_OUTOFMEMORY;
  491. }
  492. AddRef();
  493. //
  494. // Queue all animations
  495. //
  496. for (int idx = 0; idx < cItems - 1; idx++) {
  497. hr = QueueAnimation(idx);
  498. if (FAILED(hr)) {
  499. return hr;
  500. }
  501. }
  502. return S_OK;
  503. }
  504. /***************************************************************************\
  505. *
  506. * DuSequence::ApiStop
  507. *
  508. * ApiStop() stops any executing Animation sequence.
  509. *
  510. \***************************************************************************/
  511. HRESULT
  512. DuSequence::ApiStop(Sequence::StopMsg * pmsg)
  513. {
  514. UNREFERENCED_PARAMETER(pmsg);
  515. Stop(TRUE);
  516. return S_OK;
  517. }
  518. /***************************************************************************\
  519. *
  520. * DuSequence::ApiStop
  521. *
  522. * ApiStop() stops any executing Animation sequence.
  523. *
  524. \***************************************************************************/
  525. void
  526. DuSequence::Stop(BOOL fKillAnimations)
  527. {
  528. if (IsPlaying()) {
  529. //
  530. // To prevent re-entrancy, mark that we are no longer playing. However,
  531. // don't remove ourself as a listener until we are done.
  532. //
  533. Visual * pgvSubject = m_pgvSubject;
  534. m_pgvSubject = NULL;
  535. //
  536. // Stop any queued Animations. When doing this, set
  537. // m_arAniData[idx].hact to NULL to signal to the Action to not
  538. // create the Animation. We need to do this since every Action will
  539. // get called back.
  540. //
  541. if (fKillAnimations) {
  542. PRID prid = 0;
  543. VerifyHR(m_pflow->GetPRID(&prid));
  544. Animation::Stop(pgvSubject, prid);
  545. int cItems = m_arAniData.GetSize();
  546. for (int idx = 0; idx < cItems; idx++) {
  547. HACTION hact = m_arAniData[idx].hact;
  548. if (hact != NULL) {
  549. DeleteHandle(hact);
  550. AssertMsg(m_arAniData[idx].hact == NULL, "Ensure Action is destroyed");
  551. }
  552. }
  553. }
  554. AssertMsg(m_cQueuedAni == 0, "All queued animations should be destroyed");
  555. m_arAniData.RemoveAll();
  556. //
  557. // Notify any listeners that this sequence has completed.
  558. //
  559. MSGID msgid = 0;
  560. const GUID * rgMsg[] = { &__uuidof(Animation::evComplete) };
  561. if (!FindGadgetMessages(rgMsg, &msgid, 1)) {
  562. AssertMsg(0, "Animations have not been properly registered");
  563. }
  564. Animation::CompleteEvent msg;
  565. msg.cbSize = sizeof(msg);
  566. msg.nMsg = msgid;
  567. msg.hgadMsg = GetStub()->GetHandle();
  568. msg.fNormal = !fKillAnimations;
  569. DUserSendEvent(&msg, 0);
  570. //
  571. // Remove ourself as a Listener
  572. //
  573. VerifyHR(pgvSubject->RemoveHandlerG(GM_DESTROY, GetStub()));
  574. //
  575. // Release outstanding reference from when started Play().
  576. //
  577. Release();
  578. }
  579. }
  580. /***************************************************************************\
  581. *
  582. * DuSequence::QueueAnimation
  583. *
  584. * QueueAnimation() queues an Action to be fired when the specified segment
  585. * of the overall sequence is to be animated. Since an Animation can only
  586. * animate a single segment, we will build multiple Animations to play the
  587. * entire sequence.
  588. *
  589. \***************************************************************************/
  590. HRESULT
  591. DuSequence::QueueAnimation(
  592. IN int idxKeyFrame) // KeyFrame to setup
  593. {
  594. AssertMsg((idxKeyFrame < m_arAniData.GetSize()) && (idxKeyFrame >= 0),
  595. "Must have valid, non-final keyframe");
  596. SeqData & data1 = m_arSeqData[idxKeyFrame];
  597. AniData & ad = m_arAniData[idxKeyFrame];
  598. ad.pseq = this;
  599. ad.idxFrame = idxKeyFrame;
  600. //
  601. // Setup the segment. If successful, increment m_cQueuedAni to reflect
  602. // that the animation has been "enqueued". We need to wait until all
  603. // are dequeued before we can "stop" the Animation and allow applications
  604. // to modify the Sequence.
  605. //
  606. HRESULT hr;
  607. if (IsSameTime(data1.flTime, 0.0f)) {
  608. //
  609. // This segment immediate occurs, so directly build the Animation.
  610. //
  611. ad.hact = NULL; // No action
  612. hr = BuildAnimation(idxKeyFrame);
  613. if (SUCCEEDED(hr)) {
  614. m_cQueuedAni++;
  615. }
  616. } else {
  617. //
  618. // This segment occurs in the future, so build a new Action that will
  619. // be signaled when to begin the Animation between the specified
  620. // keyframes.
  621. //
  622. GMA_ACTION act;
  623. ZeroMemory(&act, sizeof(act));
  624. act.cbSize = sizeof(act);
  625. act.flDelay = data1.flTime;
  626. act.flDuration = 0.0;
  627. act.flPeriod = 0.0;
  628. act.cRepeat = 0;
  629. act.dwPause = (DWORD) -1;
  630. act.pfnProc = DuSequence::ActionProc;
  631. act.pvData = &(m_arAniData[idxKeyFrame]);
  632. if ((ad.hact = CreateAction(&act)) != NULL) {
  633. m_cQueuedAni++;
  634. hr = S_OK;
  635. } else {
  636. hr = (HRESULT) GetLastError();
  637. }
  638. }
  639. return hr;
  640. }
  641. /***************************************************************************\
  642. *
  643. * DuSequence::BuildAnimation
  644. *
  645. * BuildAnimation() builds the actual Animation for a given segment of the
  646. * sequence. This function is called by QueueAnimation() (for immediate
  647. * segments) and ActionProc() (as future segments become ready).
  648. *
  649. \***************************************************************************/
  650. HRESULT
  651. DuSequence::BuildAnimation(
  652. IN int idxKeyFrame) // KeyFrame to animate
  653. {
  654. //
  655. // Setup the actual Animation.
  656. //
  657. SeqData & data1 = m_arSeqData[idxKeyFrame];
  658. SeqData & data2 = m_arSeqData[idxKeyFrame + 1];
  659. float flDuration = data2.flTime - data1.flTime;
  660. AssertMsg(m_pflow != NULL, "Must have valid Flow");
  661. m_pflow->SetKeyFrame(Flow::tBegin, data1.pkf);
  662. m_pflow->SetKeyFrame(Flow::tEnd, data2.pkf);
  663. Animation::AniCI aci;
  664. ZeroMemory(&aci, sizeof(aci));
  665. aci.cbSize = sizeof(aci);
  666. aci.act.flDuration = flDuration;
  667. aci.act.flPeriod = 1;
  668. aci.act.cRepeat = 0;
  669. aci.act.dwPause = m_dwFramePause;
  670. aci.pgvSubject = m_pgvSubject;
  671. aci.pipol = data1.pipol;
  672. aci.pgflow = m_pflow;
  673. Animation * pani = Animation::Build(&aci);
  674. if (pani != NULL) {
  675. MSGID msgid = 0;
  676. const GUID * rgMsg[] = { &__uuidof(Animation::evComplete) };
  677. if (!FindGadgetMessages(rgMsg, &msgid, 1)) {
  678. AssertMsg(0, "Animations have not been properly registered");
  679. }
  680. VerifyHR(pani->AddHandlerD(msgid, EVENT_DELEGATE(this, OnAnimationComplete)));
  681. pani->Release();
  682. return S_OK;
  683. } else {
  684. //
  685. // Unable to build the Animation, so stop any future Animations.
  686. //
  687. Stop();
  688. return (HRESULT) GetLastError();
  689. }
  690. }
  691. /***************************************************************************\
  692. *
  693. * DuSequence::ActionProc
  694. *
  695. * ActionProc() is called when the Animation for a given segment is supposed
  696. * to begin.
  697. *
  698. \***************************************************************************/
  699. void CALLBACK
  700. DuSequence::ActionProc(
  701. IN GMA_ACTIONINFO * pmai) // Action Information
  702. {
  703. AniData * pad = reinterpret_cast<AniData *>(pmai->pvData);
  704. DuSequence * pseq = pad->pseq;
  705. if (pmai->fFinished) {
  706. if (pad->hact != NULL) {
  707. //
  708. // The Animation was never built, so we need to decrement the
  709. // number of outstanding Animations.
  710. //
  711. pad->hact = NULL;
  712. AssertMsg(pseq->m_cQueuedAni > 0, "Must have an outstanding Animation");
  713. if (--pseq->m_cQueuedAni == 0) {
  714. pseq->Stop(FALSE);
  715. }
  716. }
  717. return;
  718. }
  719. pad->hact = NULL;
  720. pseq->BuildAnimation(pad->idxFrame);
  721. }
  722. /***************************************************************************\
  723. *
  724. * DuSequence::OnAnimationComplete
  725. *
  726. * OnAnimationComplete() is called when an Animation has been completed and
  727. * is no longer attached to the subject.
  728. *
  729. \***************************************************************************/
  730. UINT CALLBACK
  731. DuSequence::OnAnimationComplete(EventMsg * pmsg)
  732. {
  733. //
  734. // If all outstanding Animations have ended, then stop the playback.
  735. //
  736. UNREFERENCED_PARAMETER(pmsg);
  737. AssertMsg(m_cQueuedAni > 0, "Must have an outstanding Animation");
  738. if (--m_cQueuedAni == 0) {
  739. Stop(FALSE);
  740. }
  741. return DU_S_COMPLETE;
  742. }
  743. /***************************************************************************\
  744. *
  745. * DuSequence::ApiReset
  746. *
  747. * ApiReset() resets the given Visual to the beginning of the sequence.
  748. *
  749. \***************************************************************************/
  750. HRESULT
  751. DuSequence::ApiReset(Sequence::ResetMsg * pmsg)
  752. {
  753. if (IsPlaying()) {
  754. PromptInvalid("Sequence is busy");
  755. return DU_E_BUSY;
  756. }
  757. HRESULT hr = CheckComplete();
  758. if (FAILED(hr)) {
  759. return hr;
  760. }
  761. if (m_arSeqData.GetSize() > 0) {
  762. ResetSubject(pmsg->pgvSubject, 0);
  763. }
  764. return S_OK;
  765. }
  766. /***************************************************************************\
  767. *
  768. * DuSequence::ApiGotoTime
  769. *
  770. * ApiGotoTime() applies all keyframes to the given Visual that would applied
  771. * at a given time.
  772. *
  773. \***************************************************************************/
  774. HRESULT
  775. DuSequence::ApiGotoTime(Sequence::GotoTimeMsg * pmsg)
  776. {
  777. if (IsPlaying()) {
  778. PromptInvalid("Sequence is busy");
  779. return DU_E_BUSY;
  780. }
  781. HRESULT hr = CheckComplete();
  782. if (FAILED(hr)) {
  783. return hr;
  784. }
  785. //
  786. // Find the keyframe before the time
  787. //
  788. int cItems = m_arSeqData.GetSize();
  789. if (cItems == 0) {
  790. //
  791. // No key frames, so nothing to do.
  792. //
  793. return S_OK;
  794. } else if (cItems == 1) {
  795. //
  796. // Only one keyframe, so just reset the object
  797. //
  798. ResetSubject(pmsg->pgvSubject, 0);
  799. } else {
  800. //
  801. // Multiple keyframes- need to determine the closest keyframe.
  802. // - If land on a keyframe, then "exact"
  803. // - If before all keyframes, idxFrame = -1;
  804. // - If after all keyframes, idxFrame = cItems
  805. // - If in the middle, idxFrame = first frame
  806. //
  807. int idxFrame = -1;
  808. BOOL fExact = FALSE;
  809. int cItems = m_arSeqData.GetSize();
  810. if (pmsg->flTime > m_arSeqData[cItems - 1].flTime) {
  811. idxFrame = cItems;
  812. } else {
  813. for (int idx = 0; idx < cItems; idx++) {
  814. SeqData & data = m_arSeqData[idx];
  815. if (data.pkf != NULL) {
  816. if (IsSameTime(data.flTime, pmsg->flTime)) {
  817. idxFrame = idx;
  818. fExact = TRUE;
  819. break;
  820. } else if (data.flTime > pmsg->flTime) {
  821. idxFrame = idx - 1;
  822. fExact = FALSE;
  823. break;
  824. }
  825. }
  826. }
  827. }
  828. if (fExact) {
  829. //
  830. // Exactly landed on a keyframe, so set directly
  831. //
  832. ResetSubject(pmsg->pgvSubject, idxFrame);
  833. } else {
  834. //
  835. // Interpolate between two keyframes. Since this wasn't an exact
  836. // match, we need to cap the keyframes.
  837. //
  838. if (idxFrame < 0) {
  839. ResetSubject(pmsg->pgvSubject, 0);
  840. } else if (idxFrame >= cItems) {
  841. ResetSubject(pmsg->pgvSubject, cItems - 1);
  842. } else {
  843. SeqData & dataA = m_arSeqData[idxFrame];
  844. SeqData & dataB = m_arSeqData[idxFrame + 1];
  845. float flTimeA = dataA.flTime;
  846. float flTimeB = dataB.flTime;
  847. float flProgress = (pmsg->flTime - flTimeA) / (flTimeB - flTimeA);
  848. if (flProgress > 1.0f) {
  849. flProgress = 1.0f;
  850. }
  851. m_pflow->SetKeyFrame(Flow::tBegin, dataA.pkf);
  852. m_pflow->SetKeyFrame(Flow::tEnd, dataB.pkf);
  853. m_pflow->OnAction(pmsg->pgvSubject, dataA.pipol, flProgress);
  854. }
  855. }
  856. }
  857. return S_OK;
  858. }
  859. /***************************************************************************\
  860. *
  861. * DuSequence::RemoveAllKeyFrames
  862. *
  863. * RemoveAllKeyFrames() removes all KeyFrames.
  864. *
  865. \***************************************************************************/
  866. void
  867. DuSequence::RemoveAllKeyFrames()
  868. {
  869. int cItems = m_arSeqData.GetSize();
  870. for (int idx = 0; idx < cItems; idx++) {
  871. SeqData & data = m_arSeqData[idx];
  872. ClientFree(data.pkf);
  873. SafeRelease(data.pipol);
  874. }
  875. m_arSeqData.RemoveAll();
  876. }
  877. /***************************************************************************\
  878. *
  879. * DuSequence::ResetSubject
  880. *
  881. * ResetSubject() resets the given subject to the beginning of the Sequence.
  882. *
  883. \***************************************************************************/
  884. void
  885. DuSequence::ResetSubject(Visual * pgvSubject, int idxFrame)
  886. {
  887. m_pflow->SetKeyFrame(Flow::tBegin, m_arSeqData[idxFrame].pkf);
  888. m_pflow->OnReset(pgvSubject);
  889. }
  890. /***************************************************************************\
  891. *
  892. * DuSequence::CompareItems
  893. *
  894. * CompareItems() is called from SortKeyFrames() to sort two individual
  895. * KeyFrames by time.
  896. *
  897. \***************************************************************************/
  898. int
  899. DuSequence::CompareItems(
  900. IN const void * pva, // First SeqData
  901. IN const void * pvb) // Second SeqData
  902. {
  903. float flTimeA = ((SeqData *) pva)->flTime;
  904. float flTimeB = ((SeqData *) pvb)->flTime;
  905. if (flTimeA < flTimeB) {
  906. return -1;
  907. } else if (flTimeA > flTimeB) {
  908. return 1;
  909. } else {
  910. return 0;
  911. }
  912. }
  913. /***************************************************************************\
  914. *
  915. * DuSequence::FindAtTime
  916. *
  917. * FindAtTime() finds the KeyFrame at the given time.
  918. *
  919. \***************************************************************************/
  920. void
  921. DuSequence::FindAtTime(
  922. IN float flTime, // Time of KeyFrame
  923. OUT int * pidxKeyFrame // KeyFrame, if found
  924. ) const
  925. {
  926. int cItems = m_arSeqData.GetSize();
  927. for (int idx = 0; idx < cItems; idx++) {
  928. SeqData & data = m_arSeqData[idx];
  929. if (data.pkf != NULL) {
  930. if (IsSameTime(data.flTime, flTime)) {
  931. *pidxKeyFrame = idx;
  932. return;
  933. }
  934. }
  935. }
  936. *pidxKeyFrame = -1; // Not found
  937. }
  938. /***************************************************************************\
  939. *
  940. * DuSequence::CheckComplete
  941. *
  942. * CheckComplete() determines if all information for the Sequence has been
  943. * filled in. This is necessary when use the sequence to play animations.
  944. *
  945. \***************************************************************************/
  946. HRESULT
  947. DuSequence::CheckComplete() const
  948. {
  949. if (m_pflow == NULL) {
  950. PromptInvalid("Flow has not been specified");
  951. return E_INVALIDARG;
  952. }
  953. int cItems = m_arSeqData.GetSize();
  954. for (int idx = 0; idx < cItems; idx++) {
  955. if (m_arSeqData[idx].pkf == NULL) {
  956. PromptInvalid("KeyFrame information has not been specified");
  957. return E_INVALIDARG;
  958. }
  959. if (m_arSeqData[idx].pipol == NULL) {
  960. PromptInvalid("Interpolation has not been specified");
  961. return E_INVALIDARG;
  962. }
  963. }
  964. return S_OK;
  965. }
  966. #if DBG
  967. /***************************************************************************\
  968. *
  969. * DuSequence::DEBUG_IsProperTimeOrder
  970. *
  971. * DEBUG_IsProperTimeOrder() validates that all keyframes are in increasing
  972. * time order.
  973. *
  974. \***************************************************************************/
  975. BOOL
  976. DuSequence::DEBUG_IsProperTimeOrder() const
  977. {
  978. float flTime = 0;
  979. int cItems = m_arSeqData.GetSize();
  980. for (int idx = 0; idx < cItems; idx++) {
  981. if (m_arSeqData[idx].flTime < flTime) {
  982. return FALSE;
  983. }
  984. flTime = m_arSeqData[idx].flTime;
  985. }
  986. return TRUE;
  987. }
  988. #endif // DBG
  989. #endif // ENABLE_MSGTABLE_API