Panda3D
|
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 }