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  */
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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for things that have a play/loop/stop type interface for frame-base...
Definition: animInterface.h:35
get_num_frames
Returns the number of frames in the animation.
Definition: animInterface.h:68
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
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
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
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
bool get_bool()
Extracts a boolean value.
int32_t get_int32()
Extracts a signed 32-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
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
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
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.