Panda3D
Loading...
Searching...
No Matches
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
21using std::max;
22using std::min;
23
24TypeHandle AnimInterface::_type_handle;
25
26/**
27 *
28 */
29AnimInterface::
30AnimInterface() :
31 _num_frames(0)
32{
33}
34
35/**
36 *
37 */
38AnimInterface::
39AnimInterface(const AnimInterface &copy) :
40 _num_frames(copy._num_frames),
41 _cycler(copy._cycler)
42{
43}
44
45/**
46 *
47 */
48AnimInterface::
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 */
59get_num_frames() const {
60 return _num_frames;
61}
62
63/**
64 *
65 */
66void AnimInterface::
67output(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 */
76void AnimInterface::
77animation_activated() {
78}
79
80/**
81 * Writes the contents of this object to the datagram for shipping out to a
82 * Bam file.
83 */
84void AnimInterface::
85write_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 */
94void AnimInterface::
95fillin(DatagramIterator &scan, BamReader *manager) {
96 _num_frames = scan.get_int32();
97 manager->read_cdata(scan, _cycler);
98}
99
100/**
101 *
102 */
103AnimInterface::CData::
104CData() :
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 */
122AnimInterface::CData::
123CData(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 */
141CycleData *AnimInterface::CData::
142make_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 */
150void AnimInterface::CData::
151write_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 */
168void AnimInterface::CData::
169fillin(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 */
191void AnimInterface::CData::
192play(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 */
217void AnimInterface::CData::
218loop(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 */
248void AnimInterface::CData::
249pingpong(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 */
278void AnimInterface::CData::
279pose(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 */
299int AnimInterface::CData::
300get_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 */
322double AnimInterface::CData::
323get_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 */
355bool AnimInterface::CData::
356is_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 */
380void AnimInterface::CData::
381output(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 */
406void AnimInterface::CData::
407internal_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 */
432double AnimInterface::CData::
433get_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...
void pose(double frame)
Sets the animation to the indicated frame and holds it there.
get_num_frames
Returns the number of frames in the animation.
get_full_fframe
Returns the current floating-point frame number.
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.
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.
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.
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.