Panda3D
 All Classes Functions Variables Enumerations
fltToEggLevelState.cxx
1 // Filename: fltToEggLevelState.cxx
2 // Created by: drose (18Apr01)
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 "fltToEggLevelState.h"
16 #include "fltToEggConverter.h"
17 #include "fltTransformTranslate.h"
18 #include "fltTransformRotateAboutPoint.h"
19 #include "fltTransformRotateAboutEdge.h"
20 #include "fltTransformScale.h"
21 #include "fltTransformPut.h"
22 #include "eggGroup.h"
23 #include "dcast.h"
24 #include "look_at.h"
25 
26 
27 ////////////////////////////////////////////////////////////////////
28 // Function: FltToEggLevelState::Destructor
29 // Access: Public
30 // Description:
31 ////////////////////////////////////////////////////////////////////
32 FltToEggLevelState::
33 ~FltToEggLevelState() {
34  Parents::iterator pi;
35  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
36  delete (*pi).second;
37  }
38 }
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: FltToEggLevelState::ParentNodes::Constructor
42 // Access: Public
43 // Description:
44 ////////////////////////////////////////////////////////////////////
45 FltToEggLevelState::ParentNodes::
46 ParentNodes() {
47  _axial_billboard = (EggGroup *)NULL;
48  _point_billboard = (EggGroup *)NULL;
49  _plain = (EggGroup *)NULL;
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: FltToEggLevelState::get_synthetic_group
54 // Access: Public
55 // Description: Sometimes it is necessary to synthesize a group
56 // within a particular EggGroup, for instance to insert
57 // a transform or billboard flag. This function will
58 // synthesize a group as needed, or return an existing
59 // group (if the group need not be synthesized, or if a
60 // matching group was previously synthesized).
61 //
62 // This collects together polygons that share the same
63 // billboard axis and/or transform space into the same
64 // group, rather than wastefully creating a group per
65 // polygon.
66 ////////////////////////////////////////////////////////////////////
68 get_synthetic_group(const string &name,
69  const FltBead *transform_bead,
70  FltGeometry::BillboardType type) {
71  LMatrix4d transform = transform_bead->get_transform();
72  bool is_identity = transform.almost_equal(LMatrix4d::ident_mat());
73  if (is_identity &&
74  (type != FltGeometry::BT_axial &&
75  type != FltGeometry::BT_point)) {
76  // Trivial case: the primitive belongs directly in its parent
77  // group node.
78  return _egg_parent;
79  }
80 
81  // For other cases, we may have to create a subgroup to put the
82  // primitive into.
83  Parents::iterator pi;
84  pi = _parents.find(transform);
85  ParentNodes *nodes;
86  if (pi != _parents.end()) {
87  nodes = (*pi).second;
88  } else {
89  nodes = new ParentNodes;
90  _parents.insert(Parents::value_type(transform, nodes));
91  }
92 
93  switch (type) {
94  case FltGeometry::BT_axial:
95  if (nodes->_axial_billboard == (EggGroupNode *)NULL) {
96  nodes->_axial_billboard = new EggGroup(name);
97  _egg_parent->add_child(nodes->_axial_billboard);
98  nodes->_axial_billboard->set_billboard_type(EggGroup::BT_axis);
99  if (!is_identity) {
100  set_transform(transform_bead, nodes->_axial_billboard);
101  nodes->_axial_billboard->set_group_type(EggGroup::GT_instance);
102  }
103  }
104  return nodes->_axial_billboard;
105 
106  case FltGeometry::BT_point:
107  if (nodes->_point_billboard == (EggGroupNode *)NULL) {
108  nodes->_point_billboard = new EggGroup(name);
109  _egg_parent->add_child(nodes->_point_billboard);
110  nodes->_point_billboard->set_billboard_type(EggGroup::BT_point_world_relative);
111  if (!is_identity) {
112  set_transform(transform_bead, nodes->_point_billboard);
113  nodes->_point_billboard->set_group_type(EggGroup::GT_instance);
114  }
115  }
116  return nodes->_point_billboard;
117 
118  default: // Normally, BT_none, although we've occasionally seen a
119  // value of 3 come in here, whatever that's supposed to mean.
120  if (nodes->_plain == (EggGroupNode *)NULL) {
121  nodes->_plain = new EggGroup(name);
122  _egg_parent->add_child(nodes->_plain);
123  if (!is_identity) {
124  set_transform(transform_bead, nodes->_plain);
125  nodes->_plain->set_group_type(EggGroup::GT_instance);
126  }
127  }
128  return nodes->_plain;
129  }
130 }
131 
132 ////////////////////////////////////////////////////////////////////
133 // Function: FltToEggLevelState::set_transform
134 // Access: Public
135 // Description: Sets up the group to reflect the transform indicated
136 // by the given record, if any.
137 ////////////////////////////////////////////////////////////////////
139 set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
140  if (flt_bead->has_transform()) {
141  egg_group->set_group_type(EggGroup::GT_instance);
142 
143  int num_steps = flt_bead->get_num_transform_steps();
144  bool componentwise_ok = !_converter->_compose_transforms;
145 
146  if (num_steps == 0) {
147  componentwise_ok = false;
148  } else {
149  // Walk through each transform step and store the individual
150  // components in the egg file. If we come across a step we
151  // don't know how to interpret, just store the whole transform
152  // matrix in the egg file.
153  egg_group->clear_transform();
154  for (int i = num_steps -1; i >= 0 && componentwise_ok; i--) {
155  const FltTransformRecord *step = flt_bead->get_transform_step(i);
156  if (step->is_exact_type(FltTransformTranslate::get_class_type())) {
157  const FltTransformTranslate *trans;
158  DCAST_INTO_V(trans, step);
159  if (!trans->get_delta().almost_equal(LVector3d::zero())) {
160  egg_group->add_translate3d(trans->get_delta());
161  }
162 
163  } else if (step->is_exact_type(FltTransformRotateAboutPoint::get_class_type())) {
164  const FltTransformRotateAboutPoint *rap;
165  DCAST_INTO_V(rap, step);
166  if (!IS_NEARLY_ZERO(rap->get_angle())) {
167  if (!rap->get_center().almost_equal(LVector3d::zero())) {
168  egg_group->add_translate3d(-rap->get_center());
169  }
170  LVector3d axis = LCAST(double, rap->get_axis());
171  egg_group->add_rotate3d(rap->get_angle(), axis);
172  if (!rap->get_center().almost_equal(LVector3d::zero())) {
173  egg_group->add_translate3d(rap->get_center());
174  }
175  }
176 
177  } else if (step->is_exact_type(FltTransformRotateAboutEdge::get_class_type())) {
178  const FltTransformRotateAboutEdge *rae;
179  DCAST_INTO_V(rae, step);
180  if (!IS_NEARLY_ZERO(rae->get_angle())) {
181  if (!rae->get_point_a().almost_equal(LVector3d::zero())) {
182  egg_group->add_translate3d(-rae->get_point_a());
183  }
184  LVector3d axis = rae->get_point_b() - rae->get_point_a();
185  egg_group->add_rotate3d(rae->get_angle(), axis);
186  if (!rae->get_point_a().almost_equal(LVector3d::zero())) {
187  egg_group->add_translate3d(rae->get_point_a());
188  }
189  }
190 
191  } else if (step->is_exact_type(FltTransformScale::get_class_type())) {
192  const FltTransformScale *scale;
193  DCAST_INTO_V(scale, step);
194  if (!scale->get_scale().almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) {
195  if (scale->has_center() &&
196  !scale->get_center().almost_equal(LVector3d::zero())) {
197  egg_group->add_translate3d(-scale->get_center());
198  }
199  egg_group->add_scale3d(LCAST(double, scale->get_scale()));
200  if (scale->has_center() &&
201  !scale->get_center().almost_equal(LVector3d::zero())) {
202  egg_group->add_translate3d(scale->get_center());
203  }
204  }
205 
206  } else if (step->is_exact_type(FltTransformPut::get_class_type())) {
207  const FltTransformPut *put;
208  DCAST_INTO_V(put, step);
209 
210  if (!put->get_from_origin().almost_equal(LVector3d::zero())) {
211  egg_group->add_translate3d(-put->get_from_origin());
212  }
213  LQuaterniond q1, q2;
214  look_at(q1, put->get_from_align() - put->get_from_origin(),
215  put->get_from_track() - put->get_from_origin(),
216  CS_zup_right);
217  look_at(q2, put->get_to_align() - put->get_to_origin(),
218  put->get_to_track() - put->get_to_origin(),
219  CS_zup_right);
220 
221  LQuaterniond q = invert(q1) * q2;
222 
223  if (!q.is_identity()) {
224  egg_group->add_rotate3d(q);
225  }
226  if (!put->get_to_origin().almost_equal(LVector3d::zero())) {
227  egg_group->add_translate3d(put->get_to_origin());
228  }
229 
230  } else {
231  // Here's a transform component we haven't implemented here.
232  // Give up on storing the componentwise transform.
233  componentwise_ok = false;
234  }
235  }
236  }
237 
238  if (!componentwise_ok) {
239  egg_group->set_transform3d(flt_bead->get_transform());
240  }
241  }
242 }
A transformation that applies a (possibly nonuniform) scale.
void clear_transform()
Resets the transform to empty, identity.
Definition: eggTransform.I:125
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
A "put", which is a MultiGen concept of defining a transformation by mapping three arbitrary points t...
void add_rotate3d(double angle, const LVector3d &axis)
Appends a 3-d rotation about an arbitrary axis to the current transform.
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
PN_stdfloat get_angle() const
Returns the angle of rotation, in degrees counterclockwise about the axis as seen from point a...
bool has_center() const
Returns true if the center is specified, false if it is not.
FltTransformRecord * get_transform_step(int n)
Returns the nth individual step that defines the net transform on this bead.
Definition: fltBead.cxx:122
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
PN_stdfloat get_angle() const
Returns the angle of rotation, in degrees counterclockwise about the axis.
This is the base quaternion class.
Definition: lquaternion.h:974
const LMatrix4d & get_transform() const
Returns the single-precision 4x4 matrix that represents the transform applied to this bead...
Definition: fltBead.cxx:66
A transformation that applies a translation.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:74
A base class for any of a broad family of flt records that represent particular beads in the hierarch...
Definition: fltBead.h:33
bool almost_equal(const LVecBase3d &other, double threshold) const
Returns true if two vectors are memberwise equal within a specified tolerance.
Definition: lvecBase3.h:2614
int get_num_transform_steps() const
Returns the number of individual steps that define the net transform on this bead as returned by set_...
Definition: fltBead.cxx:110
static const LVector3d & zero()
Returns a zero-length vector.
Definition: lvector3.h:915
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:36
bool almost_equal(const LMatrix4d &other, double threshold) const
Returns true if two matrices are memberwise equal within a specified tolerance.
Definition: lmatrix.cxx:2058
void set_transform3d(const LMatrix4d &mat)
Sets the overall transform as a 4x4 matrix.
Definition: eggTransform.I:222
bool has_transform() const
Returns true if the bead has been transformed, false otherwise.
Definition: fltBead.cxx:54
static const LMatrix4d & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:5168
void add_translate3d(const LVector3d &translate)
Appends a 3-d translation operation to the current transform.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:746
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
bool almost_equal(const LVecBase3f &other, float threshold) const
Returns true if two vectors are memberwise equal within a specified tolerance.
Definition: lvecBase3.h:1264
A base class for a number of types of ancillary records that follow beads and indicate some kind of a...
void add_scale3d(const LVecBase3d &scale)
Appends a possibly non-uniform scale to the current transform.
EggGroupNode * get_synthetic_group(const string &name, const FltBead *transform_bead, FltGeometry::BillboardType type=FltGeometry::BT_none)
Sometimes it is necessary to synthesize a group within a particular EggGroup, for instance to insert ...
A transformation that rotates about a particular axis in space, defined by two endpoints.
void set_transform(const FltBead *flt_bead, EggGroup *egg_group)
Sets up the group to reflect the transform indicated by the given record, if any. ...
A transformation that rotates about a particular axis in space, defined by a point and vector...