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