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  */
159 bool EggXfmAnimData::
160 is_anim_matrix() const {
161  return true;
162 }
163 
164 /**
165  * Writes the data to the indicated output stream in Egg format.
166  */
167 void EggXfmAnimData::
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 }
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.
int get_num_cols() const
Returns the number of columns in the table.
int get_num_rows() const
Returns the number of rows in the table.
void write_header(std::ostream &out, int indent_level, const char *egg_keyword) const
Writes the first line of the egg object, e.g.
void add_data(double value)
Adds a single element to the table.
Definition: eggAnimData.I:97
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Corresponding to an <S$Anim> entry, this stores a single column of numbers, for instance for a morph ...
Definition: eggSAnimData.h:25
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double get_value(int row) const
Returns the value at the indicated row.
Definition: eggSAnimData.I:56
virtual void write(std::ostream &out, int indent_level) const
Writes the data to the indicated output stream in Egg format.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static const std::string & get_standard_order()
Returns the standard order of matrix component composition.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
double get_value(int row, int col) const
Returns the value at the indicated row.
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine <S$Anim> entries that...
Definition: eggXfmSAnim.h:28
double get_fps() const
This is only valid if has_fps() returns true.
Definition: eggAnimData.I:79
A base class for EggSAnimData and EggXfmAnimData, which contain rows and columns of numbers.
Definition: eggAnimData.h:30
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
Corresponding to an <Xfm$Anim> entry, this stores a two-dimensional table with up to nine columns,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CoordinateSystem get_coordinate_system() const
Returns the coordinate system this table believes it is defined within.
Definition: eggXfmSAnim.I:140
int get_num_rows() const
Returns the effective number of rows in the table.
double get_fps() const
This is only valid if has_fps() returns true.
Definition: eggXfmSAnim.I:82
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool is_anim_matrix() const
Returns true if this node represents a table of animation transformation data, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_num_rows() const
Returns the number of rows in the table.
Definition: eggSAnimData.I:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.