1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkAnimationScene.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkAnimationScene.h"
16 
17 #include "vtkCollection.h"
18 #include "vtkCollectionIterator.h"
19 #include "vtkCommand.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkTimerLog.h"
22 
23 vtkStandardNewMacro(vtkAnimationScene);
24 
25 //----------------------------------------------------------------------------
vtkAnimationScene()26 vtkAnimationScene::vtkAnimationScene()
27 {
28   this->PlayMode = PLAYMODE_SEQUENCE;
29   this->FrameRate = 10.0;
30   this->Loop = 0;
31   this->InPlay = 0;
32   this->StopPlay = 0;
33   this->AnimationTime = 0.0;
34 
35   this->AnimationCues = vtkCollection::New();
36   this->AnimationCuesIterator = this->AnimationCues->NewIterator();
37   this->AnimationTimer = vtkTimerLog::New();
38 }
39 
40 //----------------------------------------------------------------------------
~vtkAnimationScene()41 vtkAnimationScene::~vtkAnimationScene()
42 {
43   if (this->InPlay)
44     {
45     this->Stop();
46     }
47   this->AnimationCues->Delete();
48   this->AnimationCuesIterator->Delete();
49   this->AnimationTimer->Delete();
50 }
51 
52 //----------------------------------------------------------------------------
AddCue(vtkAnimationCue * cue)53 void vtkAnimationScene::AddCue(vtkAnimationCue* cue)
54 {
55   if (this->AnimationCues->IsItemPresent(cue))
56     {
57     vtkErrorMacro("Animation cue already present in the scene");
58     return;
59     }
60   if (this->TimeMode == vtkAnimationCue::TIMEMODE_NORMALIZED &&
61     cue->GetTimeMode() != vtkAnimationCue::TIMEMODE_NORMALIZED)
62     {
63     vtkErrorMacro("A cue with relative time mode cannot be added to a scene "
64       "with normalized time mode.");
65     return;
66     }
67   this->AnimationCues->AddItem(cue);
68 }
69 
70 //----------------------------------------------------------------------------
RemoveCue(vtkAnimationCue * cue)71 void vtkAnimationScene::RemoveCue(vtkAnimationCue* cue)
72 {
73   this->AnimationCues->RemoveItem(cue);
74 }
75 
76 //----------------------------------------------------------------------------
RemoveAllCues()77 void vtkAnimationScene::RemoveAllCues()
78 {
79   this->AnimationCues->RemoveAllItems();
80 }
81 //----------------------------------------------------------------------------
GetNumberOfCues()82 int vtkAnimationScene::GetNumberOfCues()
83 {
84   return this->AnimationCues->GetNumberOfItems();
85 }
86 //----------------------------------------------------------------------------
SetTimeMode(int mode)87 void vtkAnimationScene::SetTimeMode(int mode)
88 {
89   if (mode == vtkAnimationCue::TIMEMODE_NORMALIZED)
90     {
91     // If noralized time mode is being set on the scene,
92     // ensure that none of the contained cues need relative times.
93     vtkCollectionIterator *it = this->AnimationCuesIterator;
94     for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem())
95       {
96       vtkAnimationCue* cue =
97         vtkAnimationCue::SafeDownCast(it->GetCurrentObject());
98       if (cue && cue->GetTimeMode() != vtkAnimationCue::TIMEMODE_NORMALIZED)
99         {
100         vtkErrorMacro("Scene contains a cue in relative mode. It must be removed "
101           "or chaged to normalized mode before changing the scene time mode");
102         return;
103         }
104       }
105     }
106   this->Superclass::SetTimeMode(mode);
107 }
108 
109 //----------------------------------------------------------------------------
InitializeChildren()110 void vtkAnimationScene::InitializeChildren()
111 {
112   // run thr all the cues and init them.
113   vtkCollectionIterator *it = this->AnimationCuesIterator;
114   for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem())
115     {
116     vtkAnimationCue* cue =
117       vtkAnimationCue::SafeDownCast(it->GetCurrentObject());
118     if (cue)
119       {
120       cue->Initialize();
121       }
122     }
123 }
124 
125 //----------------------------------------------------------------------------
FinalizeChildren()126 void vtkAnimationScene::FinalizeChildren()
127 {
128   vtkCollectionIterator *it = this->AnimationCuesIterator;
129   for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem())
130     {
131     vtkAnimationCue* cue =
132       vtkAnimationCue::SafeDownCast(it->GetCurrentObject());
133     if (cue)
134       {
135       cue->Finalize();
136       }
137     }
138 }
139 
140 //----------------------------------------------------------------------------
Play()141 void vtkAnimationScene::Play()
142 {
143   if (this->InPlay)
144     {
145     return;
146     }
147 
148   if (this->TimeMode == vtkAnimationCue::TIMEMODE_NORMALIZED)
149     {
150     vtkErrorMacro("Cannot play a scene with normalized time mode");
151     return;
152     }
153   if (this->EndTime <= this->StartTime)
154     {
155     vtkErrorMacro("Scene start and end times are not suitable for playing");
156     return;
157     }
158 
159   this->InvokeEvent(vtkCommand::StartEvent);
160 
161   this->InPlay = 1;
162   this->StopPlay = 0;
163   this->FrameRate = (!this->FrameRate)? 1.0 : this->FrameRate;
164   // the actual play loop, check for StopPlay flag.
165 
166   double currenttime = this->AnimationTime;
167   // adjust currenttime to a valid time.
168   currenttime = (currenttime < this->StartTime || currenttime >= this->EndTime)?
169     this->StartTime : currenttime;
170 
171   double time_per_frame =
172     (this->PlayMode == PLAYMODE_SEQUENCE)?  (1.0 / this->FrameRate) : 1;
173   do
174     {
175     this->Initialize(); // Set the Scene in unintialized mode.
176     this->AnimationTimer->StartTimer();
177     double timer_start_time = currenttime;
178     double deltatime = 0.0;
179     do
180       {
181       this->Tick(currenttime, deltatime, currenttime);
182 
183       // needed to compute delta times.
184       double previous_tick_time = currenttime;
185 
186       switch (this->PlayMode)
187         {
188       case PLAYMODE_REALTIME:
189         this->AnimationTimer->StopTimer();
190         currenttime = this->AnimationTimer->GetElapsedTime() +
191           timer_start_time;
192         break;
193 
194       case PLAYMODE_SEQUENCE:
195         currenttime += time_per_frame;
196         break;
197 
198       default:
199         vtkErrorMacro("Invalid Play Mode");
200         this->StopPlay = 1;
201         }
202 
203       deltatime = currenttime - previous_tick_time;
204       deltatime = (deltatime < 0)? -1*deltatime : deltatime;
205       } while (!this->StopPlay && this->CueState != vtkAnimationCue::INACTIVE);
206       // End of loop for 1 cycle.
207 
208     // restart the loop.
209     currenttime = this->StartTime;
210     } while (this->Loop && !this->StopPlay);
211 
212   this->StopPlay = 0;
213   this->InPlay = 0;
214 
215   this->InvokeEvent(vtkCommand::EndEvent);
216 }
217 
218 //----------------------------------------------------------------------------
Stop()219 void vtkAnimationScene::Stop()
220 {
221   if (!this->InPlay)
222     {
223     return;
224     }
225   this->StopPlay = 1;
226 }
227 
228 //----------------------------------------------------------------------------
TickInternal(double currenttime,double deltatime,double clocktime)229 void vtkAnimationScene::TickInternal(
230   double currenttime, double deltatime, double clocktime)
231 {
232   this->AnimationTime = currenttime;
233   this->ClockTime = clocktime;
234 
235   vtkCollectionIterator* iter = this->AnimationCuesIterator;
236   for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
237     {
238     vtkAnimationCue* cue = vtkAnimationCue::SafeDownCast(
239       iter->GetCurrentObject());
240     if (cue)
241       {
242       switch(cue->GetTimeMode())
243         {
244       case vtkAnimationCue::TIMEMODE_RELATIVE:
245         cue->Tick(currenttime - this->StartTime, deltatime, clocktime);
246         break;
247 
248       case vtkAnimationCue::TIMEMODE_NORMALIZED:
249         cue->Tick( (currenttime - this->StartTime) / (this->EndTime - this->StartTime),
250           deltatime / (this->EndTime - this->StartTime), clocktime);
251         break;
252 
253       default:
254         vtkErrorMacro("Invalid cue time mode");
255         }
256       }
257     }
258 
259   this->Superclass::TickInternal(currenttime, deltatime, clocktime);
260 }
261 
262 //----------------------------------------------------------------------------
StartCueInternal()263 void vtkAnimationScene::StartCueInternal()
264 {
265   this->Superclass::StartCueInternal();
266   this->InitializeChildren();
267 }
268 
269 //----------------------------------------------------------------------------
EndCueInternal()270 void vtkAnimationScene::EndCueInternal()
271 {
272   this->FinalizeChildren();
273   this->Superclass::EndCueInternal();
274 }
275 
276 //----------------------------------------------------------------------------
SetAnimationTime(double currenttime)277 void vtkAnimationScene::SetAnimationTime(double currenttime)
278 {
279   if (this->InPlay)
280     {
281     vtkErrorMacro("SetAnimationTime cannot be called while playing");
282     return;
283     }
284   this->Initialize();
285   this->Tick(currenttime, 0.0, currenttime);
286   if (this->CueState == vtkAnimationCue::INACTIVE)
287     {
288     this->Finalize();
289     }
290 }
291 
292 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)293 void vtkAnimationScene::PrintSelf(ostream& os, vtkIndent indent)
294 {
295   this->Superclass::PrintSelf(os, indent);
296   os << indent << "PlayMode: " << this->PlayMode << endl;
297   os << indent << "FrameRate: " << this->FrameRate << endl;
298   os << indent << "Loop: " << this->Loop << endl;
299   os << indent << "InPlay: " << this->InPlay << endl;
300   os << indent << "StopPlay: " << this->StopPlay << endl;
301   os << indent << "AnimationTime: " << this->AnimationTime << endl;
302 }
303