Panda3D
 All Classes Functions Variables Enumerations
indexedFaceSet.cxx
00001 // Filename: indexedFaceSet.cxx
00002 // Created by:  drose (24Jun99)
00003 // 
00004 ////////////////////////////////////////////////////////////////////
00005 // PANDA 3D SOFTWARE
00006 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00007 //
00008 // All use of this software is subject to the terms of the revised BSD
00009 // license.  You should have received a copy of this license along
00010 // with this source code in a file named "LICENSE."
00011 ////////////////////////////////////////////////////////////////////
00012 
00013 #include "indexedFaceSet.h"
00014 #include "vrmlAppearance.h"
00015 #include "vrmlNodeType.h"
00016 #include "vrmlNode.h"
00017 #include "pnotify.h"
00018 
00019 #include "eggGroup.h"
00020 #include "eggVertex.h"
00021 #include "eggVertexPool.h"
00022 #include "eggPolygon.h"
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: IndexedFaceSet::Constructor
00026 //       Access: Public
00027 //  Description: 
00028 ////////////////////////////////////////////////////////////////////
00029 IndexedFaceSet::
00030 IndexedFaceSet(const VrmlNode *geometry, const VRMLAppearance &appearance) :
00031   _geometry(geometry), _appearance(appearance)
00032 {
00033   get_coord_values();
00034   get_polys();
00035   get_colors();
00036   _has_normals = get_normals();
00037   if (!_per_vertex_normals.empty()) {
00038     assign_per_vertex_normals();
00039   }
00040   get_uvs();
00041   if (!_per_vertex_uvs.empty()) {
00042     assign_per_vertex_uvs();
00043   }
00044 }
00045 
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: IndexedFaceSet::convert_to_egg
00049 //       Access: Private
00050 //  Description: 
00051 ////////////////////////////////////////////////////////////////////
00052 void IndexedFaceSet::
00053 convert_to_egg(EggGroup *group, const LMatrix4d &net_transform) {
00054   EggVertexPool *vpool = new EggVertexPool(group->get_name());
00055   group->add_child(vpool);
00056 
00057   make_polys(vpool, group, net_transform);
00058   if (!_has_normals && _appearance._has_material) {
00059     compute_normals(group);
00060   }
00061 }
00062 
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: IndexedFaceSet::get_coord_values
00066 //       Access: Private
00067 //  Description: 
00068 ////////////////////////////////////////////////////////////////////
00069 void IndexedFaceSet::
00070 get_coord_values() {
00071   const VrmlNode *coord = _geometry->get_value("coord")._sfnode._p;
00072 
00073   if (coord != NULL) {
00074     const MFArray *point = coord->get_value("point")._mf;
00075     MFArray::const_iterator ci;
00076     for (ci = point->begin(); ci != point->end(); ++ci) {
00077       const double *p = (*ci)._sfvec;
00078       _coord_values.push_back(LVertexd(p[0], p[1], p[2]));
00079     }
00080   }
00081 }
00082 
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: IndexedFaceSet::get_polys
00086 //       Access: Private
00087 //  Description: 
00088 ////////////////////////////////////////////////////////////////////
00089 void IndexedFaceSet::
00090 get_polys() {
00091   const MFArray *coordIndex = _geometry->get_value("coordIndex")._mf;
00092   VrmlPolygon poly;
00093 
00094   MFArray::const_iterator ci;
00095   for (ci = coordIndex->begin(); ci != coordIndex->end(); ++ci) {
00096     if ((*ci)._sfint32 < 0) {
00097       _polys.push_back(poly);
00098       poly._verts.clear();
00099     } else {
00100       const LVertexd &p = _coord_values[(*ci)._sfint32];
00101       VrmlVertex vert;
00102       vert._index = (*ci)._sfint32;
00103       vert._pos = p;
00104       poly._verts.push_back(vert);
00105     }
00106   }
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: IndexedFaceSet::get_vrml_colors
00111 //       Access: Private
00112 //  Description: Builds up a vector of LColor pointers corresponding
00113 //               to the VRML color node.
00114 ////////////////////////////////////////////////////////////////////
00115 void IndexedFaceSet::
00116 get_vrml_colors(const VrmlNode *color_node, double transparency,
00117                 pvector<UnalignedLVecBase4> &color_list) {
00118   const MFArray *color = color_node->get_value("color")._mf;
00119   MFArray::const_iterator ci;
00120   for (ci = color->begin(); ci != color->end(); ++ci) {
00121     const double *p = (*ci)._sfvec;
00122     LColor color(p[0], p[1], p[2], 1.0 - transparency);
00123     color_list.push_back(color);
00124   }
00125 }
00126 
00127 ////////////////////////////////////////////////////////////////////
00128 //     Function: IndexedFaceSet::get_vrml_normals
00129 //       Access: Private
00130 //  Description: Builds up a vector of double array pointers corresponding
00131 //               to the VRML normal node.
00132 ////////////////////////////////////////////////////////////////////
00133 void IndexedFaceSet::
00134 get_vrml_normals(const VrmlNode *normal_node, 
00135                  pvector<LNormald> &normal_list) {
00136   const MFArray *point = normal_node->get_value("vector")._mf;
00137   MFArray::const_iterator ci;
00138   for (ci = point->begin(); ci != point->end(); ++ci) {
00139     const double *p = (*ci)._sfvec;
00140     LNormald normal(p[0], p[1], p[2]);
00141     normal_list.push_back(normal);
00142   }
00143 }
00144 
00145 ////////////////////////////////////////////////////////////////////
00146 //     Function: IndexedFaceSet::get_vrml_uvs
00147 //       Access: Private
00148 //  Description: Builds up a vector of double array pointers corresponding
00149 //               to the VRML texCoord node.
00150 ////////////////////////////////////////////////////////////////////
00151 void IndexedFaceSet::
00152 get_vrml_uvs(const VrmlNode *texCoord_node, 
00153              pvector<LTexCoordd> &uv_list) {
00154   const MFArray *point = texCoord_node->get_value("point")._mf;
00155   MFArray::const_iterator ci;
00156   for (ci = point->begin(); ci != point->end(); ++ci) {
00157     const double *p = (*ci)._sfvec;
00158     LTexCoordd uv(p[0], p[1]);
00159     uv_list.push_back(uv);
00160   }
00161 }
00162 
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: IndexedFaceSet::get_colors
00166 //       Access: Private
00167 //  Description: 
00168 ////////////////////////////////////////////////////////////////////
00169 bool IndexedFaceSet::
00170 get_colors() {
00171   const VrmlNode *color = _geometry->get_value("color")._sfnode._p;
00172   if (color != NULL) {
00173     // Vertex or face colors.
00174     pvector<UnalignedLVecBase4> color_list;
00175     get_vrml_colors(color, _appearance._transparency, color_list);
00176     
00177     bool colorPerVertex = _geometry->get_value("colorPerVertex")._sfbool;
00178     MFArray *colorIndex = _geometry->get_value("colorIndex")._mf;
00179     if (colorPerVertex) {
00180       MFArray::const_iterator ci;
00181       size_t pi = 0;
00182       size_t pv = 0;
00183       for (ci = colorIndex->begin(); ci != colorIndex->end(); ++ci) {
00184         if ((*ci)._sfint32 < 0) {
00185           // End of poly.
00186           if (pv != _polys[pi]._verts.size()) {
00187             cerr << "Color indices don't match up!\n";
00188             return false;
00189           }
00190           pi++;
00191           pv = 0;
00192         } else {
00193           if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
00194             cerr << "Color indices don't match up!\n";
00195             return false;
00196           }
00197           _polys[pi]._verts[pv]._attrib.set_color(color_list[(*ci)._sfint32]);
00198           pv++;
00199         }
00200       }
00201       if (pi != _polys.size()) {
00202         cerr << "Not enough color indices!\n";
00203         return false;
00204       }
00205     } else {
00206       if (!colorIndex->empty()) {
00207         MFArray::const_iterator ci;
00208         size_t pi = 0;
00209         if (colorIndex->size() != _polys.size()) {
00210           cerr << "Wrong number of color indices!\n";
00211           return false;
00212         }
00213         for (ci = colorIndex->begin(); ci != colorIndex->end(); ++ci) {
00214           if ((*ci)._sfint32 < 0 || (*ci)._sfint32 >= (int)color_list.size()) {
00215             cerr << "Invalid color index!\n";
00216             return false;
00217           }
00218           _polys[pi]._attrib.set_color(color_list[(*ci)._sfint32]);
00219           pi++;
00220         }
00221       } else {
00222         if (color_list.size() != _polys.size()) {
00223           cerr << "Wrong number of colors!\n";
00224           return false;
00225         }
00226         for (size_t pi = 0; pi < color_list.size(); pi++) {
00227           _polys[pi]._attrib.set_color(color_list[pi]);
00228         }
00229       }
00230     }
00231     return true;
00232   }
00233   return false;
00234 }
00235 
00236 ////////////////////////////////////////////////////////////////////
00237 //     Function: IndexedFaceSet::get_normals
00238 //       Access: Private
00239 //  Description: 
00240 ////////////////////////////////////////////////////////////////////
00241 bool IndexedFaceSet::
00242 get_normals() {
00243   const VrmlNode *normal = _geometry->get_value("normal")._sfnode._p;
00244   if (normal != NULL) {
00245     // Vertex or face normals.
00246     pvector<LNormald> normal_list;
00247     get_vrml_normals(normal, normal_list);
00248     
00249     bool normalPerVertex = _geometry->get_value("normalPerVertex")._sfbool;
00250     MFArray *normalIndex = _geometry->get_value("normalIndex")._mf;
00251     MFArray::const_iterator ci;
00252 
00253     if (normalPerVertex &&
00254         normal_list.size() == _polys.size() &&
00255         normalIndex->empty()) {
00256       // Here's an interesting formZ bug.  We end up with a VRML file
00257       // that claims to have normals per vertex, yet there is no
00258       // normal index list, and there are exactly enough normals in
00259       // the list to indicate one normal per face.  Silly formZ.
00260       normalPerVertex = false;
00261     }
00262 
00263     if (normalPerVertex) {
00264 
00265       if (normalIndex->empty()) {
00266         // If we have *no* normal index array, but we do have
00267         // per-vertex normals, assume the VRML writer meant to imply a
00268         // one-to-one mapping.  This works around a broken formZ VRML
00269         // file writer.
00270         for (size_t i = 0; i < normal_list.size(); i++) {
00271           VrmlFieldValue fv;
00272           fv._sfint32 = i;
00273           (*normalIndex).push_back(fv);
00274         }
00275       }
00276 
00277       // It's possible that this .wrl file indexes normals directly
00278       // into the vertex array, instead of into the polygon list.
00279       // Check for this possibility.  This can only happen if the
00280       // number of normal indices exactly matches the number of
00281       // vertices, and none of the indices is -1.
00282       bool linear_list = (normalIndex->size() == _coord_values.size());
00283       for (ci = normalIndex->begin(); 
00284            ci != normalIndex->end() && linear_list; 
00285            ++ci) {
00286         linear_list = ((*ci)._sfint32 >= 0);
00287       }
00288       
00289       if (linear_list) {
00290         // Ok, we do have such a list.  This .wrl file seems to store
00291         // its texture coordinates one per vertex, instead of one per
00292         // polygon vertex.
00293         _per_vertex_normals.reserve(_coord_values.size());
00294 
00295         for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
00296           size_t vi = (*ci)._sfint32;
00297           nassertr(vi >= 0, false);
00298           if (vi >= normal_list.size()) {
00299             cerr << "Invalid normal index: " << vi << "\n";
00300             return false;
00301           }
00302           _per_vertex_normals.push_back(normal_list[vi]);
00303         }
00304         nassertr(_per_vertex_normals.size() == _coord_values.size(), false);
00305 
00306       } else {
00307         // This is a "correct" .wrl file that stores its texture
00308         // coordinates one per polygon vertex.  This allows a shared
00309         // vertex to contain two different normal values in differing
00310         // polygons (meaning it's not actually shared).
00311 
00312         MFArray::const_iterator ci;
00313         size_t pi = 0;
00314         size_t pv = 0;
00315         for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
00316           if ((*ci)._sfint32 < 0) {
00317             // End of poly.
00318             if (pv != _polys[pi]._verts.size()) {
00319               cerr << "Normal indices don't match up!\n";
00320               return false;
00321             }
00322             pi++;
00323             pv = 0;
00324           } else {
00325             if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
00326               cerr << "Normal indices don't match up!\n";
00327               return false;
00328             }
00329             const LNormald &d = normal_list[(*ci)._sfint32];
00330             _polys[pi]._verts[pv]._attrib.set_normal(d);
00331             pv++;
00332           }
00333         }
00334         if (pi != _polys.size()) {
00335           cerr << "Not enough normal indices!\n";
00336           return false;
00337         }
00338       }
00339     } else {
00340       if (!normalIndex->empty()) {
00341         size_t pi = 0;
00342         if (normalIndex->size() != _polys.size()) {
00343           cerr << "Wrong number of normal indices!\n";
00344           return false;
00345         }
00346         for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
00347           if ((*ci)._sfint32 < 0 || (*ci)._sfint32 >= (int)normal_list.size()) {
00348             cerr << "Invalid normal index!\n";
00349             return false;
00350           }
00351           const LNormald &d = normal_list[(*ci)._sfint32];
00352           _polys[pi]._attrib.set_normal(d);
00353           pi++;
00354         }
00355       } else {
00356         if (normal_list.size() != _polys.size()) {
00357           cerr << "Wrong number of normals!\n";
00358           return false;
00359         }
00360         for (size_t pi = 0; pi < normal_list.size(); pi++) {
00361           const LNormald &d = normal_list[pi];
00362           _polys[pi]._attrib.set_normal(d);
00363         }
00364       }
00365     }
00366     return true;
00367   }
00368   return false;
00369 }
00370 
00371 ////////////////////////////////////////////////////////////////////
00372 //     Function: IndexedFaceSet::assign_per_vertex_normals
00373 //       Access: Private
00374 //  Description: Once the array of _per_vertex_normals has been filled
00375 //               (by a broken .wrl file that indexes the normal's
00376 //               directly into the vertex array instead of per polygon
00377 //               vertex), go back through the polygons and assign the
00378 //               normals by index number.
00379 ////////////////////////////////////////////////////////////////////
00380 void IndexedFaceSet::
00381 assign_per_vertex_normals() {
00382   for (size_t pi = 0; pi < _polys.size(); pi++) {
00383     for (size_t pv = 0; pv < _polys[pi]._verts.size(); pv++) {
00384       VrmlVertex &vv = _polys[pi]._verts[pv];
00385       if (vv._index >= 0 && vv._index < (int)_per_vertex_normals.size()) {
00386         const LNormald &d = _per_vertex_normals[vv._index];
00387         vv._attrib.set_normal(d);
00388       }
00389     }
00390   }
00391 }
00392 
00393 
00394 ////////////////////////////////////////////////////////////////////
00395 //     Function: IndexedFaceSet::get_uvs
00396 //       Access: Private
00397 //  Description: 
00398 ////////////////////////////////////////////////////////////////////
00399 bool IndexedFaceSet::
00400 get_uvs() {
00401   const VrmlNode *texCoord = _geometry->get_value("texCoord")._sfnode._p;
00402   if (texCoord != NULL) {
00403     // Vertex or face texCoords.
00404     pvector<LTexCoordd> uv_list;
00405     get_vrml_uvs(texCoord, uv_list);
00406     
00407     MFArray *texCoordIndex = _geometry->get_value("texCoordIndex")._mf;
00408     MFArray::const_iterator ci;
00409 
00410     if (texCoordIndex->empty()) {
00411       // If we have *no* texture coordinate index array, but we do
00412       // have texture coordinates, assume the VRML writer meant to
00413       // imply a one-to-one mapping.  This works around a broken formZ
00414       // VRML file writer.
00415       for (size_t i = 0; i < uv_list.size(); i++) {
00416         VrmlFieldValue fv;
00417         fv._sfint32 = i;
00418         (*texCoordIndex).push_back(fv);
00419       }
00420     }
00421 
00422     // It's possible that this .wrl file indexes texture coordinates
00423     // directly into the vertex array, instead of into the polygon
00424     // list.  Check for this possibility.  This can only happen if the
00425     // number of texture coordinate indices exactly matches the number
00426     // of vertices, and none of the indices is -1.
00427     bool linear_list = (texCoordIndex->size() == _coord_values.size());
00428     for (ci = texCoordIndex->begin(); 
00429          ci != texCoordIndex->end() && linear_list; 
00430          ++ci) {
00431       linear_list = ((*ci)._sfint32 >= 0);
00432     }
00433 
00434     if (linear_list) {
00435       // Ok, we do have such a list.  This .wrl file seems to store
00436       // its texture coordinates one per vertex, instead of one per
00437       // polygon vertex.
00438       _per_vertex_uvs.reserve(_coord_values.size());
00439 
00440       for (ci = texCoordIndex->begin(); ci != texCoordIndex->end(); ++ci) {
00441         size_t vi = (*ci)._sfint32;
00442         nassertr(vi >= 0, false);
00443         if (vi >= uv_list.size()) {
00444           cerr << "Invalid texCoord index: " << vi << "\n";
00445           return false;
00446         }
00447         _per_vertex_uvs.push_back(uv_list[vi]);
00448       }
00449       nassertr(_per_vertex_uvs.size() == _coord_values.size(), false);
00450 
00451     } else {
00452       // This is a "correct" .wrl file that stores its texture
00453       // coordinates one per polygon vertex.  This allows a shared
00454       // vertex to contain two different texture coordinate values in
00455       // differing polygons (meaning it's not actually shared).
00456 
00457       size_t pi = 0;
00458       size_t pv = 0;
00459       for (ci = texCoordIndex->begin(); ci != texCoordIndex->end(); ++ci) {
00460         if ((*ci)._sfint32 < 0) {
00461           // End of poly.
00462           if (pv != _polys[pi]._verts.size()) {
00463             cerr << "texCoord indices don't match up!\n";
00464             return false;
00465           }
00466           pi++;
00467           pv = 0;
00468         } else {
00469           if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
00470             cerr << "texCoord indices don't match up!\n";
00471             return false;
00472           }
00473           _polys[pi]._verts[pv]._attrib.set_uv(uv_list[(*ci)._sfint32]);
00474           pv++;
00475         }
00476       }
00477       if (pi != _polys.size()) {
00478         cerr << "Not enough texCoord indices!\n";
00479         return false;
00480       }
00481     }
00482     return true;
00483   }
00484   return false;
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: IndexedFaceSet::assign_per_vertex_uvs
00489 //       Access: Private
00490 //  Description: Once the array of _per_vertex_uvs has been filled (by
00491 //               a broken .wrl file that indexes the uv's directly
00492 //               into the vertex array instead of per polygon vertex),
00493 //               go back through the polygons and assign the UV's by
00494 //               index number.
00495 ////////////////////////////////////////////////////////////////////
00496 void IndexedFaceSet::
00497 assign_per_vertex_uvs() {
00498   for (size_t pi = 0; pi < _polys.size(); pi++) {
00499     for (size_t pv = 0; pv < _polys[pi]._verts.size(); pv++) {
00500       VrmlVertex &vv = _polys[pi]._verts[pv];
00501       if (vv._index >= 0 && vv._index < (int)_per_vertex_uvs.size()) {
00502         const LTexCoordd &d = _per_vertex_uvs[vv._index];
00503         vv._attrib.set_uv(d);
00504       }
00505     }
00506   }
00507 }
00508 
00509 
00510 ////////////////////////////////////////////////////////////////////
00511 //     Function: IndexedFaceSet::make_polys
00512 //       Access: Private
00513 //  Description: 
00514 ////////////////////////////////////////////////////////////////////
00515 void IndexedFaceSet::
00516 make_polys(EggVertexPool *vpool, EggGroup *group, 
00517            const LMatrix4d &net_transform) {
00518   bool ccw = _geometry->get_value("ccw")._sfbool;
00519   bool solid = _geometry->get_value("solid")._sfbool;
00520 
00521   for (size_t pi = 0; pi < _polys.size(); pi++) {
00522     EggPolygon *poly = new EggPolygon;
00523     group->add_child(poly);
00524     poly->copy_attributes(_polys[pi]._attrib);
00525 
00526     if (!poly->has_color() && _appearance._has_material) {
00527       poly->set_color(_appearance._color);
00528     }
00529 
00530     if (_appearance._tex != (EggTexture *)NULL) {
00531       poly->set_texture(_appearance._tex);
00532     }
00533 
00534     if (!solid) {
00535       poly->set_bface_flag(true);
00536     }
00537 
00538     if (ccw) {
00539       // The vertices are counterclockwise, same as Egg.
00540       for (int pv = 0; pv < (int)_polys[pi]._verts.size(); pv++) {
00541         EggVertex vert(_polys[pi]._verts[pv]._attrib);
00542         LVertexd pos = 
00543           _polys[pi]._verts[pv]._pos * net_transform;
00544         vert.set_pos(pos);
00545 
00546         poly->add_vertex(vpool->create_unique_vertex(vert));
00547       }
00548     } else {
00549       // The vertices are clockwise, so add 'em in reverse order.
00550       for (int pv = (int)_polys[pi]._verts.size() - 1; pv >= 0; pv--) {
00551         EggVertex vert(_polys[pi]._verts[pv]._attrib);
00552         LVertexd pos = 
00553           _polys[pi]._verts[pv]._pos * net_transform;
00554         vert.set_pos(pos);
00555 
00556         poly->add_vertex(vpool->create_unique_vertex(vert));
00557       }
00558     }
00559   }
00560 }
00561 
00562 
00563 ////////////////////////////////////////////////////////////////////
00564 //     Function: IndexedFaceSet::compute_normals
00565 //       Access: Private
00566 //  Description: 
00567 ////////////////////////////////////////////////////////////////////
00568 void IndexedFaceSet::
00569 compute_normals(EggGroup *group) {
00570   const VrmlNode *normal = _geometry->get_value("normal")._sfnode._p;
00571   if (normal == NULL) {
00572     // Compute normals.
00573     double creaseAngle = _geometry->get_value("creaseAngle")._sffloat;
00574     if (creaseAngle == 0.0) {
00575       group->recompute_polygon_normals();
00576     } else {
00577       group->recompute_vertex_normals(rad_2_deg(creaseAngle));
00578     }
00579   }
00580 }
 All Classes Functions Variables Enumerations