Panda3D
 All Classes Functions Variables Enumerations
rigidBodyCombiner.cxx
1 // Filename: rigidBodyCombiner.cxx
2 // Created by: drose (22Feb07)
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 "rigidBodyCombiner.h"
16 #include "nodePath.h"
17 #include "geomNode.h"
18 #include "modelNode.h"
19 #include "geomVertexData.h"
20 #include "geomVertexFormat.h"
21 #include "geomVertexArrayFormat.h"
22 #include "geomVertexAnimationSpec.h"
23 #include "sceneGraphReducer.h"
24 #include "omniBoundingVolume.h"
25 #include "cullTraverserData.h"
26 
27 TypeHandle RigidBodyCombiner::_type_handle;
28 
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: RigidBodyCombiner::Constructor
32 // Access: Published
33 // Description:
34 ////////////////////////////////////////////////////////////////////
35 RigidBodyCombiner::
36 RigidBodyCombiner(const string &name) : PandaNode(name) {
37  set_cull_callback();
38 
39  _internal_root = new PandaNode(name);
40 
41  // We don't want to perform any additional culling once we get
42  // within the RigidBodyCombiner. The internal Geom's bounding
43  // volume is not updated and might not be accurate. However, the
44  // bounding volume of the RigidBodyCombiner itself should be
45  // accurate, and this is sufficient.
46  _internal_root->set_bounds(new OmniBoundingVolume);
47  _internal_root->set_final(true);
48 }
49 
50 ////////////////////////////////////////////////////////////////////
51 // Function: RigidBodyCombiner::Copy Constructor
52 // Access: Published
53 // Description:
54 ////////////////////////////////////////////////////////////////////
55 RigidBodyCombiner::
56 RigidBodyCombiner(const RigidBodyCombiner &copy) : PandaNode(copy) {
57  set_cull_callback();
58 
59  _internal_root = copy._internal_root;
60  _internal_transforms = copy._internal_transforms;
61 }
62 
63 ////////////////////////////////////////////////////////////////////
64 // Function: RigidBodyCombiner::make_copy
65 // Access: Public, Virtual
66 // Description: Returns a newly-allocated PandaNode that is a shallow
67 // copy of this one. It will be a different pointer,
68 // but its internal data may or may not be shared with
69 // that of the original PandaNode. No children will be
70 // copied.
71 ////////////////////////////////////////////////////////////////////
72 PandaNode *RigidBodyCombiner::
73 make_copy() const {
74  return new RigidBodyCombiner(*this);
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: RigidBodyCombiner::collect
79 // Access: Published
80 // Description: Walks through the entire subgraph of nodes rooted at
81 // this node, accumulates all of the RenderAttribs and
82 // Geoms below this node, flattening them into just one
83 // Geom (or as few as possible, if there are multiple
84 // different states).
85 //
86 // Nodes that have transforms on them at the time of
87 // collect(), or any ModelNodes with the
88 // preserve_transform flag, will be identified as
89 // "moving" nodes, and their transforms will be
90 // monitored as they change in future frames and each
91 // new transform directly applied to the vertices.
92 //
93 // This call must be made after adding any nodes to or
94 // removing any nodes from the subgraph rooted at this
95 // node. It should not be made too often, as it is a
96 // relatively expensive call. If you need to hide
97 // children of this node, consider scaling them to zero
98 // (or very near zero), or moving them behind the
99 // camera, instead.
100 ////////////////////////////////////////////////////////////////////
103  _internal_root = new GeomNode(get_name());
104  _internal_transforms.clear();
105  _vd_table.clear();
106 
107  Children cr = get_children();
108  int num_children = cr.get_num_children();
109  for (int i = 0; i < num_children; i++) {
110  r_collect(cr.get_child(i), RenderState::make_empty(), NULL);
111  }
112 
113  _vd_table.clear();
114 
116  gr.apply_attribs(_internal_root);
117  gr.collect_vertex_data(_internal_root, ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type));
118  gr.unify(_internal_root, false);
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: RigidBodyCombiner::get_internal_scene
123 // Access: Published
124 // Description: Returns a special NodePath that represents the
125 // internal node of this object. This is the node that
126 // is actually sent to the graphics card for rendering;
127 // it contains the collection of the children of this
128 // node into as few Geoms as possible.
129 //
130 // This node is filled up by the last call to collect().
131 ////////////////////////////////////////////////////////////////////
134  return NodePath(_internal_root);
135 }
136 
137 ////////////////////////////////////////////////////////////////////
138 // Function: RigidBodyCombiner::cull_callback
139 // Access: Protected, Virtual
140 // Description: This function will be called during the cull
141 // traversal to perform any additional operations that
142 // should be performed at cull time. This may include
143 // additional manipulation of render state or additional
144 // visible/invisible decisions, or any other arbitrary
145 // operation.
146 //
147 // Note that this function will *not* be called unless
148 // set_cull_callback() is called in the constructor of
149 // the derived class. It is necessary to call
150 // set_cull_callback() to indicated that we require
151 // cull_callback() to be called.
152 //
153 // By the time this function is called, the node has
154 // already passed the bounding-volume test for the
155 // viewing frustum, and the node's transform and state
156 // have already been applied to the indicated
157 // CullTraverserData object.
158 //
159 // The return value is true if this node should be
160 // visible, or false if it should be culled.
161 ////////////////////////////////////////////////////////////////////
164  // Pretend that all of our transforms have been modified (since we
165  // don't really know which ones have).
166  Thread *current_thread = Thread::get_current_thread();
167  Transforms::iterator ti;
168  for (ti = _internal_transforms.begin();
169  ti != _internal_transforms.end();
170  ++ti) {
171  (*ti)->mark_modified(current_thread);
172  }
173 
174  // Render the internal scene only--this is the optimized scene.
175  CullTraverserData next_data(data, _internal_root);
176  trav->traverse(next_data);
177 
178  // Do not directly render the nodes beneath this node.
179  return false;
180 }
181 
182 ////////////////////////////////////////////////////////////////////
183 // Function: RigidBodyCombiner::r_collect
184 // Access: Private
185 // Description: Recursively visits each child or descedant of this
186 // node, accumulating state and transform as we go.
187 // When GeomNodes are encountered, their Geoms are
188 // extracted and added to the _internal_root node.
189 ////////////////////////////////////////////////////////////////////
190 void RigidBodyCombiner::
191 r_collect(PandaNode *node, const RenderState *state,
192  const VertexTransform *transform) {
193  CPT(RenderState) next_state = state->compose(node->get_state());
194  CPT(VertexTransform) next_transform = transform;
195  if (!node->get_transform()->is_identity() ||
196  (node->is_of_type(ModelNode::get_class_type()) &&
197  DCAST(ModelNode, node)->get_preserve_transform() != ModelNode::PT_none)) {
198  // This node has a transform we need to keep.
199  PT(NodeVertexTransform) new_transform = new NodeVertexTransform(node, transform);
200  _internal_transforms.push_back(new_transform);
201  next_transform = new_transform.p();
202 
203  }
204 
205  if (node->is_geom_node()) {
206  GeomNode *gnode = DCAST(GeomNode, node);
207  GeomNode *root_gnode = DCAST(GeomNode, _internal_root);
208 
209  int num_geoms = gnode->get_num_geoms();
210  for (int i = 0; i < num_geoms; ++i) {
211  PT(Geom) geom = gnode->get_geom(i)->make_copy();
212  if (next_transform != (const VertexTransform *)NULL) {
213  geom->set_vertex_data(convert_vd(next_transform, geom->get_vertex_data()));
214  }
215  CPT(RenderState) gstate = next_state->compose(gnode->get_geom_state(i));
216  root_gnode->add_geom(geom, gstate);
217  }
218  }
219 
220  Children cr = node->get_children();
221  int num_children = cr.get_num_children();
222  for (int i = 0; i < num_children; i++) {
223  r_collect(cr.get_child(i), next_state, next_transform);
224  }
225 }
226 
227 ////////////////////////////////////////////////////////////////////
228 // Function: RigidBodyCombiner::convert_vd
229 // Access: Private
230 // Description: Converts a GeomVertexData to a new form in which all
231 // of the vertices are transformed by the node's
232 // transform.
233 ////////////////////////////////////////////////////////////////////
235 convert_vd(const VertexTransform *transform, const GeomVertexData *orig) {
236  // First, unify this operation for unique transform/data
237  // combinations. If we encounter a given GeomVertexData more than
238  // once under the same transform, we should return exactly the same
239  // GeomVertexData.
240  VDTable::iterator vdti = _vd_table.find(VDUnifier(transform, orig));
241  if (vdti != _vd_table.end()) {
242  return (*vdti).second;
243  }
244 
245  PT(GeomVertexFormat) format = new GeomVertexFormat(*orig->get_format());
246  if (!orig->get_format()->has_column(InternalName::get_transform_blend())) {
247  PT(GeomVertexArrayFormat) af =
248  new GeomVertexArrayFormat(InternalName::get_transform_blend(), 1,
249  Geom::NT_uint16, Geom::C_index);
250  format->add_array(af);
251  }
252 
254  spec.set_panda();
255  format->set_animation(spec);
256  format->maybe_align_columns_for_animation();
257 
258  CPT(GeomVertexFormat) new_format = GeomVertexFormat::register_format(format);
259  CPT(GeomVertexData) converted = orig->convert_to(new_format);
260  PT(GeomVertexData) new_data = new GeomVertexData(*converted);
261 
262  if (new_data->get_transform_blend_table() == (TransformBlendTable *)NULL) {
263  // Create a new table that has just the one blend: all vertices
264  // hard-assigned to the indicated transform.
265  PT(TransformBlendTable) new_table = new TransformBlendTable;
266  new_table->add_blend(TransformBlend(transform, 1.0f));
267  new_table->set_rows(SparseArray::range(0, new_data->get_num_rows()));
268  new_data->set_transform_blend_table(new_table);
269  } else {
270  // The GeomVertexData already has a TransformBlendTable. In this
271  // case, we'll have to adjust it. TODO.
272  }
273 
274  // Store the result for the next time.
275  _vd_table[VDUnifier(transform, orig)] = new_data;
276 
277  return new_data;
278 }
This class records a set of integers, where each integer is either present or not present in the set...
Definition: sparseArray.h:49
void collect()
Walks through the entire subgraph of nodes rooted at this node, accumulates all of the RenderAttribs ...
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
int collect_vertex_data(PandaNode *root, int collect_bits=~0)
Collects all different GeomVertexData blocks that have compatible formats at this node and below into...
NodePath get_internal_scene()
Returns a special NodePath that represents the internal node of this object.
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded...
PandaNode * get_child(int n) const
Returns the nth child of the node.
Definition: pandaNode.I:1174
This is a special node that combines multiple independently-moving rigid nodes into one Geom internal...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
An interface for simplifying (&quot;flattening&quot;) scene graphs by eliminating unneeded nodes and collapsing...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
This node is placed at key points within the scene graph to indicate the roots of &quot;models&quot;: subtrees ...
Definition: modelNode.h:34
This is an abstract base class that holds a pointer to some transform, computed in some arbitrary way...
int get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:1163
void unify(PandaNode *root, bool preserve_order)
Calls unify() on every GeomNode at this level and below.
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
Definition: pandaNode.I:68
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:58
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.I:773
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
This defines a single entry in a TransformBlendTable.
void apply_attribs(PandaNode *node, int attrib_types=~(TT_clip_plane|TT_cull_face|TT_apply_texture_color))
Walks the scene graph, accumulating attribs of the indicated types, applying them to the vertices...
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
Definition: pandaNode.I:82
A thread; that is, a lightweight process.
Definition: thread.h:51
This is a special kind of GeometricBoundingVolume that fills all of space.
This structure collects together the different combinations of transforms and blend amounts used by a...
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2486
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This VertexTransform gets its matrix from the Transform stored on a node.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:37
int get_num_geoms() const
Returns the number of geoms in the node.
Definition: geomNode.I:46