Panda3D
 All Classes Functions Variables Enumerations
eggXfmAnimData.cxx
1 // Filename: eggXfmAnimData.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 "eggXfmAnimData.h"
16 #include "eggXfmSAnim.h"
17 #include "eggSAnimData.h"
18 #include "eggMiscFuncs.h"
19 #include "config_egg.h"
20 
21 #include "indent.h"
22 #include "luse.h"
23 #include "lmatrix.h"
24 #include "compose_matrix.h"
25 #include "dcast.h"
26 
27 TypeHandle EggXfmAnimData::_type_handle;
28 
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: EggXfmAnimData::Conversion constructor
32 // Access: Public
33 // Description: Converts the newer-style XfmSAnim table to the
34 // older-style XfmAnim table.
35 ////////////////////////////////////////////////////////////////////
36 EggXfmAnimData::
37 EggXfmAnimData(const EggXfmSAnim &convert_from)
38  : EggAnimData(convert_from.get_name())
39 {
40  if (convert_from.has_order()) {
41  set_order(convert_from.get_order());
42  }
43  if (convert_from.has_fps()) {
44  set_fps(convert_from.get_fps());
45  }
46  _coordsys = convert_from.get_coordinate_system();
47 
48  // First, get the table names so we know how to build up our
49  // contents string. Also store up the SAnim tables themselves in a
50  // temporary vector for convenience.
51 
52  pvector<EggSAnimData *> subtables;
53 
54  EggXfmSAnim::const_iterator ci;
55  for (ci = convert_from.begin(); ci != convert_from.end(); ++ci) {
56  if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
57  EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
58  nassertv(sanim->get_name().length() == 1);
59 
60  if (sanim->get_num_rows() > 0) {
61  subtables.push_back(sanim);
62  _contents += sanim->get_name()[0];
63  }
64  }
65  }
66 
67  // Now, go through and extract out all the data.
68  int num_rows = convert_from.get_num_rows();
69  for (int row = 0; row < num_rows; row++) {
70  for (int col = 0; col < (int)subtables.size(); col++) {
71  EggSAnimData *sanim = subtables[col];
72  if (sanim->get_num_rows() == 1) {
73  add_data(sanim->get_value(0));
74  } else {
75  nassertv(row < sanim->get_num_rows());
76  add_data(sanim->get_value(row));
77  }
78  }
79  }
80 }
81 
82 
83 ////////////////////////////////////////////////////////////////////
84 // Function: EggXfmAnimData::get_value
85 // Access: Public
86 // Description: Returns the value of the aggregate row of the table
87 // as a matrix. This is a convenience function that
88 // treats the 2-d table as if it were a single table of
89 // matrices.
90 ////////////////////////////////////////////////////////////////////
92 get_value(int row, LMatrix4d &mat) const {
93  LVector3d scale(1.0, 1.0, 1.0);
94  LVector3d shear(0.0, 0.0, 0.0);
95  LVector3d hpr(0.0, 0.0, 0.0);
96  LVector3d translate(0.0, 0.0, 0.0);
97 
98  for (int col = 0; col < get_num_cols(); col++) {
99  double value = get_value(row, col);
100 
101  switch (_contents[col]) {
102  case 'i':
103  scale[0] = value;
104  break;
105 
106  case 'j':
107  scale[1] = value;
108  break;
109 
110  case 'k':
111  scale[2] = value;
112  break;
113 
114  case 'a':
115  shear[0] = value;
116  break;
117 
118  case 'b':
119  shear[1] = value;
120  break;
121 
122  case 'c':
123  shear[2] = value;
124  break;
125 
126  case 'h':
127  hpr[0] = value;
128  break;
129 
130  case 'p':
131  hpr[1] = value;
132  break;
133 
134  case 'r':
135  hpr[2] = value;
136  break;
137 
138  case 'x':
139  translate[0] = value;
140  break;
141 
142  case 'y':
143  translate[1] = value;
144  break;
145 
146  case 'z':
147  translate[2] = value;
148  break;
149 
150  default:
151  // The contents string contained an invalid letter.
152  nassertv(false);
153  }
154  }
155 
156  // So now we've got the twelve components; build a matrix.
157  EggXfmSAnim::compose_with_order(mat, scale, shear, hpr, translate, get_order(),
158  _coordsys);
159 }
160 
161 ////////////////////////////////////////////////////////////////////
162 // Function: EggXfmAnimData::is_anim_matrix
163 // Access: Public, Virtual
164 // Description: Returns true if this node represents a table of
165 // animation transformation data, false otherwise.
166 ////////////////////////////////////////////////////////////////////
167 bool EggXfmAnimData::
168 is_anim_matrix() const {
169  return true;
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: EggXfmAnimData::write
174 // Access: Public, Virtual
175 // Description: Writes the data to the indicated output stream in Egg
176 // format.
177 ////////////////////////////////////////////////////////////////////
178 void EggXfmAnimData::
179 write(ostream &out, int indent_level) const {
180  write_header(out, indent_level, "<Xfm$Anim>");
181 
182  if (has_fps()) {
183  indent(out, indent_level + 2)
184  << "<Scalar> fps { " << get_fps() << " }\n";
185  }
186 
187  if (has_order()) {
188  indent(out, indent_level + 2)
189  << "<Char*> order { " << get_order() << " }\n";
190  }
191 
192  if (has_contents()) {
193  indent(out, indent_level + 2)
194  << "<Char*> contents { " << get_contents() << " }\n";
195  }
196 
197  indent(out, indent_level + 2) << "<V> {\n";
198  write_long_list(out, indent_level + 4, _data.begin(), _data.end(),
199  "", "", 72);
200  indent(out, indent_level + 2) << "}\n";
201  indent(out, indent_level) << "}\n";
202 }
203 
204 ////////////////////////////////////////////////////////////////////
205 // Function: EggXfmAnimData::r_transform
206 // Access: Protected, Virtual
207 // Description: Applies the indicated transform to all the rows of
208 // the table. This actually forces the generation of a
209 // totally new set of rows.
210 ////////////////////////////////////////////////////////////////////
211 void EggXfmAnimData::
212 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
213  CoordinateSystem to_cs) {
214  // We need to build an inverse matrix that doesn't reflect the
215  // translation component.
216  LMatrix4d inv1 = inv;
217  inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
218 
219  // Now we build a temporary copy of the table as an EggXfmSAnim. We
220  // do this because this kind of table is easier to build and
221  // optimize.
222 
223  if (to_cs == CS_default) {
224  to_cs = _coordsys;
225  }
226 
227  EggXfmSAnim new_table(get_name(), to_cs);
228  if (has_fps()) {
229  new_table.set_fps(get_fps());
230  }
231 
232  // We insist on the standard order now.
233  new_table.set_order(get_standard_order());
234 
235  // Now build up the data into the new table.
236  LMatrix4d orig_mat;
237  for (int r = 0; r < get_num_rows(); r++) {
238  get_value(r, orig_mat);
239  bool result = new_table.add_data(inv1 * orig_mat * mat);
240 
241  if (!result) {
242  egg_cat.error()
243  << "Transform from " << _coordsys << " to " << to_cs
244  << " failed!\n";
245  LVector3d scale, shear, hpr, trans;
246  bool d = decompose_matrix(orig_mat, scale, shear, hpr, trans, _coordsys);
247  egg_cat.error(false)
248  << "orig:\n" << orig_mat
249  << "d = " << d
250  << "\n scale: " << scale
251  << "\n shear: " << shear
252  << "\n hpr: " << hpr
253  << "\n trans: " << trans << "\n";
254 
255  LMatrix4d new_mat = inv1 * orig_mat * mat;
256  d = decompose_matrix(new_mat, scale, shear, hpr, trans, to_cs);
257  egg_cat.error(false)
258  << "new:\n" << new_mat
259  << "d = " << d
260  << "\n scale: " << scale
261  << "\n shear: " << shear
262  << "\n hpr: " << hpr
263  << "\n trans: " << trans << "\n";
264  }
265 
266  // If this assertion fails, we attempted to transform by non-affine
267  // matrix or some such thing that cannot be represented in an anim
268  // file.
269  nassertv(result);
270  }
271 
272  // Now clean out the redundant columns we created.
273  new_table.optimize();
274 
275  // And copy that back into EggXfmAnimData table form.
276  EggXfmAnimData copy_table(new_table);
277  (*this) = copy_table;
278 }
279 
280 ////////////////////////////////////////////////////////////////////
281 // Function: EggXfmAnimData::r_mark_coordsys
282 // Access: Protected, Virtual
283 // Description: This is only called immediately after loading an egg
284 // file from disk, to propagate the value found in the
285 // CoordinateSystem entry (or the default Y-up
286 // coordinate system) to all nodes that care about what
287 // the coordinate system is.
288 ////////////////////////////////////////////////////////////////////
289 void EggXfmAnimData::
290 r_mark_coordsys(CoordinateSystem cs) {
291  _coordsys = cs;
292 }
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
void add_data(double value)
Adds a single element to the table.
Definition: eggAnimData.I:116
void write_header(ostream &out, int indent_level, const char *egg_keyword) const
Writes the first line of the egg object, e.g.
int get_num_cols() const
Returns the number of columns in the table.
double get_value(int row, int col) const
Returns the value at the indicated row.
Corresponding to an &lt;S$Anim&gt; entry, this stores a single column of numbers, for instance for a morph ...
Definition: eggSAnimData.h:28
double get_fps() const
This is only valid if has_fps() returns true.
Definition: eggAnimData.I:94
void set_row(int row, const LVecBase4d &v)
Replaces the indicated row of the matrix.
Definition: lmatrix.h:5452
int get_num_rows() const
Returns the effective number of rows in the table.
CoordinateSystem get_coordinate_system() const
Returns the coordinate system this table believes it is defined within.
Definition: eggXfmSAnim.I:175
This corresponds to an &lt;Xfm$Anim_S$&gt; entry, which is a collection of up to nine &lt;S$Anim&gt; entries that...
Definition: eggXfmSAnim.h:33
A base class for EggSAnimData and EggXfmAnimData, which contain rows and columns of numbers...
Definition: eggAnimData.h:32
Corresponding to an &lt;Xfm$Anim&gt; entry, this stores a two-dimensional table with up to nine columns...
int get_num_rows() const
Returns the number of rows in the table.
Definition: eggSAnimData.I:56
static void compose_with_order(LMatrix4d &mat, const LVecBase3d &scale, const LVecBase3d &shear, const LVecBase3d &hpr, const LVecBase3d &trans, const string &order, CoordinateSystem cs)
Composes a matrix out of the nine individual components, respecting the order string.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:746
static const string & get_standard_order()
Returns the standard order of matrix component composition.
virtual bool is_anim_matrix() const
Returns true if this node represents a table of animation transformation data, false otherwise...
double get_fps() const
This is only valid if has_fps() returns true.
Definition: eggXfmSAnim.I:98
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
virtual void write(ostream &out, int indent_level) const
Writes the data to the indicated output stream in Egg format.
int get_num_rows() const
Returns the number of rows in the table.
double get_value(int row) const
Returns the value at the indicated row.
Definition: eggSAnimData.I:68