Panda3D
eggMatrixTablePointer.cxx
1 // Filename: eggMatrixTablePointer.cxx
2 // Created by: drose (26Feb01)
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 "eggMatrixTablePointer.h"
16 #include "dcast.h"
17 #include "eggSAnimData.h"
18 #include "eggXfmAnimData.h"
19 #include "eggXfmSAnim.h"
20 
21 TypeHandle EggMatrixTablePointer::_type_handle;
22 
23 ////////////////////////////////////////////////////////////////////
24 // Function: EggMatrixTablePointer::Constructor
25 // Access: Public
26 // Description:
27 ////////////////////////////////////////////////////////////////////
28 EggMatrixTablePointer::
29 EggMatrixTablePointer(EggObject *object) {
30  _table = DCAST(EggTable, object);
31 
32  if (_table != (EggTable *)NULL) {
33  // Now search for the child named "xform". This contains the
34  // actual table data.
35  EggGroupNode::iterator ci;
36  bool found = false;
37  for (ci = _table->begin(); ci != _table->end() && !found; ++ci) {
38  EggNode *child = (*ci);
39  if (child->get_name() == "xform") {
40  if (child->is_of_type(EggXfmSAnim::get_class_type())) {
41  _xform = DCAST(EggXfmSAnim, child);
42  _xform->normalize();
43  found = true;
44 
45  } else if (child->is_of_type(EggXfmAnimData::get_class_type())) {
46  // Quietly replace old-style XfmAnim tables with new-style
47  // XfmSAnim tables.
48  PT(EggXfmAnimData) anim = DCAST(EggXfmAnimData, child);
49  _xform = new EggXfmSAnim(*anim);
50  _table->replace(ci, _xform.p());
51  found = true;
52  }
53  }
54  }
55  }
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: EggMatrixTablePointer::get_frame_rate
60 // Access: Public, Virtual
61 // Description: Returns the stated frame rate of this particular
62 // joint, or 0.0 if it doesn't state.
63 ////////////////////////////////////////////////////////////////////
65 get_frame_rate() const {
66  if (_xform == (EggXfmSAnim *)NULL || !_xform->has_fps()) {
67  return 0.0;
68  } else {
69  return _xform->get_fps();
70  }
71 }
72 
73 ////////////////////////////////////////////////////////////////////
74 // Function: EggMatrixTablePointer::get_num_frames
75 // Access: Public, Virtual
76 // Description: Returns the number of frames of animation for this
77 // particular joint.
78 ////////////////////////////////////////////////////////////////////
80 get_num_frames() const {
81  if (_xform == (EggXfmSAnim *)NULL) {
82  return 0;
83  } else {
84  return _xform->get_num_rows();
85  }
86 }
87 
88 ////////////////////////////////////////////////////////////////////
89 // Function: EggMatrixTablePointer::extend_to
90 // Access: Public, Virtual
91 // Description: Extends the table to the indicated number of frames.
92 ////////////////////////////////////////////////////////////////////
94 extend_to(int num_frames) {
95  nassertv(_xform != (EggXfmSAnim *)NULL);
96  _xform->normalize();
97  int num_rows = _xform->get_num_rows();
98  LMatrix4d last_mat;
99  if (num_rows == 0) {
100  last_mat = LMatrix4d::ident_mat();
101  } else {
102  _xform->get_value(num_rows - 1, last_mat);
103  }
104 
105  while (num_rows < num_frames) {
106  _xform->add_data(last_mat);
107  num_rows++;
108  }
109 }
110 
111 ////////////////////////////////////////////////////////////////////
112 // Function: EggMatrixTablePointer::get_frame
113 // Access: Public, Virtual
114 // Description: Returns the transform matrix corresponding to this
115 // joint position in the nth frame.
116 ////////////////////////////////////////////////////////////////////
118 get_frame(int n) const {
119  if (get_num_frames() == 1) {
120  // If we have exactly one frame, then we have as many frames as we
121  // want; just repeat the first frame.
122  n = 0;
123 
124  } else if (get_num_frames() == 0) {
125  // If we have no frames, we really have the identity matrix.
126  return LMatrix4d::ident_mat();
127  }
128 
129  nassertr(n >= 0 && n < get_num_frames(), LMatrix4d::ident_mat());
130  LMatrix4d mat;
131  _xform->get_value(n, mat);
132  return mat;
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: EggMatrixTablePointer::set_frame
137 // Access: Public, Virtual
138 // Description: Sets the transform matrix corresponding to this
139 // joint position in the nth frame.
140 ////////////////////////////////////////////////////////////////////
142 set_frame(int n, const LMatrix4d &mat) {
143  nassertv(n >= 0 && n < get_num_frames());
144  _xform->set_value(n, mat);
145 }
146 
147 ////////////////////////////////////////////////////////////////////
148 // Function: EggMatrixTablePointer::add_frame
149 // Access: Public, Virtual
150 // Description: Appends a new frame onto the end of the data, if
151 // possible; returns true if not possible, or false
152 // otherwise (e.g. for a static joint).
153 ////////////////////////////////////////////////////////////////////
155 add_frame(const LMatrix4d &mat) {
156  if (_xform == (EggXfmSAnim *)NULL) {
157  return false;
158  }
159 
160  return _xform->add_data(mat);
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: EggMatrixTablePointer::do_finish_reparent
165 // Access: Protected
166 // Description: Performs the actual reparenting operation
167 // by removing the node from its old parent and
168 // associating it with its new parent, if any.
169 ////////////////////////////////////////////////////////////////////
172  if (new_parent == (EggJointPointer *)NULL) {
173  // No new parent; unparent the joint.
174  EggGroupNode *egg_parent = _table->get_parent();
175  if (egg_parent != (EggGroupNode *)NULL) {
176  egg_parent->remove_child(_table.p());
177  }
178 
179  } else {
180  // Reparent the joint to its new parent (implicitly unparenting it
181  // from its previous parent).
182  EggMatrixTablePointer *new_node = DCAST(EggMatrixTablePointer, new_parent);
183  if (new_node->_table != _table->get_parent()) {
184  new_node->_table->add_child(_table.p());
185  }
186  }
187 }
188 
189 ////////////////////////////////////////////////////////////////////
190 // Function: EggMatrixTablePointer::do_rebuild
191 // Access: Public, Virtual
192 // Description: Rebuilds the entire table all at once, based on the
193 // frames added by repeated calls to add_rebuild_frame()
194 // since the last call to begin_rebuild().
195 //
196 // Until do_rebuild() is called, the animation table is
197 // not changed.
198 //
199 // The return value is true if all frames are
200 // acceptable, or false if there is some problem.
201 ////////////////////////////////////////////////////////////////////
204  LMatrix4d mat;
205  if (!db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, 0, mat)) {
206  // No rebuild frame; this is OK.
207  return true;
208  }
209 
210  if (_xform == (EggXfmSAnim *)NULL) {
211  return false;
212  }
213 
214  bool all_ok = true;
215 
216  _xform->clear_data();
217  if (!_xform->add_data(mat)) {
218  all_ok = false;
219  }
220 
221  // Assume all frames will be contiguous.
222  int n = 1;
223  while (db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, n, mat)) {
224  if (!_xform->add_data(mat)) {
225  all_ok = false;
226  }
227  ++n;
228  }
229 
230  return all_ok;
231 }
232 
233 ////////////////////////////////////////////////////////////////////
234 // Function: EggMatrixTablePointer::optimize
235 // Access: Public, Virtual
236 // Description: Resets the table before writing to disk so that
237 // redundant rows (e.g. i { 1 1 1 1 1 1 1 1 }) are
238 // collapsed out.
239 ////////////////////////////////////////////////////////////////////
242  if (_xform != (EggXfmSAnim *)NULL) {
243  _xform->optimize();
244  }
245 }
246 
247 ////////////////////////////////////////////////////////////////////
248 // Function: EggMatrixTablePointer::zero_channels
249 // Access: Public, Virtual
250 // Description: Zeroes out the named components of the transform in
251 // the animation frames.
252 ////////////////////////////////////////////////////////////////////
254 zero_channels(const string &components) {
255  if (_xform == (EggXfmSAnim *)NULL) {
256  return;
257  }
258 
259  // This is particularly easy: we only have to remove children from
260  // the _xform object whose name is listed in the components.
261  string::const_iterator si;
262  for (si = components.begin(); si != components.end(); ++si) {
263  string table_name(1, *si);
264  EggNode *child = _xform->find_child(table_name);
265  if (child != (EggNode *)NULL) {
266  _xform->remove_child(child);
267  }
268  }
269 }
270 
271 ////////////////////////////////////////////////////////////////////
272 // Function: EggMatrixTablePointer::quantize_channels
273 // Access: Public, Virtual
274 // Description: Rounds the named components of the transform to the
275 // nearest multiple of quantum.
276 ////////////////////////////////////////////////////////////////////
278 quantize_channels(const string &components, double quantum) {
279  if (_xform == (EggXfmSAnim *)NULL) {
280  return;
281  }
282 
283  // This is similar to the above: we quantize children of the _xform
284  // object whose name is listed in the components.
285  string::const_iterator si;
286  for (si = components.begin(); si != components.end(); ++si) {
287  string table_name(1, *si);
288  EggNode *child = _xform->find_child(table_name);
289  if (child != (EggNode *)NULL &&
290  child->is_of_type(EggSAnimData::get_class_type())) {
291  EggSAnimData *anim = DCAST(EggSAnimData, child);
292  anim->quantize(quantum);
293  }
294  }
295 }
296 
297 ////////////////////////////////////////////////////////////////////
298 // Function: EggMatrixTablePointer::make_new_joint
299 // Access: Public, Virtual
300 // Description: Creates a new child of the current joint in the
301 // egg data, and returns a pointer to it.
302 ////////////////////////////////////////////////////////////////////
304 make_new_joint(const string &name) {
305  EggTable *new_table = new EggTable(name);
306  _table->add_child(new_table);
307  CoordinateSystem cs = CS_default;
308  if (_xform != (EggXfmSAnim *)NULL) {
309  cs = _xform->get_coordinate_system();
310  }
311  EggXfmSAnim *new_xform = new EggXfmSAnim("xform", cs);
312  new_table->add_child(new_xform);
313  new_xform->add_data(LMatrix4d::ident_mat());
314 
315  return new EggMatrixTablePointer(new_table);
316 }
317 
318 ////////////////////////////////////////////////////////////////////
319 // Function: EggMatrixTablePointer::set_name
320 // Access: Public, Virtual
321 // Description: Applies the indicated name change to the egg file.
322 ////////////////////////////////////////////////////////////////////
324 set_name(const string &name) {
325  _table->set_name(name);
326 }
virtual LMatrix4d get_frame(int n) const
Returns the transform matrix corresponding to this joint position in the nth frame.
bool add_data(const LMatrix4d &mat)
Adds a new matrix to the table, by adding a new row to each of the subtables.
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
virtual void set_frame(int n, const LMatrix4d &mat)
Sets the transform matrix corresponding to this joint position in the nth frame.
void quantize(double quantum)
Rounds each element of the table to the nearest multiple of quantum.
Definition: eggAnimData.cxx:26
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
virtual void extend_to(int num_frames)
Extends the table to the indicated number of frames.
virtual void set_name(const string &name)
Applies the indicated name change to the egg file.
Corresponding to an <S$Anim> entry, this stores a single column of numbers, for instance for a morph ...
Definition: eggSAnimData.h:28
virtual void optimize()
Resets the table before writing to disk so that redundant rows (e.g.
virtual EggJointPointer * make_new_joint(const string &name)
Creates a new child of the current joint in the egg data, and returns a pointer to it...
This class is used during joint optimization or restructuring to store the table of interim joint com...
virtual bool do_rebuild(EggCharacterDb &db)
Rebuilds the entire table all at once, based on the frames added by repeated calls to add_rebuild_fra...
static const LMatrix4d & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:5168
virtual bool add_frame(const LMatrix4d &mat)
Appends a new frame onto the end of the data, if possible; returns true if not possible, or false otherwise (e.g.
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine <S$Anim> entries that...
Definition: eggXfmSAnim.h:33
This is a base class for EggJointNodePointer and EggMatrixTablePointer.
Corresponding to an <Xfm$Anim> entry, this stores a two-dimensional table with up to nine columns...
This corresponds to a.
Definition: eggTable.h:31
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
This stores a pointer back to an EggXfmSAnim table (i.e.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
virtual int get_num_frames() const
Returns the number of frames of animation for this particular joint.
virtual void quantize_channels(const string &components, double quantum)
Rounds the named components of the transform to the nearest multiple of quantum.
virtual void do_finish_reparent(EggJointPointer *new_parent)
Performs the actual reparenting operation by removing the node from its old parent and associating it...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
virtual double get_frame_rate() const
Returns the stated frame rate of this particular joint, or 0.0 if it doesn&#39;t state.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
virtual void zero_channels(const string &components)
Zeroes out the named components of the transform in the animation frames.
The highest-level base class in the egg directory.
Definition: eggObject.h:31
bool get_matrix(const EggJointPointer *joint, TableType type, int frame, LMatrix4d &mat) const
Looks up the data for the indicated joint, type, and frame, and fills it in result (and returns true)...