Panda3D
bulletHelper.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 bulletHelper.cxx
10  * @author enn0x
11  * @date 2011-01-19
12  */
13 
14 #include "bulletHelper.h"
15 
16 #include "bulletRigidBodyNode.h"
17 #include "bulletSoftBodyNode.h"
18 #include "bulletGhostNode.h"
19 
20 #include "geomLines.h"
21 #include "geomTriangles.h"
22 #include "geomVertexRewriter.h"
23 
24 #include "bullet_utils.h"
25 
26 PT(InternalName) BulletHelper::_sb_index;
27 PT(InternalName) BulletHelper::_sb_flip;
28 
29 /**
30  *
31  */
32 NodePathCollection BulletHelper::
33 from_collision_solids(NodePath &np, bool clear) {
34 
35  NodePathCollection result;
36 
37  // Iterate over all CollisionNodes below the given node
38  NodePathCollection npc = np.find_all_matches( "**/+CollisionNode" );
39 
40  for (int i=0; i<npc.get_num_paths(); i++) {
41  NodePath cnp = npc.get_path(i);
42  CollisionNode *cnode = DCAST(CollisionNode, cnp.node());
43 
44  PT(PandaNode) bnode = nullptr;
45 
46  // Create a either a new rigid body or a new ghost for each CollisionNode,
47  // and add one shape per CollisionSolid contained in the CollisionNode
48  if (is_tangible(cnode)) {
49  PT(BulletRigidBodyNode) body;
50 
51  body = new BulletRigidBodyNode();
52  body->add_shapes_from_collision_solids(cnode);
53  body->set_transform(cnp.get_transform(np));
54  body->set_into_collide_mask(cnode->get_into_collide_mask());
55  body->set_mass(0.0f);
56  body->set_name(cnode->get_name());
57 
58  bnode = body;
59  }
60  else {
61  PT(BulletGhostNode) ghost;
62 
63  ghost = new BulletGhostNode();
64  ghost->add_shapes_from_collision_solids(cnode);
65  ghost->set_transform(cnp.get_transform(np));
66  ghost->set_into_collide_mask(cnode->get_into_collide_mask());
67  ghost->set_name(cnode->get_name());
68 
69  bnode = ghost;
70  }
71 
72  // Remove collision node if requested
73  if (clear) {
74  cnp.remove_node();
75  }
76 
77  result.add_path(NodePath::any_path(bnode));
78  }
79 
80  return result;
81 }
82 
83 /**
84  * Returns TRUE if at least one CollisionSolid of the given CollisionNode is
85  * tangible. Returns FALSE if all CollisionSolids are intangible.
86  */
87 bool BulletHelper::
88 is_tangible(CollisionNode *cnode) {
89 
90  for (size_t j = 0; j < cnode->get_num_solids(); ++j) {
91  CPT(CollisionSolid) solid = cnode->get_solid(j);
92  if (solid->is_tangible()) {
93  return true;
94  }
95  }
96 
97  return false;
98 }
99 
100 /**
101  *
102  */
103 CPT(GeomVertexFormat) BulletHelper::
104 add_sb_index_column(const GeomVertexFormat *format) {
105 
106  PT(InternalName) name = BulletHelper::get_sb_index();
107 
108  if (format->has_column(name)) return format;
109 
110  PT(GeomVertexArrayFormat) array;
111  PT(GeomVertexFormat) unregistered_format;
112  CPT(GeomVertexFormat) registered_format;
113 
114  array = new GeomVertexArrayFormat();
115  array->add_column(name, 1, Geom::NT_uint16, Geom::C_index);
116 
117  unregistered_format = new GeomVertexFormat(*format);
118  unregistered_format->add_array(array);
119 
120  registered_format = GeomVertexFormat::register_format(unregistered_format);
121 
122  return registered_format;
123 }
124 
125 /**
126  *
127  */
128 CPT(GeomVertexFormat) BulletHelper::
129 add_sb_flip_column(const GeomVertexFormat *format) {
130 
131  PT(InternalName) name = BulletHelper::get_sb_flip();
132 
133  if (format->has_column(name)) return format;
134 
135  PT(GeomVertexArrayFormat) array;
136  PT(GeomVertexFormat) unregistered_format;
137  CPT(GeomVertexFormat) registered_format;
138 
139  array = new GeomVertexArrayFormat();
140  array->add_column(name, 1, Geom::NT_uint8, Geom::C_other);
141 
142  unregistered_format = new GeomVertexFormat(*format);
143  unregistered_format->add_array(array);
144 
145  registered_format = GeomVertexFormat::register_format(unregistered_format);
146 
147  return registered_format;
148 }
149 
150 /**
151  *
152  */
153 PT(Geom) BulletHelper::
154 make_geom_from_faces(BulletSoftBodyNode *node, const GeomVertexFormat *format, bool two_sided) {
155 
156  return make_geom(node, format, two_sided, true);
157 }
158 
159 /**
160  *
161  */
162 PT(Geom) BulletHelper::
163 make_geom_from_links(BulletSoftBodyNode *node, const GeomVertexFormat *format) {
164 
165  return make_geom(node, format, false, false);
166 }
167 
168 /**
169  *
170  */
171 PT(Geom) BulletHelper::
172 make_geom(BulletSoftBodyNode *node, const GeomVertexFormat *format, bool two_sided, bool use_faces) {
173 
174  btTransform trans = btTransform::getIdentity();
175  get_node_transform(trans, node);
176 
177  btSoftBody *body = (btSoftBody *)node->get_object();
178 
179  PT(Geom) geom;
180  PT(GeomPrimitive) prim;
181  PT(GeomVertexData) vdata;
182 
183  CPT(GeomVertexFormat) fmt = (format) ? format : GeomVertexFormat::get_v3n3t2();
184  fmt = BulletHelper::add_sb_flip_column(fmt);
185 
186  nassertr(fmt->has_column(InternalName::get_vertex()), nullptr);
187  nassertr(fmt->has_column(InternalName::get_normal()), nullptr);
188 
189  btSoftBody::tNodeArray &nodes(body->m_nodes);
190 
191  // Vertex data
192  vdata = new GeomVertexData("", fmt, Geom::UH_stream);
193 
194  GeomVertexWriter vwriter(vdata, InternalName::get_vertex());
195  GeomVertexWriter nwriter(vdata, InternalName::get_normal());
196  GeomVertexWriter fwriter(vdata, BulletHelper::get_sb_flip());
197 
198  for (int j=0; j<nodes.size(); ++j) {
199  btVector3 v = nodes[j].m_x;
200  btVector3 &n = nodes[j].m_n;
201 
202  v = trans.invXform(v);
203 
204  vwriter.add_data3((PN_stdfloat)v.getX(), (PN_stdfloat)v.getY(), (PN_stdfloat)v.getZ());
205  nwriter.add_data3((PN_stdfloat)n.getX(), (PN_stdfloat)n.getY(), (PN_stdfloat)n.getZ());
206  fwriter.add_data1i(0);
207  }
208 
209  if (two_sided) {
210  for (int j=0; j<nodes.size(); ++j) {
211  btVector3 v = nodes[j].m_x;
212  btVector3 &n = nodes[j].m_n;
213 
214  v = trans.invXform(v);
215 
216  vwriter.add_data3((PN_stdfloat)v.getX(), (PN_stdfloat)v.getY(), (PN_stdfloat)v.getZ());
217  nwriter.add_data3((PN_stdfloat)n.getX(), (PN_stdfloat)n.getY(), (PN_stdfloat)n.getZ());
218  fwriter.add_data1i(1);
219  }
220  }
221 
222  // Indices
223  btSoftBody::Node *node0 = &nodes[0];
224  int i0, i1, i2;
225 
226  if (use_faces) {
227 
228  btSoftBody::tFaceArray &faces(body->m_faces);
229 
230  prim = new GeomTriangles(Geom::UH_stream);
231  prim->set_shade_model(Geom::SM_uniform);
232 
233  for (int j=0; j<faces.size(); ++j) {
234  i0 = int(faces[j].m_n[0] - node0);
235  i1 = int(faces[j].m_n[1] - node0);
236  i2 = int(faces[j].m_n[2] - node0);
237 
238  prim->add_vertices(i0, i1, i2);
239  prim->close_primitive();
240 
241  if (two_sided) {
242  i0 = nodes.size() + int(faces[j].m_n[0] - node0);
243  i1 = nodes.size() + int(faces[j].m_n[2] - node0);
244  i2 = nodes.size() + int(faces[j].m_n[1] - node0);
245 
246  prim->add_vertices(i0, i1, i2);
247  prim->close_primitive();
248  }
249  }
250  }
251  else {
252  btSoftBody::tLinkArray &links(body->m_links);
253 
254  prim = new GeomLines(Geom::UH_stream);
255  prim->set_shade_model(Geom::SM_uniform);
256 
257  for (int j=0; j<links.size(); ++j) {
258  i0 = int(links[j].m_n[0] - node0);
259  i1 = int(links[j].m_n[1] - node0);
260 
261  prim->add_vertices(i0, i1);
262  prim->close_primitive();
263  }
264  }
265 
266  // Geom
267  geom = new Geom(vdata);
268  geom->add_primitive(prim);
269 
270  return geom;
271 }
272 
273 /**
274  *
275  */
276 void BulletHelper::
277 make_texcoords_for_patch(Geom *geom, int resx, int resy) {
278 
279  PT(GeomVertexData) vdata = geom->modify_vertex_data();
280 
281  nassertv(vdata->has_column(InternalName::get_texcoord()));
282 
283  GeomVertexRewriter texcoords(vdata, InternalName::get_texcoord());
284 
285  int n = resx * resy;
286  int i = 0;
287  int ix;
288  int iy;
289  float u;
290  float v;
291 
292  while (!texcoords.is_at_end()) {
293  ix = i / resx;
294  iy = i % resy;
295 
296  if (i > n) ix -= 1;
297 
298  u = (float)ix/(float)(resx - 1);
299  v = (float)iy/(float)(resy - 1);
300 
301  texcoords.set_data2f(u, v);
302  i++;
303  }
304 }
NodePathCollection find_all_matches(const std::string &path) const
Returns the complete set of all NodePaths that begin with this NodePath and can be extended by path.
Definition: nodePath.cxx:354
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The abstract base class for all things that can collide with other things in the world,...
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
PT(Geom) BulletHelper
Returns a bounding-box visualization of the indicated node's "tight" bounding volume.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static const GeomVertexFormat * get_v3n3t2()
Returns a standard vertex format with a 2-component texture coordinate pair, a 3-component normal,...
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition: nodePath.I:62
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_path
Returns the nth NodePath in the collection.
get_into_collide_mask
Returns the current "into" CollideMask.
Definition: collisionNode.h:61
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:54
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
Defines a series of disconnected line segments.
Definition: geomLines.h:23
This class defines the physical layout of the vertex data stored within a Geom.
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:591
A node in the scene graph that can hold any number of CollisionSolids.
Definition: collisionNode.h:30
This describes the structure of a single array within a Geom data.
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
CPT(GeomVertexFormat) BulletHelper
Given a source GeomVertexFormat, converts it if necessary to the appropriate format for rendering.
get_num_paths
Returns the number of NodePaths in the collection.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:758
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
has_column
Returns true if the format has the named column, false otherwise.
This is a set of zero or more NodePaths.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.