Panda3D

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