Panda3D
 All Classes Functions Variables Enumerations
indexedFaceSet.cxx
1 // Filename: indexedFaceSet.cxx
2 // Created by: drose (24Jun99)
3 //
4 ////////////////////////////////////////////////////////////////////
5 // PANDA 3D SOFTWARE
6 // Copyright (c) Carnegie Mellon University. All rights reserved.
7 //
8 // All use of this software is subject to the terms of the revised BSD
9 // license. You should have received a copy of this license along
10 // with this source code in a file named "LICENSE."
11 ////////////////////////////////////////////////////////////////////
12 
13 #include "indexedFaceSet.h"
14 #include "vrmlAppearance.h"
15 #include "vrmlNodeType.h"
16 #include "vrmlNode.h"
17 #include "pnotify.h"
18 
19 #include "eggGroup.h"
20 #include "eggVertex.h"
21 #include "eggVertexPool.h"
22 #include "eggPolygon.h"
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: IndexedFaceSet::Constructor
26 // Access: Public
27 // Description:
28 ////////////////////////////////////////////////////////////////////
29 IndexedFaceSet::
30 IndexedFaceSet(const VrmlNode *geometry, const VRMLAppearance &appearance) :
31  _geometry(geometry), _appearance(appearance)
32 {
33  get_coord_values();
34  get_polys();
35  get_colors();
36  _has_normals = get_normals();
37  if (!_per_vertex_normals.empty()) {
38  assign_per_vertex_normals();
39  }
40  get_uvs();
41  if (!_per_vertex_uvs.empty()) {
42  assign_per_vertex_uvs();
43  }
44 }
45 
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: IndexedFaceSet::convert_to_egg
49 // Access: Private
50 // Description:
51 ////////////////////////////////////////////////////////////////////
52 void IndexedFaceSet::
53 convert_to_egg(EggGroup *group, const LMatrix4d &net_transform) {
54  EggVertexPool *vpool = new EggVertexPool(group->get_name());
55  group->add_child(vpool);
56 
57  make_polys(vpool, group, net_transform);
58  if (!_has_normals && _appearance._has_material) {
59  compute_normals(group);
60  }
61 }
62 
63 
64 ////////////////////////////////////////////////////////////////////
65 // Function: IndexedFaceSet::get_coord_values
66 // Access: Private
67 // Description:
68 ////////////////////////////////////////////////////////////////////
69 void IndexedFaceSet::
70 get_coord_values() {
71  const VrmlNode *coord = _geometry->get_value("coord")._sfnode._p;
72 
73  if (coord != NULL) {
74  const MFArray *point = coord->get_value("point")._mf;
75  MFArray::const_iterator ci;
76  for (ci = point->begin(); ci != point->end(); ++ci) {
77  const double *p = (*ci)._sfvec;
78  _coord_values.push_back(LVertexd(p[0], p[1], p[2]));
79  }
80  }
81 }
82 
83 
84 ////////////////////////////////////////////////////////////////////
85 // Function: IndexedFaceSet::get_polys
86 // Access: Private
87 // Description:
88 ////////////////////////////////////////////////////////////////////
89 void IndexedFaceSet::
90 get_polys() {
91  const MFArray *coordIndex = _geometry->get_value("coordIndex")._mf;
92  VrmlPolygon poly;
93 
94  MFArray::const_iterator ci;
95  for (ci = coordIndex->begin(); ci != coordIndex->end(); ++ci) {
96  if ((*ci)._sfint32 < 0) {
97  _polys.push_back(poly);
98  poly._verts.clear();
99  } else {
100  const LVertexd &p = _coord_values[(*ci)._sfint32];
101  VrmlVertex vert;
102  vert._index = (*ci)._sfint32;
103  vert._pos = p;
104  poly._verts.push_back(vert);
105  }
106  }
107 }
108 
109 ////////////////////////////////////////////////////////////////////
110 // Function: IndexedFaceSet::get_vrml_colors
111 // Access: Private
112 // Description: Builds up a vector of LColor pointers corresponding
113 // to the VRML color node.
114 ////////////////////////////////////////////////////////////////////
115 void IndexedFaceSet::
116 get_vrml_colors(const VrmlNode *color_node, double transparency,
117  pvector<UnalignedLVecBase4> &color_list) {
118  const MFArray *color = color_node->get_value("color")._mf;
119  MFArray::const_iterator ci;
120  for (ci = color->begin(); ci != color->end(); ++ci) {
121  const double *p = (*ci)._sfvec;
122  LColor color(p[0], p[1], p[2], 1.0 - transparency);
123  color_list.push_back(color);
124  }
125 }
126 
127 ////////////////////////////////////////////////////////////////////
128 // Function: IndexedFaceSet::get_vrml_normals
129 // Access: Private
130 // Description: Builds up a vector of double array pointers corresponding
131 // to the VRML normal node.
132 ////////////////////////////////////////////////////////////////////
133 void IndexedFaceSet::
134 get_vrml_normals(const VrmlNode *normal_node,
135  pvector<LNormald> &normal_list) {
136  const MFArray *point = normal_node->get_value("vector")._mf;
137  MFArray::const_iterator ci;
138  for (ci = point->begin(); ci != point->end(); ++ci) {
139  const double *p = (*ci)._sfvec;
140  LNormald normal(p[0], p[1], p[2]);
141  normal_list.push_back(normal);
142  }
143 }
144 
145 ////////////////////////////////////////////////////////////////////
146 // Function: IndexedFaceSet::get_vrml_uvs
147 // Access: Private
148 // Description: Builds up a vector of double array pointers corresponding
149 // to the VRML texCoord node.
150 ////////////////////////////////////////////////////////////////////
151 void IndexedFaceSet::
152 get_vrml_uvs(const VrmlNode *texCoord_node,
153  pvector<LTexCoordd> &uv_list) {
154  const MFArray *point = texCoord_node->get_value("point")._mf;
155  MFArray::const_iterator ci;
156  for (ci = point->begin(); ci != point->end(); ++ci) {
157  const double *p = (*ci)._sfvec;
158  LTexCoordd uv(p[0], p[1]);
159  uv_list.push_back(uv);
160  }
161 }
162 
163 
164 ////////////////////////////////////////////////////////////////////
165 // Function: IndexedFaceSet::get_colors
166 // Access: Private
167 // Description:
168 ////////////////////////////////////////////////////////////////////
169 bool IndexedFaceSet::
170 get_colors() {
171  const VrmlNode *color = _geometry->get_value("color")._sfnode._p;
172  if (color != NULL) {
173  // Vertex or face colors.
174  pvector<UnalignedLVecBase4> color_list;
175  get_vrml_colors(color, _appearance._transparency, color_list);
176 
177  bool colorPerVertex = _geometry->get_value("colorPerVertex")._sfbool;
178  MFArray *colorIndex = _geometry->get_value("colorIndex")._mf;
179  if (colorPerVertex) {
180  MFArray::const_iterator ci;
181  size_t pi = 0;
182  size_t pv = 0;
183  for (ci = colorIndex->begin(); ci != colorIndex->end(); ++ci) {
184  if ((*ci)._sfint32 < 0) {
185  // End of poly.
186  if (pv != _polys[pi]._verts.size()) {
187  cerr << "Color indices don't match up!\n";
188  return false;
189  }
190  pi++;
191  pv = 0;
192  } else {
193  if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
194  cerr << "Color indices don't match up!\n";
195  return false;
196  }
197  _polys[pi]._verts[pv]._attrib.set_color(color_list[(*ci)._sfint32]);
198  pv++;
199  }
200  }
201  if (pi != _polys.size()) {
202  cerr << "Not enough color indices!\n";
203  return false;
204  }
205  } else {
206  if (!colorIndex->empty()) {
207  MFArray::const_iterator ci;
208  size_t pi = 0;
209  if (colorIndex->size() != _polys.size()) {
210  cerr << "Wrong number of color indices!\n";
211  return false;
212  }
213  for (ci = colorIndex->begin(); ci != colorIndex->end(); ++ci) {
214  if ((*ci)._sfint32 < 0 || (*ci)._sfint32 >= (int)color_list.size()) {
215  cerr << "Invalid color index!\n";
216  return false;
217  }
218  _polys[pi]._attrib.set_color(color_list[(*ci)._sfint32]);
219  pi++;
220  }
221  } else {
222  if (color_list.size() != _polys.size()) {
223  cerr << "Wrong number of colors!\n";
224  return false;
225  }
226  for (size_t pi = 0; pi < color_list.size(); pi++) {
227  _polys[pi]._attrib.set_color(color_list[pi]);
228  }
229  }
230  }
231  return true;
232  }
233  return false;
234 }
235 
236 ////////////////////////////////////////////////////////////////////
237 // Function: IndexedFaceSet::get_normals
238 // Access: Private
239 // Description:
240 ////////////////////////////////////////////////////////////////////
241 bool IndexedFaceSet::
242 get_normals() {
243  const VrmlNode *normal = _geometry->get_value("normal")._sfnode._p;
244  if (normal != NULL) {
245  // Vertex or face normals.
246  pvector<LNormald> normal_list;
247  get_vrml_normals(normal, normal_list);
248 
249  bool normalPerVertex = _geometry->get_value("normalPerVertex")._sfbool;
250  MFArray *normalIndex = _geometry->get_value("normalIndex")._mf;
251  MFArray::const_iterator ci;
252 
253  if (normalPerVertex &&
254  normal_list.size() == _polys.size() &&
255  normalIndex->empty()) {
256  // Here's an interesting formZ bug. We end up with a VRML file
257  // that claims to have normals per vertex, yet there is no
258  // normal index list, and there are exactly enough normals in
259  // the list to indicate one normal per face. Silly formZ.
260  normalPerVertex = false;
261  }
262 
263  if (normalPerVertex) {
264 
265  if (normalIndex->empty()) {
266  // If we have *no* normal index array, but we do have
267  // per-vertex normals, assume the VRML writer meant to imply a
268  // one-to-one mapping. This works around a broken formZ VRML
269  // file writer.
270  for (size_t i = 0; i < normal_list.size(); i++) {
271  VrmlFieldValue fv;
272  fv._sfint32 = i;
273  (*normalIndex).push_back(fv);
274  }
275  }
276 
277  // It's possible that this .wrl file indexes normals directly
278  // into the vertex array, instead of into the polygon list.
279  // Check for this possibility. This can only happen if the
280  // number of normal indices exactly matches the number of
281  // vertices, and none of the indices is -1.
282  bool linear_list = (normalIndex->size() == _coord_values.size());
283  for (ci = normalIndex->begin();
284  ci != normalIndex->end() && linear_list;
285  ++ci) {
286  linear_list = ((*ci)._sfint32 >= 0);
287  }
288 
289  if (linear_list) {
290  // Ok, we do have such a list. This .wrl file seems to store
291  // its texture coordinates one per vertex, instead of one per
292  // polygon vertex.
293  _per_vertex_normals.reserve(_coord_values.size());
294 
295  for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
296  size_t vi = (*ci)._sfint32;
297  nassertr(vi >= 0, false);
298  if (vi >= normal_list.size()) {
299  cerr << "Invalid normal index: " << vi << "\n";
300  return false;
301  }
302  _per_vertex_normals.push_back(normal_list[vi]);
303  }
304  nassertr(_per_vertex_normals.size() == _coord_values.size(), false);
305 
306  } else {
307  // This is a "correct" .wrl file that stores its texture
308  // coordinates one per polygon vertex. This allows a shared
309  // vertex to contain two different normal values in differing
310  // polygons (meaning it's not actually shared).
311 
312  MFArray::const_iterator ci;
313  size_t pi = 0;
314  size_t pv = 0;
315  for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
316  if ((*ci)._sfint32 < 0) {
317  // End of poly.
318  if (pv != _polys[pi]._verts.size()) {
319  cerr << "Normal indices don't match up!\n";
320  return false;
321  }
322  pi++;
323  pv = 0;
324  } else {
325  if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
326  cerr << "Normal indices don't match up!\n";
327  return false;
328  }
329  const LNormald &d = normal_list[(*ci)._sfint32];
330  _polys[pi]._verts[pv]._attrib.set_normal(d);
331  pv++;
332  }
333  }
334  if (pi != _polys.size()) {
335  cerr << "Not enough normal indices!\n";
336  return false;
337  }
338  }
339  } else {
340  if (!normalIndex->empty()) {
341  size_t pi = 0;
342  if (normalIndex->size() != _polys.size()) {
343  cerr << "Wrong number of normal indices!\n";
344  return false;
345  }
346  for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
347  if ((*ci)._sfint32 < 0 || (*ci)._sfint32 >= (int)normal_list.size()) {
348  cerr << "Invalid normal index!\n";
349  return false;
350  }
351  const LNormald &d = normal_list[(*ci)._sfint32];
352  _polys[pi]._attrib.set_normal(d);
353  pi++;
354  }
355  } else {
356  if (normal_list.size() != _polys.size()) {
357  cerr << "Wrong number of normals!\n";
358  return false;
359  }
360  for (size_t pi = 0; pi < normal_list.size(); pi++) {
361  const LNormald &d = normal_list[pi];
362  _polys[pi]._attrib.set_normal(d);
363  }
364  }
365  }
366  return true;
367  }
368  return false;
369 }
370 
371 ////////////////////////////////////////////////////////////////////
372 // Function: IndexedFaceSet::assign_per_vertex_normals
373 // Access: Private
374 // Description: Once the array of _per_vertex_normals has been filled
375 // (by a broken .wrl file that indexes the normal's
376 // directly into the vertex array instead of per polygon
377 // vertex), go back through the polygons and assign the
378 // normals by index number.
379 ////////////////////////////////////////////////////////////////////
380 void IndexedFaceSet::
381 assign_per_vertex_normals() {
382  for (size_t pi = 0; pi < _polys.size(); pi++) {
383  for (size_t pv = 0; pv < _polys[pi]._verts.size(); pv++) {
384  VrmlVertex &vv = _polys[pi]._verts[pv];
385  if (vv._index >= 0 && vv._index < (int)_per_vertex_normals.size()) {
386  const LNormald &d = _per_vertex_normals[vv._index];
387  vv._attrib.set_normal(d);
388  }
389  }
390  }
391 }
392 
393 
394 ////////////////////////////////////////////////////////////////////
395 // Function: IndexedFaceSet::get_uvs
396 // Access: Private
397 // Description:
398 ////////////////////////////////////////////////////////////////////
399 bool IndexedFaceSet::
400 get_uvs() {
401  const VrmlNode *texCoord = _geometry->get_value("texCoord")._sfnode._p;
402  if (texCoord != NULL) {
403  // Vertex or face texCoords.
404  pvector<LTexCoordd> uv_list;
405  get_vrml_uvs(texCoord, uv_list);
406 
407  MFArray *texCoordIndex = _geometry->get_value("texCoordIndex")._mf;
408  MFArray::const_iterator ci;
409 
410  if (texCoordIndex->empty()) {
411  // If we have *no* texture coordinate index array, but we do
412  // have texture coordinates, assume the VRML writer meant to
413  // imply a one-to-one mapping. This works around a broken formZ
414  // VRML file writer.
415  for (size_t i = 0; i < uv_list.size(); i++) {
416  VrmlFieldValue fv;
417  fv._sfint32 = i;
418  (*texCoordIndex).push_back(fv);
419  }
420  }
421 
422  // It's possible that this .wrl file indexes texture coordinates
423  // directly into the vertex array, instead of into the polygon
424  // list. Check for this possibility. This can only happen if the
425  // number of texture coordinate indices exactly matches the number
426  // of vertices, and none of the indices is -1.
427  bool linear_list = (texCoordIndex->size() == _coord_values.size());
428  for (ci = texCoordIndex->begin();
429  ci != texCoordIndex->end() && linear_list;
430  ++ci) {
431  linear_list = ((*ci)._sfint32 >= 0);
432  }
433 
434  if (linear_list) {
435  // Ok, we do have such a list. This .wrl file seems to store
436  // its texture coordinates one per vertex, instead of one per
437  // polygon vertex.
438  _per_vertex_uvs.reserve(_coord_values.size());
439 
440  for (ci = texCoordIndex->begin(); ci != texCoordIndex->end(); ++ci) {
441  size_t vi = (*ci)._sfint32;
442  nassertr(vi >= 0, false);
443  if (vi >= uv_list.size()) {
444  cerr << "Invalid texCoord index: " << vi << "\n";
445  return false;
446  }
447  _per_vertex_uvs.push_back(uv_list[vi]);
448  }
449  nassertr(_per_vertex_uvs.size() == _coord_values.size(), false);
450 
451  } else {
452  // This is a "correct" .wrl file that stores its texture
453  // coordinates one per polygon vertex. This allows a shared
454  // vertex to contain two different texture coordinate values in
455  // differing polygons (meaning it's not actually shared).
456 
457  size_t pi = 0;
458  size_t pv = 0;
459  for (ci = texCoordIndex->begin(); ci != texCoordIndex->end(); ++ci) {
460  if ((*ci)._sfint32 < 0) {
461  // End of poly.
462  if (pv != _polys[pi]._verts.size()) {
463  cerr << "texCoord indices don't match up!\n";
464  return false;
465  }
466  pi++;
467  pv = 0;
468  } else {
469  if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
470  cerr << "texCoord indices don't match up!\n";
471  return false;
472  }
473  _polys[pi]._verts[pv]._attrib.set_uv(uv_list[(*ci)._sfint32]);
474  pv++;
475  }
476  }
477  if (pi != _polys.size()) {
478  cerr << "Not enough texCoord indices!\n";
479  return false;
480  }
481  }
482  return true;
483  }
484  return false;
485 }
486 
487 ////////////////////////////////////////////////////////////////////
488 // Function: IndexedFaceSet::assign_per_vertex_uvs
489 // Access: Private
490 // Description: Once the array of _per_vertex_uvs has been filled (by
491 // a broken .wrl file that indexes the uv's directly
492 // into the vertex array instead of per polygon vertex),
493 // go back through the polygons and assign the UV's by
494 // index number.
495 ////////////////////////////////////////////////////////////////////
496 void IndexedFaceSet::
497 assign_per_vertex_uvs() {
498  for (size_t pi = 0; pi < _polys.size(); pi++) {
499  for (size_t pv = 0; pv < _polys[pi]._verts.size(); pv++) {
500  VrmlVertex &vv = _polys[pi]._verts[pv];
501  if (vv._index >= 0 && vv._index < (int)_per_vertex_uvs.size()) {
502  const LTexCoordd &d = _per_vertex_uvs[vv._index];
503  vv._attrib.set_uv(d);
504  }
505  }
506  }
507 }
508 
509 
510 ////////////////////////////////////////////////////////////////////
511 // Function: IndexedFaceSet::make_polys
512 // Access: Private
513 // Description:
514 ////////////////////////////////////////////////////////////////////
515 void IndexedFaceSet::
516 make_polys(EggVertexPool *vpool, EggGroup *group,
517  const LMatrix4d &net_transform) {
518  bool ccw = _geometry->get_value("ccw")._sfbool;
519  bool solid = _geometry->get_value("solid")._sfbool;
520 
521  for (size_t pi = 0; pi < _polys.size(); pi++) {
522  EggPolygon *poly = new EggPolygon;
523  group->add_child(poly);
524  poly->copy_attributes(_polys[pi]._attrib);
525 
526  if (!poly->has_color() && _appearance._has_material) {
527  poly->set_color(_appearance._color);
528  }
529 
530  if (_appearance._tex != (EggTexture *)NULL) {
531  poly->set_texture(_appearance._tex);
532  }
533 
534  if (!solid) {
535  poly->set_bface_flag(true);
536  }
537 
538  if (ccw) {
539  // The vertices are counterclockwise, same as Egg.
540  for (int pv = 0; pv < (int)_polys[pi]._verts.size(); pv++) {
541  EggVertex vert(_polys[pi]._verts[pv]._attrib);
542  LVertexd pos =
543  _polys[pi]._verts[pv]._pos * net_transform;
544  vert.set_pos(pos);
545 
546  poly->add_vertex(vpool->create_unique_vertex(vert));
547  }
548  } else {
549  // The vertices are clockwise, so add 'em in reverse order.
550  for (int pv = (int)_polys[pi]._verts.size() - 1; pv >= 0; pv--) {
551  EggVertex vert(_polys[pi]._verts[pv]._attrib);
552  LVertexd pos =
553  _polys[pi]._verts[pv]._pos * net_transform;
554  vert.set_pos(pos);
555 
556  poly->add_vertex(vpool->create_unique_vertex(vert));
557  }
558  }
559  }
560 }
561 
562 
563 ////////////////////////////////////////////////////////////////////
564 // Function: IndexedFaceSet::compute_normals
565 // Access: Private
566 // Description:
567 ////////////////////////////////////////////////////////////////////
568 void IndexedFaceSet::
569 compute_normals(EggGroup *group) {
570  const VrmlNode *normal = _geometry->get_value("normal")._sfnode._p;
571  if (normal == NULL) {
572  // Compute normals.
573  double creaseAngle = _geometry->get_value("creaseAngle")._sffloat;
574  if (creaseAngle == 0.0) {
575  group->recompute_polygon_normals();
576  } else {
577  group->recompute_vertex_normals(rad_2_deg(creaseAngle));
578  }
579  }
580 }
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
void recompute_polygon_normals(CoordinateSystem cs=CS_default)
Recomputes all the polygon normals for polygon geometry at this group node and below so that they acc...
void set_texture(EggTexture *texture)
Replaces the current list of textures with the indicated texture.
Definition: eggPrimitive.I:139
void copy_attributes(const EggAttributes &other)
Copies the rendering attributes from the indicated primitive.
This is a two-component point in space.
Definition: lpoint2.h:411
void set_bface_flag(bool flag)
Sets the backfacing flag of the polygon.
Definition: eggPrimitive.I:289
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
A single polygon.
Definition: eggPolygon.h:26
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:746
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:531
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
A collection of vertices.
Definition: eggVertexPool.h:46
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive&#39;s list of vertices, and returns it...
void recompute_vertex_normals(double threshold, CoordinateSystem cs=CS_default)
Recomputes all the vertex normals for polygon geometry at this group node and below so that they accu...