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