Panda3D
animInterface.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file animInterface.cxx
10  * @author drose
11  * @date 2005-09-20
12  */
13 
14 #include "animInterface.h"
15 #include "clockObject.h"
16 #include "bamReader.h"
17 #include "bamWriter.h"
18 #include "datagram.h"
19 #include "datagramIterator.h"
20 
21 using std::max;
22 using std::min;
23 
24 TypeHandle AnimInterface::_type_handle;
25 
26 /**
27  *
28  */
29 AnimInterface::
30 AnimInterface() :
31  _num_frames(0)
32 {
33 }
34 
35 /**
36  *
37  */
38 AnimInterface::
39 AnimInterface(const AnimInterface &copy) :
40  _num_frames(copy._num_frames),
41  _cycler(copy._cycler)
42 {
43 }
44 
45 /**
46  *
47  */
48 AnimInterface::
49 ~AnimInterface() {
50 }
51 
52 /**
53  * Returns the number of frames in the animation. This is a property of the
54  * animation and may not be directly adjusted by the user (although it may
55  * change without warning with certain kinds of animations, since this is a
56  * virtual method that may be overridden).
57  */
58 int AnimInterface::
59 get_num_frames() const {
60  return _num_frames;
61 }
62 
63 /**
64  *
65  */
66 void AnimInterface::
67 output(std::ostream &out) const {
68  CDReader cdata(_cycler);
69  cdata->output(out);
70 }
71 
72 /**
73  * This is provided as a callback method for when the user calls one of the
74  * play/loop/pose type methods to start the animation playing.
75  */
76 void AnimInterface::
77 animation_activated() {
78 }
79 
80 /**
81  * Writes the contents of this object to the datagram for shipping out to a
82  * Bam file.
83  */
84 void AnimInterface::
85 write_datagram(BamWriter *manager, Datagram &dg) {
86  dg.add_int32(_num_frames);
87  manager->write_cdata(dg, _cycler);
88 }
89 
90 /**
91  * This internal function is called by make_from_bam to read in all of the
92  * relevant data from the BamFile for the new AnimInterface.
93  */
94 void AnimInterface::
95 fillin(DatagramIterator &scan, BamReader *manager) {
96  _num_frames = scan.get_int32();
97  manager->read_cdata(scan, _cycler);
98 }
99 
100 /**
101  *
102  */
103 AnimInterface::CData::
104 CData() :
105  _frame_rate(0.0),
106  _play_mode(PM_pose),
107  _start_time(0.0),
108  _start_frame(0.0),
109  _play_frames(0.0),
110  _from_frame(0),
111  _to_frame(0),
112  _play_rate(1.0),
113  _effective_frame_rate(0.0),
114  _paused(true),
115  _paused_f(0.0)
116 {
117 }
118 
119 /**
120  *
121  */
122 AnimInterface::CData::
123 CData(const AnimInterface::CData &copy) :
124  _frame_rate(copy._frame_rate),
125  _play_mode(copy._play_mode),
126  _start_time(copy._start_time),
127  _start_frame(copy._start_frame),
128  _play_frames(copy._play_frames),
129  _from_frame(copy._from_frame),
130  _to_frame(copy._to_frame),
131  _play_rate(copy._play_rate),
132  _effective_frame_rate(copy._effective_frame_rate),
133  _paused(copy._paused),
134  _paused_f(copy._paused_f)
135 {
136 }
137 
138 /**
139  *
140  */
141 CycleData *AnimInterface::CData::
142 make_copy() const {
143  return new CData(*this);
144 }
145 
146 /**
147  * Writes the contents of this object to the datagram for shipping out to a
148  * Bam file.
149  */
150 void AnimInterface::CData::
151 write_datagram(BamWriter *, Datagram &dg) const {
152  dg.add_stdfloat(_frame_rate);
153  dg.add_uint8(_play_mode);
154  dg.add_stdfloat(_start_time);
155  dg.add_stdfloat(_start_frame);
156  dg.add_stdfloat(_play_frames);
157  dg.add_int32(_from_frame);
158  dg.add_int32(_to_frame);
159  dg.add_stdfloat(_play_rate);
160  dg.add_bool(_paused);
161  dg.add_stdfloat(_paused_f);
162 }
163 
164 /**
165  * This internal function is called by make_from_bam to read in all of the
166  * relevant data from the BamFile for the new AnimInterface.
167  */
168 void AnimInterface::CData::
169 fillin(DatagramIterator &scan, BamReader *) {
170  _frame_rate = scan.get_stdfloat();
171  _play_mode = (PlayMode)scan.get_uint8();
172  _start_time = scan.get_stdfloat();
173  _start_frame = scan.get_stdfloat();
174  _play_frames = scan.get_stdfloat();
175  _from_frame = scan.get_int32();
176  _to_frame = scan.get_int32();
177  _play_rate = scan.get_stdfloat();
178  _effective_frame_rate = _frame_rate * _play_rate;
179  _paused = scan.get_bool();
180  _paused_f = scan.get_stdfloat();
181 }
182 
183 /**
184  * Runs the animation from the frame "from" to and including the frame "to",
185  * at which point the animation is stopped. Both "from" and "to" frame
186  * numbers may be outside the range (0, get_num_frames()) and the animation
187  * will follow the range correctly, reporting numbers modulo get_num_frames().
188  * For instance, play(0, get_num_frames() * 2) will play the animation twice
189  * and then stop.
190  */
191 void AnimInterface::CData::
192 play(double from, double to) {
193  if (from >= to) {
194  pose(from);
195  return;
196  }
197 
198  _play_mode = PM_play;
200  _start_frame = from;
201  _play_frames = to - from + 1.0;
202  _from_frame = (int)floor(from);
203  _to_frame = (int)floor(to);
204  _paused_f = 0.0;
205 
206  if (_effective_frame_rate < 0.0) {
207  // If we'll be playing backward, start at the end.
208  _start_time -= _play_frames / _effective_frame_rate;
209  }
210 }
211 
212 /**
213  * Loops the animation from the frame "from" to and including the frame "to",
214  * indefinitely. If restart is true, the animation is restarted from the
215  * beginning; otherwise, it continues from the current frame.
216  */
217 void AnimInterface::CData::
218 loop(bool restart, double from, double to) {
219  if (from >= to) {
220  pose(from);
221  return;
222  }
223 
224  double fframe = get_full_fframe();
225 
226  _play_mode = PM_loop;
228  _start_frame = from;
229  _play_frames = to - from + 1.0;
230  _from_frame = (int)floor(from);
231  _to_frame = (int)floor(to);
232  _paused_f = 0.0;
233 
234  if (!restart) {
235  fframe = min(max(fframe, from), to);
236  if (_paused) {
237  _paused_f = fframe - _start_frame;
238  } else {
239  _start_time -= (fframe - _start_frame) / _effective_frame_rate;
240  }
241  }
242 }
243 
244 /**
245  * Loops the animation from the frame "from" to and including the frame "to",
246  * and then back in the opposite direction, indefinitely.
247  */
248 void AnimInterface::CData::
249 pingpong(bool restart, double from, double to) {
250  if (from >= to) {
251  pose(from);
252  return;
253  }
254 
255  double fframe = get_full_fframe();
256 
257  _play_mode = PM_pingpong;
259  _start_frame = from;
260  _play_frames = to - from + 1.0;
261  _from_frame = (int)floor(from);
262  _to_frame = (int)floor(to);
263  _paused_f = 0.0;
264 
265  if (!restart) {
266  fframe = min(max(fframe, from), to);
267  if (_paused) {
268  _paused_f = fframe - _start_frame;
269  } else {
270  _start_time -= (fframe - _start_frame) / _effective_frame_rate;
271  }
272  }
273 }
274 
275 /**
276  * Sets the animation to the indicated frame and holds it there.
277  */
278 void AnimInterface::CData::
279 pose(double frame) {
280  _play_mode = PM_pose;
282  _start_frame = frame;
283  _play_frames = 0.0;
284  _from_frame = (int)floor(frame);
285  _to_frame = (int)floor(frame);
286  _paused_f = 0.0;
287 }
288 
289 /**
290  * Returns the current integer frame number, plus the indicated increment.
291  *
292  * Unlike the value returned by get_frame(), this frame number may extend
293  * beyond the range of get_num_frames() if the frame range passed to play(),
294  * loop(), etc. did.
295  *
296  * Unlike the value returned by get_full_fframe(), this return value will
297  * never exceed the value passed to to_frame in the play() method.
298  */
299 int AnimInterface::CData::
300 get_full_frame(int increment) const {
301  int frame = (int)floor(get_full_fframe()) + increment;
302  if (_play_mode == PM_play) {
303  // In play mode, we never let the return value exceed (_from_frame,
304  // _to_frame).
305  frame = min(max(frame, _from_frame), _to_frame);
306  }
307  return frame;
308 }
309 
310 /**
311  * Returns the current floating-point frame number.
312  *
313  * Unlike the value returned by get_frame(), this frame number may extend
314  * beyond the range of get_num_frames() if the frame range passed to play(),
315  * loop(), etc. did.
316  *
317  * Unlike the value returned by get_full_frame(), this return value may equal
318  * (to_frame + 1.0), when the animation has played to its natural end.
319  * However, in this case the return value of get_full_frame() will be
320  * to_frame, not (to_frame + 1).
321  */
322 double AnimInterface::CData::
323 get_full_fframe() const {
324  switch (_play_mode) {
325  case PM_pose:
326  return _start_frame;
327 
328  case PM_play:
329  return min(max(get_f(), 0.0), _play_frames) + _start_frame;
330 
331  case PM_loop:
332  nassertr(_play_frames >= 0.0, 0.0);
333  return cmod(get_f(), _play_frames) + _start_frame;
334 
335  case PM_pingpong:
336  {
337  nassertr(_play_frames >= 0.0, 0.0);
338  double f = cmod(get_f(), _play_frames * 2.0);
339  if (f > _play_frames) {
340  return (_play_frames * 2.0 - f) + _start_frame;
341  } else {
342  return f + _start_frame;
343  }
344  }
345  }
346 
347  return _start_frame;
348 }
349 
350 /**
351  * Returns true if the animation is currently playing, false if it is stopped
352  * (e.g. because stop() or pose() was called, or because it reached the end
353  * of the animation after play() was called).
354  */
355 bool AnimInterface::CData::
356 is_playing() const {
357  switch (_play_mode) {
358  case PM_pose:
359  return false;
360 
361  case PM_play:
362  if (_effective_frame_rate < 0.0) {
363  // If we're playing backwards, check if we're at the beginning.
364  return get_f() > 0;
365  } else {
366  return get_f() < _play_frames;
367  }
368 
369  case PM_loop:
370  case PM_pingpong:
371  return true;
372  }
373 
374  return false;
375 }
376 
377 /**
378  *
379  */
380 void AnimInterface::CData::
381 output(std::ostream &out) const {
382  switch (_play_mode) {
383  case PM_pose:
384  out << "pose, frame " << get_full_fframe();
385  return;
386 
387  case PM_play:
388  out << "play, frame " << get_full_fframe();
389  return;
390 
391  case PM_loop:
392  out << "loop, frame " << get_full_fframe();
393  return;
394 
395  case PM_pingpong:
396  out << "pingpong, frame " << get_full_fframe();
397  return;
398  }
399 }
400 
401 /**
402  * Called internally to adjust either or both of the frame_rate or play_rate
403  * without changing the current frame number if the animation is already
404  * playing.
405  */
406 void AnimInterface::CData::
407 internal_set_rate(double frame_rate, double play_rate) {
408  double f = get_f();
409 
410  _frame_rate = frame_rate;
411  _play_rate = play_rate;
412  _effective_frame_rate = frame_rate * play_rate;
413 
414  if (_effective_frame_rate == 0.0) {
415  _paused_f = f;
416  _paused = true;
417 
418  } else {
419  // Compute a new _start_time that will keep f the same value with the new
420  // play_rate.
421  double new_elapsed = f / _effective_frame_rate;
423  _start_time = now - new_elapsed;
424  _paused = false;
425  }
426 }
427 
428 /**
429  * Returns the current floating-point frame number, elapsed since
430  * _start_frame.
431  */
432 double AnimInterface::CData::
433 get_f() const {
434  if (_paused) {
435  return _paused_f;
436 
437  } else {
439  double elapsed = now - _start_time;
440  return (elapsed * _effective_frame_rate);
441  }
442 }
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
float cmod(float x, float y)
This is similar to fmod(), but it behaves properly when x is negative: that is, it always returns a v...
Definition: cmath.I:130
bool get_bool()
Extracts a boolean value.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
int32_t get_int32()
Extracts a signed 32-bit integer.
This is the fundamental interface for things that have a play/loop/stop type interface for frame-base...
Definition: animInterface.h:35
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
Definition: datagram.I:133
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:67
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.