Panda3D
animControl.cxx
1 // Filename: animControl.cxx
2 // Created by: drose (19Feb99)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "animControl.h"
16 #include "animChannelBase.h"
17 #include "partBundle.h"
18 #include "config_chan.h"
19 #include "dcast.h"
20 #include "mutexHolder.h"
21 #include "throw_event.h"
22 
23 TypeHandle AnimControl::_type_handle;
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: AnimControl::Constructor
27 // Access: Public
28 // Description: This constructor is used to create a temporarily
29 // uninitialized AnimControl that will serve as a
30 // placeholder for an animation while the animation is
31 // being loaded during an asynchronous load-and-bind
32 // operation.
33 ////////////////////////////////////////////////////////////////////
35 AnimControl(const string &name, PartBundle *part,
36  double frame_rate, int num_frames) :
37  Namable(name),
38  _pending_lock(name),
39  _pending_cvar(_pending_lock),
40  _bound_joints(BitArray::all_on())
41 {
42 #ifdef DO_MEMORY_USAGE
43  MemoryUsage::update_type(this, get_class_type());
44 #endif
45 
46  _pending = true;
47  _part = part;
48  _anim = NULL;
49  _channel_index = -1;
50  set_frame_rate(frame_rate);
51  set_num_frames(num_frames);
52 
53  _marked_frame = -1;
54 }
55 
56 ////////////////////////////////////////////////////////////////////
57 // Function: AnimControl::setup_anim
58 // Access: Public
59 // Description: This can only be called once for a given AnimControl.
60 // It is used to supply the AnimBundle and related
61 // information.
62 ////////////////////////////////////////////////////////////////////
63 void AnimControl::
64 setup_anim(PartBundle *part, AnimBundle *anim, int channel_index,
65  const BitArray &bound_joints) {
66  MutexHolder holder(_pending_lock);
67  nassertv(_pending && part == _part);
68  nassertv(_anim == (AnimBundle *)NULL);
69  _anim = anim;
70  _channel_index = channel_index;
71  _bound_joints = bound_joints;
72  set_frame_rate(_anim->get_base_frame_rate());
73  set_num_frames(_anim->get_num_frames());
74 
75  // Now the AnimControl is fully set up.
76  _marked_frame = -1;
77  _pending = false;
78  _pending_cvar.notify_all();
79  if (!_pending_done_event.empty()) {
80  throw_event(_pending_done_event);
81  }
82 }
83 
84 ////////////////////////////////////////////////////////////////////
85 // Function: AnimControl::set_bound_joints
86 // Access: Public
87 // Description: Called to initialize the AnimControl with its array
88 // of bound_joints, before setup_anim() has completed.
89 ////////////////////////////////////////////////////////////////////
90 void AnimControl::
91 set_bound_joints(const BitArray &bound_joints) {
92  MutexHolder holder(_pending_lock);
93  _bound_joints = bound_joints;
94 }
95 
96 ////////////////////////////////////////////////////////////////////
97 // Function: AnimControl::fail_anim
98 // Access: Public
99 // Description: This can only be called once for a given AnimControl.
100 // It indicates the attempt to bind it asynchronously
101 // has failed.
102 ////////////////////////////////////////////////////////////////////
103 void AnimControl::
105  MutexHolder holder(_pending_lock);
106  nassertv(_pending && part == _part);
107  _pending = false;
108  _pending_cvar.notify_all();
109  if (!_pending_done_event.empty()) {
110  throw_event(_pending_done_event);
111  }
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: AnimControl::Destructor
116 // Access: Published, Virtual
117 // Description:
118 ////////////////////////////////////////////////////////////////////
119 AnimControl::
120 ~AnimControl() {
121  get_part()->set_control_effect(this, 0.0f);
122 }
123 
124 ////////////////////////////////////////////////////////////////////
125 // Function: AnimControl::wait_pending
126 // Access: Published
127 // Description: Blocks the current thread until the AnimControl has
128 // finished loading and is fully bound.
129 ////////////////////////////////////////////////////////////////////
130 void AnimControl::
132  MutexHolder holder(_pending_lock);
133  if (_pending) {
134  // TODO: we should elevate the priority of the associated
135  // BindAnimRequest while we're waiting for it, so it will jump to
136  // the front of the queue.
137  chan_cat.info()
138  << "Blocking " << *Thread::get_current_thread()
139  << " until " << get_name() << " is bound\n";
140  while (_pending) {
141  _pending_cvar.wait();
142  }
143  }
144 }
145 
146 ////////////////////////////////////////////////////////////////////
147 // Function: AnimControl::set_pending_done_event
148 // Access: Published
149 // Description: Specifies an event name that will be thrown when the
150 // AnimControl is finished binding asynchronously. If
151 // the AnimControl has already finished binding, the
152 // event will be thrown immediately.
153 ////////////////////////////////////////////////////////////////////
154 void AnimControl::
155 set_pending_done_event(const string &done_event) {
156  MutexHolder holder(_pending_lock);
157  _pending_done_event = done_event;
158  if (!_pending) {
159  throw_event(_pending_done_event);
160  }
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: AnimControl::get_pending_done_event
165 // Access: Published
166 // Description: Returns the event name that will be thrown when the
167 // AnimControl is finished binding asynchronously.
168 ////////////////////////////////////////////////////////////////////
169 string AnimControl::
171  MutexHolder holder(_pending_lock);
172  return _pending_done_event;
173 }
174 
175 ////////////////////////////////////////////////////////////////////
176 // Function: AnimControl::get_part
177 // Access: Published
178 // Description: Returns the PartBundle bound in with this
179 // AnimControl.
180 ////////////////////////////////////////////////////////////////////
182 get_part() const {
183  return DCAST(PartBundle, _part);
184 }
185 
186 ////////////////////////////////////////////////////////////////////
187 // Function: AnimControl::output
188 // Access: Published
189 // Description:
190 ////////////////////////////////////////////////////////////////////
191 void AnimControl::
192 output(ostream &out) const {
193  out << "AnimControl(" << get_name() << ", " << get_part()->get_name()
194  << ": ";
195  AnimInterface::output(out);
196  out << ")";
197 
198  if (is_pending()) {
199  out << " (pending bind)";
200  } else if (!has_anim()) {
201  out << " (failed bind)";
202  }
203 }
204 
205 ////////////////////////////////////////////////////////////////////
206 // Function: AnimControl::channel_has_changed
207 // Access: Public
208 // Description: Returns true if the indicated channel value has
209 // changed since the last call to mark_channels().
210 ////////////////////////////////////////////////////////////////////
211 bool AnimControl::
212 channel_has_changed(AnimChannelBase *channel, bool frame_blend_flag) const {
213  if (_marked_frame < 0) {
214  return true;
215  }
216 
217  int this_frame = get_frame();
218  double this_frac = 0.0;
219  if (frame_blend_flag) {
220  this_frac = get_frac();
221  }
222  return channel->has_changed(_marked_frame, _marked_frac,
223  this_frame, this_frac);
224 }
225 
226 ////////////////////////////////////////////////////////////////////
227 // Function: AnimControl::mark_channels
228 // Access: Public
229 // Description: Marks this point as the point of reference for the
230 // next call to channel_has_changed().
231 ////////////////////////////////////////////////////////////////////
232 void AnimControl::
233 mark_channels(bool frame_blend_flag) {
234  _marked_frame = get_frame();
235  _marked_frac = 0.0;
236  if (frame_blend_flag) {
237  _marked_frac = get_frac();
238  }
239 }
240 
241 ////////////////////////////////////////////////////////////////////
242 // Function: AnimControl::animation_activated
243 // Access: Protected, Virtual
244 // Description: This is provided as a callback method for when the
245 // user calls one of the play/loop/pose type methods to
246 // start the animation playing.
247 ////////////////////////////////////////////////////////////////////
248 void AnimControl::
249 animation_activated() {
250  get_part()->control_activated(this);
251 }
void set_control_effect(AnimControl *control, PN_stdfloat effect)
Sets the amount by which the character is affected by the indicated AnimControl (and its associated a...
Definition: partBundle.I:232
void wait()
Waits on the condition.
AnimControl(const string &name, PartBundle *part, double frame_rate, int num_frames)
This constructor is used to create a temporarily uninitialized AnimControl that will serve as a place...
Definition: animControl.cxx:35
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:31
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
void set_pending_done_event(const string &done_event)
Specifies an event name that will be thrown when the AnimControl is finished binding asynchronously...
bool channel_has_changed(AnimChannelBase *channel, bool frame_blend_flag) const
Returns true if the indicated channel value has changed since the last call to mark_channels().
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
virtual bool has_changed(int last_frame, double last_frac, int this_frame, double this_frac)
Returns true if the value has changed since the last call to has_changed().
PartBundle * get_part() const
Returns the PartBundle bound in with this AnimControl.
void notify_all()
Informs all of the other threads who are currently blocked on wait() that the relevant condition has ...
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:42
Parent class for all animation channels.
A base class for all things which can have a name.
Definition: namable.h:29
string get_pending_done_event() const
Returns the event name that will be thrown when the AnimControl is finished binding asynchronously...
void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index, const BitArray &bound_joints)
This can only be called once for a given AnimControl.
Definition: animControl.cxx:64
void set_bound_joints(const BitArray &bound_joints)
Called to initialize the AnimControl with its array of bound_joints, before setup_anim() has complete...
Definition: animControl.cxx:91
void wait_pending()
Blocks the current thread until the AnimControl has finished loading and is fully bound...
bool has_anim() const
Returns true if the AnimControl was successfully loaded, or false if there was a problem.
Definition: animControl.I:39
virtual void control_activated(AnimControl *control)
Called by the AnimControl whenever it starts an animation.
Definition: partBundle.cxx:606
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:49
void mark_channels(bool frame_blend_flag)
Marks this point as the point of reference for the next call to channel_has_changed().
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
int get_frame() const
Returns the current integer frame number.
double get_frac() const
Returns the fractional part of the current frame.
void fail_anim(PartBundle *part)
This can only be called once for a given AnimControl.
bool is_pending() const
Returns true if the AnimControl is being bound asynchronously, and has not yet finished.
Definition: animControl.I:27