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