Panda3D
|
00001 // Filename: xFileMesh.cxx 00002 // Created by: drose (19Jun01) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "xFileMesh.h" 00016 #include "xFileFace.h" 00017 #include "xFileVertex.h" 00018 #include "xFileNormal.h" 00019 #include "xFileMaterial.h" 00020 #include "xFileDataNode.h" 00021 #include "config_xfile.h" 00022 #include "string_utils.h" 00023 #include "eggVertexPool.h" 00024 #include "eggVertex.h" 00025 #include "eggPolygon.h" 00026 #include "eggGroupNode.h" 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: XFileMesh::Constructor 00030 // Access: Public 00031 // Description: 00032 //////////////////////////////////////////////////////////////////// 00033 XFileMesh:: 00034 XFileMesh(CoordinateSystem cs) : _cs(cs) { 00035 _has_normals = false; 00036 _has_colors = false; 00037 _has_uvs = false; 00038 _has_materials = false; 00039 _egg_parent = NULL; 00040 } 00041 00042 //////////////////////////////////////////////////////////////////// 00043 // Function: XFileMesh::Destructor 00044 // Access: Public 00045 // Description: 00046 //////////////////////////////////////////////////////////////////// 00047 XFileMesh:: 00048 ~XFileMesh() { 00049 clear(); 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: XFileMesh::clear 00054 // Access: Public 00055 // Description: Empties all data from the mesh. 00056 //////////////////////////////////////////////////////////////////// 00057 void XFileMesh:: 00058 clear() { 00059 Vertices::iterator vi; 00060 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00061 XFileVertex *vertex = (*vi); 00062 delete vertex; 00063 } 00064 Normals::iterator ni; 00065 for (ni = _normals.begin(); ni != _normals.end(); ++ni) { 00066 XFileNormal *normal = (*ni); 00067 delete normal; 00068 } 00069 Materials::iterator mi; 00070 for (mi = _materials.begin(); mi != _materials.end(); ++mi) { 00071 XFileMaterial *material = (*mi); 00072 delete material; 00073 } 00074 Faces::iterator fi; 00075 for (fi = _faces.begin(); fi != _faces.end(); ++fi) { 00076 XFileFace *face = (*fi); 00077 delete face; 00078 } 00079 00080 _vertices.clear(); 00081 _normals.clear(); 00082 _materials.clear(); 00083 _faces.clear(); 00084 00085 _unique_vertices.clear(); 00086 _unique_normals.clear(); 00087 _unique_materials.clear(); 00088 00089 _has_normals = false; 00090 _has_colors = false; 00091 _has_uvs = false; 00092 _has_materials = false; 00093 } 00094 00095 //////////////////////////////////////////////////////////////////// 00096 // Function: XFileMesh::add_polygon 00097 // Access: Public 00098 // Description: Adds the indicated polygon to the mesh. 00099 //////////////////////////////////////////////////////////////////// 00100 void XFileMesh:: 00101 add_polygon(EggPolygon *egg_poly) { 00102 XFileFace *face = new XFileFace; 00103 face->set_from_egg(this, egg_poly); 00104 _faces.push_back(face); 00105 } 00106 00107 //////////////////////////////////////////////////////////////////// 00108 // Function: XFileMesh::add_vertex 00109 // Access: Public 00110 // Description: Creates a new XFileVertex, if one does not already 00111 // exist for the indicated vertex, and returns its 00112 // index. 00113 //////////////////////////////////////////////////////////////////// 00114 int XFileMesh:: 00115 add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) { 00116 int next_index = _vertices.size(); 00117 XFileVertex *vertex = new XFileVertex; 00118 vertex->set_from_egg(egg_vertex, egg_prim); 00119 if (vertex->_has_color) { 00120 _has_colors = true; 00121 } 00122 if (vertex->_has_uv) { 00123 _has_uvs = true; 00124 } 00125 00126 pair<UniqueVertices::iterator, bool> result = 00127 _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index)); 00128 00129 if (result.second) { 00130 // Successfully added; this is a new vertex. 00131 _vertices.push_back(vertex); 00132 return next_index; 00133 } else { 00134 // Not successfully added; there is already a vertex with these 00135 // properties. Return that one instead. 00136 delete vertex; 00137 return (*result.first).second; 00138 } 00139 } 00140 00141 00142 //////////////////////////////////////////////////////////////////// 00143 // Function: XFileMesh::add_normal 00144 // Access: Public 00145 // Description: Creates a new XFileNormal, if one does not already 00146 // exist for the indicated normal, and returns its 00147 // index. 00148 //////////////////////////////////////////////////////////////////// 00149 int XFileMesh:: 00150 add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim) { 00151 int next_index = _normals.size(); 00152 XFileNormal *normal = new XFileNormal; 00153 normal->set_from_egg(egg_vertex, egg_prim); 00154 if (normal->_has_normal) { 00155 _has_normals = true; 00156 } 00157 00158 pair<UniqueNormals::iterator, bool> result = 00159 _unique_normals.insert(UniqueNormals::value_type(normal, next_index)); 00160 00161 if (result.second) { 00162 // Successfully added; this is a new normal. 00163 _normals.push_back(normal); 00164 return next_index; 00165 } else { 00166 // Not successfully added; there is already a normal with these 00167 // properties. Return that one instead. 00168 delete normal; 00169 return (*result.first).second; 00170 } 00171 } 00172 00173 //////////////////////////////////////////////////////////////////// 00174 // Function: XFileMesh::add_material 00175 // Access: Public 00176 // Description: Creates a new XFileMaterial, if one does not already 00177 // exist for the indicated material, and returns its 00178 // index. 00179 //////////////////////////////////////////////////////////////////// 00180 int XFileMesh:: 00181 add_material(EggPrimitive *egg_prim) { 00182 int next_index = _materials.size(); 00183 XFileMaterial *material = new XFileMaterial; 00184 material->set_from_egg(egg_prim); 00185 if (material->has_material()) { 00186 _has_materials = true; 00187 } 00188 00189 pair<UniqueMaterials::iterator, bool> result = 00190 _unique_materials.insert(UniqueMaterials::value_type(material, next_index)); 00191 00192 if (result.second) { 00193 // Successfully added; this is a new material. 00194 _materials.push_back(material); 00195 return next_index; 00196 } else { 00197 // Not successfully added; there is already a material with these 00198 // properties. Return that one instead. 00199 delete material; 00200 return (*result.first).second; 00201 } 00202 } 00203 00204 00205 //////////////////////////////////////////////////////////////////// 00206 // Function: XFileMesh::add_vertex 00207 // Access: Public 00208 // Description: Adds the newly-created XFileVertex unequivocally to 00209 // the mesh, returning its index number. The XFileMesh 00210 // object becomes the owner of the XFileVertex 00211 // pointer, and will delete it when it destructs. 00212 //////////////////////////////////////////////////////////////////// 00213 int XFileMesh:: 00214 add_vertex(XFileVertex *vertex) { 00215 int next_index = _vertices.size(); 00216 _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index)); 00217 _vertices.push_back(vertex); 00218 return next_index; 00219 } 00220 00221 //////////////////////////////////////////////////////////////////// 00222 // Function: XFileMesh::add_normal 00223 // Access: Public 00224 // Description: Adds the newly-created XFileNormal unequivocally to 00225 // the mesh, returning its index number. The XFileMesh 00226 // object becomes the owner of the XFileNormal 00227 // pointer, and will delete it when it destructs. 00228 //////////////////////////////////////////////////////////////////// 00229 int XFileMesh:: 00230 add_normal(XFileNormal *normal) { 00231 int next_index = _normals.size(); 00232 _unique_normals.insert(UniqueNormals::value_type(normal, next_index)); 00233 _normals.push_back(normal); 00234 return next_index; 00235 } 00236 00237 //////////////////////////////////////////////////////////////////// 00238 // Function: XFileMesh::add_material 00239 // Access: Public 00240 // Description: Adds the newly-created XFileMaterial unequivocally to 00241 // the mesh, returning its index number. The XFileMesh 00242 // object becomes the owner of the XFileMaterial 00243 // pointer, and will delete it when it destructs. 00244 //////////////////////////////////////////////////////////////////// 00245 int XFileMesh:: 00246 add_material(XFileMaterial *material) { 00247 int next_index = _materials.size(); 00248 _unique_materials.insert(UniqueMaterials::value_type(material, next_index)); 00249 _materials.push_back(material); 00250 return next_index; 00251 } 00252 00253 //////////////////////////////////////////////////////////////////// 00254 // Function: XFileMesh::set_egg_parent 00255 // Access: Public 00256 // Description: Specifies the egg node that will eventually be the 00257 // parent of this mesh, when create_polygons() is later 00258 // called. 00259 //////////////////////////////////////////////////////////////////// 00260 void XFileMesh:: 00261 set_egg_parent(EggGroupNode *egg_parent) { 00262 // We actually put the mesh under its own group. 00263 EggGroup *egg_group = new EggGroup(get_name()); 00264 egg_parent->add_child(egg_group); 00265 00266 _egg_parent = egg_group; 00267 } 00268 00269 //////////////////////////////////////////////////////////////////// 00270 // Function: XFileMesh::create_polygons 00271 // Access: Public 00272 // Description: Creates a slew of EggPolygons according to the faces 00273 // in the mesh, and adds them to the 00274 // previously-indicated parent node. 00275 //////////////////////////////////////////////////////////////////// 00276 bool XFileMesh:: 00277 create_polygons(XFileToEggConverter *converter) { 00278 nassertr(_egg_parent != (EggGroupNode *)NULL, false); 00279 00280 EggVertexPool *vpool = new EggVertexPool(get_name()); 00281 _egg_parent->add_child(vpool); 00282 Faces::const_iterator fi; 00283 for (fi = _faces.begin(); fi != _faces.end(); ++fi) { 00284 XFileFace *face = (*fi); 00285 00286 EggPolygon *egg_poly = new EggPolygon; 00287 _egg_parent->add_child(egg_poly); 00288 00289 // Set up the vertices for the polygon. 00290 XFileFace::Vertices::reverse_iterator vi; 00291 for (vi = face->_vertices.rbegin(); vi != face->_vertices.rend(); ++vi) { 00292 int vertex_index = (*vi)._vertex_index; 00293 int normal_index = (*vi)._normal_index; 00294 if (vertex_index < 0 || vertex_index >= (int)_vertices.size()) { 00295 xfile_cat.warning() 00296 << "Vertex index out of range in Mesh " << get_name() << "\n"; 00297 continue; 00298 } 00299 XFileVertex *vertex = _vertices[vertex_index]; 00300 XFileNormal *normal = (XFileNormal *)NULL; 00301 00302 if (normal_index >= 0 && normal_index < (int)_normals.size()) { 00303 normal = _normals[normal_index]; 00304 } 00305 00306 // Create a temporary EggVertex before adding it to the pool. 00307 EggVertex temp_vtx; 00308 temp_vtx.set_external_index(vertex_index); 00309 temp_vtx.set_pos(vertex->_point); 00310 if (vertex->_has_color) { 00311 temp_vtx.set_color(vertex->_color); 00312 } 00313 if (vertex->_has_uv) { 00314 LTexCoordd uv = vertex->_uv; 00315 // Windows draws the UV's upside-down. 00316 uv[1] = 1.0 - uv[1]; 00317 temp_vtx.set_uv(uv); 00318 } 00319 00320 if (normal != (XFileNormal *)NULL && normal->_has_normal) { 00321 temp_vtx.set_normal(normal->_normal); 00322 } 00323 00324 // We are given the vertex in local space; we need to transform 00325 // it into global space. If the vertex has been skinned, that 00326 // means the global space of all of its joints (modified by the 00327 // matrix_offset provided in the skinning data). 00328 double net_weight = 0.0; 00329 LMatrix4d weighted_transform(0.0, 0.0, 0.0, 0.0, 00330 0.0, 0.0, 0.0, 0.0, 00331 0.0, 0.0, 0.0, 0.0, 00332 0.0, 0.0, 0.0, 0.0); 00333 SkinWeights::const_iterator swi; 00334 for (swi = _skin_weights.begin(); swi != _skin_weights.end(); ++swi) { 00335 const SkinWeightsData &data = (*swi); 00336 WeightMap::const_iterator wmi = data._weight_map.find(vertex_index); 00337 if (wmi != data._weight_map.end()) { 00338 EggGroup *joint = converter->find_joint(data._joint_name); 00339 if (joint != (EggGroup *)NULL) { 00340 double weight = (*wmi).second; 00341 LMatrix4d mat = data._matrix_offset; 00342 mat *= joint->get_node_to_vertex(); 00343 weighted_transform += mat * weight; 00344 net_weight += weight; 00345 } 00346 } 00347 } 00348 00349 if (net_weight == 0.0) { 00350 // The vertex had no joint membership. Transform it into the 00351 // appropriate (global) space based on its parent. 00352 temp_vtx.transform(_egg_parent->get_node_to_vertex()); 00353 00354 } else { 00355 // The vertex was skinned into one or more joints. Therefore, 00356 // transform it according to the blended matrix_offset from 00357 // the skinning data. 00358 weighted_transform /= net_weight; 00359 temp_vtx.transform(weighted_transform); 00360 } 00361 00362 // Now get a real EggVertex matching our template. 00363 EggVertex *egg_vtx = vpool->create_unique_vertex(temp_vtx); 00364 egg_poly->add_vertex(egg_vtx); 00365 } 00366 00367 // And apply the material for the polygon. 00368 int material_index = face->_material_index; 00369 if (material_index >= 0 && material_index < (int)_materials.size()) { 00370 XFileMaterial *material = _materials[material_index]; 00371 material->apply_to_egg(egg_poly, converter); 00372 } 00373 } 00374 00375 // Now go through all of the vertices and skin them up. 00376 EggVertexPool::iterator vi; 00377 for (vi = vpool->begin(); vi != vpool->end(); ++vi) { 00378 EggVertex *egg_vtx = (*vi); 00379 int vertex_index = egg_vtx->get_external_index(); 00380 00381 SkinWeights::const_iterator swi; 00382 for (swi = _skin_weights.begin(); swi != _skin_weights.end(); ++swi) { 00383 const SkinWeightsData &data = (*swi); 00384 WeightMap::const_iterator wmi = data._weight_map.find(vertex_index); 00385 if (wmi != data._weight_map.end()) { 00386 EggGroup *joint = converter->find_joint(data._joint_name); 00387 if (joint != (EggGroup *)NULL) { 00388 double weight = (*wmi).second; 00389 joint->ref_vertex(egg_vtx, weight); 00390 } 00391 } 00392 } 00393 } 00394 00395 if (!has_normals()) { 00396 // If we don't have explicit normals, make some up, per the DX 00397 // spec. Since the DX spec doesn't mention anything about a 00398 // crease angle, we should be as generous as possible. 00399 _egg_parent->recompute_vertex_normals(180.0, _cs); 00400 } 00401 00402 return true; 00403 } 00404 00405 //////////////////////////////////////////////////////////////////// 00406 // Function: XFileMesh::has_normals 00407 // Access: Public 00408 // Description: Returns true if any of the vertices or faces added to 00409 // this mesh used a normal, false otherwise. 00410 //////////////////////////////////////////////////////////////////// 00411 bool XFileMesh:: 00412 has_normals() const { 00413 return _has_normals; 00414 } 00415 00416 //////////////////////////////////////////////////////////////////// 00417 // Function: XFileMesh::has_colors 00418 // Access: Public 00419 // Description: Returns true if any of the vertices or faces added to 00420 // this mesh used a color, false otherwise. 00421 //////////////////////////////////////////////////////////////////// 00422 bool XFileMesh:: 00423 has_colors() const { 00424 return _has_colors; 00425 } 00426 00427 //////////////////////////////////////////////////////////////////// 00428 // Function: XFileMesh::has_uvs 00429 // Access: Public 00430 // Description: Returns true if any of the vertices added to this 00431 // mesh used a texture coordinate, false otherwise. 00432 //////////////////////////////////////////////////////////////////// 00433 bool XFileMesh:: 00434 has_uvs() const { 00435 return _has_uvs; 00436 } 00437 00438 //////////////////////////////////////////////////////////////////// 00439 // Function: XFileMesh::has_materials 00440 // Access: Public 00441 // Description: Returns true if any of the faces added to this mesh 00442 // used a real material, false otherwise. 00443 //////////////////////////////////////////////////////////////////// 00444 bool XFileMesh:: 00445 has_materials() const { 00446 return _has_materials; 00447 } 00448 00449 //////////////////////////////////////////////////////////////////// 00450 // Function: XFileMesh::get_num_materials 00451 // Access: Public 00452 // Description: Returns the number of distinct materials associated 00453 // with the mesh. 00454 //////////////////////////////////////////////////////////////////// 00455 int XFileMesh:: 00456 get_num_materials() const { 00457 return _materials.size(); 00458 } 00459 00460 //////////////////////////////////////////////////////////////////// 00461 // Function: XFileMesh::get_material 00462 // Access: Public 00463 // Description: Returns a pointer to the nth materials associated 00464 // with the mesh. 00465 //////////////////////////////////////////////////////////////////// 00466 XFileMaterial *XFileMesh:: 00467 get_material(int n) const { 00468 nassertr(n >= 0 && n < (int)_materials.size(), (XFileMaterial *)NULL); 00469 return _materials[n]; 00470 } 00471 00472 //////////////////////////////////////////////////////////////////// 00473 // Function: XFileMesh::make_x_mesh 00474 // Access: Public 00475 // Description: Creates an X structure corresponding to the mesh. 00476 //////////////////////////////////////////////////////////////////// 00477 XFileDataNode *XFileMesh:: 00478 make_x_mesh(XFileNode *x_parent, const string &suffix) { 00479 XFileDataNode *x_mesh = x_parent->add_Mesh("mesh" + suffix); 00480 00481 // First, fill in the table of vertices. 00482 XFileDataObject &x_vertices = (*x_mesh)["vertices"]; 00483 00484 Vertices::const_iterator vi; 00485 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00486 XFileVertex *vertex = (*vi); 00487 x_vertices.add_Vector(x_mesh->get_x_file(), vertex->_point); 00488 } 00489 (*x_mesh)["nVertices"] = x_vertices.size(); 00490 00491 // Then, create the list of faces that index into the above vertices. 00492 XFileDataObject &x_faces = (*x_mesh)["faces"]; 00493 Faces::const_iterator fi; 00494 for (fi = _faces.begin(); fi != _faces.end(); ++fi) { 00495 XFileFace *face = (*fi); 00496 00497 XFileDataObject &x_mesh_face = x_faces.add_MeshFace(x_mesh->get_x_file()); 00498 XFileDataObject &x_faceVertexIndices = x_mesh_face["faceVertexIndices"]; 00499 XFileFace::Vertices::const_iterator fvi; 00500 for (fvi = face->_vertices.begin(); 00501 fvi != face->_vertices.end(); 00502 ++fvi) { 00503 x_faceVertexIndices.add_int((*fvi)._vertex_index); 00504 } 00505 x_mesh_face["nFaceVertexIndices"] = x_faceVertexIndices.size(); 00506 } 00507 (*x_mesh)["nFaces"] = x_faces.size(); 00508 00509 // Now, add in any supplemental data. 00510 00511 if (has_normals()) { 00512 // Tack on normals. 00513 make_x_normals(x_mesh, suffix); 00514 } 00515 if (has_colors()) { 00516 // Tack on colors. 00517 make_x_colors(x_mesh, suffix); 00518 } 00519 if (has_uvs()) { 00520 // Tack on uvs. 00521 make_x_uvs(x_mesh, suffix); 00522 } 00523 if (has_materials()) { 00524 // Tack on materials. 00525 make_x_material_list(x_mesh, suffix); 00526 } 00527 00528 return x_mesh; 00529 } 00530 00531 //////////////////////////////////////////////////////////////////// 00532 // Function: XFileMesh::make_x_normals 00533 // Access: Public 00534 // Description: Creates a MeshNormals table for the mesh. 00535 //////////////////////////////////////////////////////////////////// 00536 XFileDataNode *XFileMesh:: 00537 make_x_normals(XFileNode *x_mesh, const string &suffix) { 00538 XFileDataNode *x_meshNormals = x_mesh->add_MeshNormals("norms" + suffix); 00539 00540 XFileDataObject &x_normals = (*x_meshNormals)["normals"]; 00541 00542 Normals::const_iterator ni; 00543 for (ni = _normals.begin(); ni != _normals.end(); ++ni) { 00544 XFileNormal *normal = (*ni); 00545 x_normals.add_Vector(x_mesh->get_x_file(), normal->_normal); 00546 } 00547 (*x_meshNormals)["nNormals"] = x_normals.size(); 00548 00549 // Then, create the list of faces that index into the above normals. 00550 XFileDataObject &x_faces = (*x_meshNormals)["faceNormals"]; 00551 Faces::const_iterator fi; 00552 for (fi = _faces.begin(); fi != _faces.end(); ++fi) { 00553 XFileFace *face = (*fi); 00554 00555 XFileDataObject &x_normals_face = x_faces.add_MeshFace(x_mesh->get_x_file()); 00556 XFileDataObject &x_faceVertexIndices = x_normals_face["faceVertexIndices"]; 00557 XFileFace::Vertices::const_iterator fvi; 00558 for (fvi = face->_vertices.begin(); 00559 fvi != face->_vertices.end(); 00560 ++fvi) { 00561 x_faceVertexIndices.add_int((*fvi)._normal_index); 00562 } 00563 x_normals_face["nFaceVertexIndices"] = x_faceVertexIndices.size(); 00564 } 00565 (*x_meshNormals)["nFaceNormals"] = x_faces.size(); 00566 00567 return x_meshNormals; 00568 } 00569 00570 //////////////////////////////////////////////////////////////////// 00571 // Function: XFileMesh::make_x_colors 00572 // Access: Public 00573 // Description: Creates a MeshVertexColors table for the mesh. 00574 //////////////////////////////////////////////////////////////////// 00575 XFileDataNode *XFileMesh:: 00576 make_x_colors(XFileNode *x_mesh, const string &suffix) { 00577 XFileDataNode *x_meshColors = x_mesh->add_MeshVertexColors("colors" + suffix); 00578 00579 XFileDataObject &x_colors = (*x_meshColors)["vertexColors"]; 00580 00581 Vertices::const_iterator vi; 00582 int i = 0; 00583 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00584 XFileVertex *vertex = (*vi); 00585 const LColor &color = vertex->_color; 00586 x_colors.add_IndexedColor(x_mesh->get_x_file(), i, color); 00587 i++; 00588 } 00589 00590 (*x_meshColors)["nVertexColors"] = x_colors.size(); 00591 00592 return x_meshColors; 00593 } 00594 00595 //////////////////////////////////////////////////////////////////// 00596 // Function: XFileMesh::make_x_uvs 00597 // Access: Public 00598 // Description: Creates a MeshTextureCoords table for the mesh. 00599 //////////////////////////////////////////////////////////////////// 00600 XFileDataNode *XFileMesh:: 00601 make_x_uvs(XFileNode *x_mesh, const string &suffix) { 00602 XFileDataNode *x_meshUvs = x_mesh->add_MeshTextureCoords("uvs" + suffix); 00603 00604 XFileDataObject &x_uvs = (*x_meshUvs)["textureCoords"]; 00605 00606 Vertices::const_iterator vi; 00607 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { 00608 XFileVertex *vertex = (*vi); 00609 x_uvs.add_Coords2d(x_mesh->get_x_file(), vertex->_uv); 00610 } 00611 00612 (*x_meshUvs)["nTextureCoords"] = x_uvs.size(); 00613 00614 return x_meshUvs; 00615 } 00616 00617 //////////////////////////////////////////////////////////////////// 00618 // Function: XFileMesh::make_x_material_list 00619 // Access: Public 00620 // Description: Creates a MeshMaterialList table for the mesh. 00621 //////////////////////////////////////////////////////////////////// 00622 XFileDataNode *XFileMesh:: 00623 make_x_material_list(XFileNode *x_mesh, const string &suffix) { 00624 XFileDataNode *x_meshMaterials = 00625 x_mesh->add_MeshMaterialList("materials" + suffix); 00626 00627 // First, build up the list of faces the reference the materials. 00628 XFileDataObject &x_indexes = (*x_meshMaterials)["faceIndexes"]; 00629 00630 Faces::const_iterator fi; 00631 for (fi = _faces.begin(); fi != _faces.end(); ++fi) { 00632 XFileFace *face = (*fi); 00633 x_indexes.add_int(face->_material_index); 00634 } 00635 00636 (*x_meshMaterials)["nFaceIndexes"] = x_indexes.size(); 00637 00638 // Now, build up the list of materials themselves. Each material is 00639 // a child of the MeshMaterialList node, rather than an element of 00640 // an array. 00641 for (size_t i = 0; i < _materials.size(); i++) { 00642 XFileMaterial *material = _materials[i]; 00643 00644 material->make_x_material(x_meshMaterials, 00645 suffix + "_" + format_string(i)); 00646 } 00647 00648 (*x_meshMaterials)["nMaterials"] = (int)_materials.size(); 00649 00650 return x_meshMaterials; 00651 } 00652 00653 //////////////////////////////////////////////////////////////////// 00654 // Function: XFileMesh::fill_mesh 00655 // Access: Public 00656 // Description: Fills the structure based on the raw data from the 00657 // X file's Mesh object. 00658 //////////////////////////////////////////////////////////////////// 00659 bool XFileMesh:: 00660 fill_mesh(XFileDataNode *obj) { 00661 clear(); 00662 00663 int i, j; 00664 00665 const XFileDataObject &vertices = (*obj)["vertices"]; 00666 for (i = 0; i < vertices.size(); i++) { 00667 XFileVertex *vertex = new XFileVertex; 00668 vertex->_point = vertices[i].vec3(); 00669 add_vertex(vertex); 00670 } 00671 00672 const XFileDataObject &faces = (*obj)["faces"]; 00673 for (i = 0; i < faces.size(); i++) { 00674 XFileFace *face = new XFileFace; 00675 00676 const XFileDataObject &faceIndices = faces[i]["faceVertexIndices"]; 00677 00678 for (j = 0; j < faceIndices.size(); j++) { 00679 XFileFace::Vertex vertex; 00680 vertex._vertex_index = faceIndices[j].i(); 00681 vertex._normal_index = -1; 00682 00683 face->_vertices.push_back(vertex); 00684 } 00685 _faces.push_back(face); 00686 } 00687 00688 // Some properties are stored as children of the mesh. 00689 int num_objects = obj->get_num_objects(); 00690 for (i = 0; i < num_objects; i++) { 00691 if (!fill_mesh_child(obj->get_object(i))) { 00692 return false; 00693 } 00694 } 00695 00696 return true; 00697 } 00698 00699 //////////////////////////////////////////////////////////////////// 00700 // Function: XFileMesh::fill_mesh_child 00701 // Access: Public 00702 // Description: Fills the structure based on one of the children of 00703 // the Mesh object. 00704 //////////////////////////////////////////////////////////////////// 00705 bool XFileMesh:: 00706 fill_mesh_child(XFileDataNode *obj) { 00707 if (obj->is_standard_object("MeshNormals")) { 00708 if (!fill_normals(obj)) { 00709 return false; 00710 } 00711 00712 } else if (obj->is_standard_object("MeshVertexColors")) { 00713 if (!fill_colors(obj)) { 00714 return false; 00715 } 00716 00717 } else if (obj->is_standard_object("MeshTextureCoords")) { 00718 if (!fill_uvs(obj)) { 00719 return false; 00720 } 00721 00722 } else if (obj->is_standard_object("MeshMaterialList")) { 00723 if (!fill_material_list(obj)) { 00724 return false; 00725 } 00726 00727 } else if (obj->is_standard_object("XSkinMeshHeader")) { 00728 // Quietly ignore a skin mesh header. 00729 00730 } else if (obj->is_standard_object("SkinWeights")) { 00731 if (!fill_skin_weights(obj)) { 00732 return false; 00733 } 00734 00735 } else { 00736 if (xfile_cat.is_debug()) { 00737 xfile_cat.debug() 00738 << "Ignoring mesh data object of unknown type: " 00739 << obj->get_template_name() << "\n"; 00740 } 00741 } 00742 00743 return true; 00744 } 00745 00746 //////////////////////////////////////////////////////////////////// 00747 // Function: XFileMesh::fill_normals 00748 // Access: Public 00749 // Description: Fills the structure based on the raw data from the 00750 // MeshNormals template. 00751 //////////////////////////////////////////////////////////////////// 00752 bool XFileMesh:: 00753 fill_normals(XFileDataNode *obj) { 00754 int i, j; 00755 00756 const XFileDataObject &normals = (*obj)["normals"]; 00757 for (i = 0; i < normals.size(); i++) { 00758 XFileNormal *normal = new XFileNormal; 00759 normal->_normal = normals[i].vec3(); 00760 normal->_has_normal = true; 00761 add_normal(normal); 00762 } 00763 00764 const XFileDataObject &faceNormals = (*obj)["faceNormals"]; 00765 if (faceNormals.size() != (int)_faces.size()) { 00766 xfile_cat.warning() 00767 << "Incorrect number of faces in MeshNormals within " 00768 << get_name() << "\n"; 00769 } 00770 00771 int num_normals = min(faceNormals.size(), (int)_faces.size()); 00772 for (i = 0; i < num_normals; i++) { 00773 XFileFace *face = _faces[i]; 00774 00775 const XFileDataObject &faceIndices = faceNormals[i]["faceVertexIndices"]; 00776 00777 if (faceIndices.size() != (int)face->_vertices.size()) { 00778 xfile_cat.warning() 00779 << "Incorrect number of vertices for face in MeshNormals within " 00780 << get_name() << "\n"; 00781 } 00782 00783 int num_vertices = min(faceIndices.size(), (int)face->_vertices.size()); 00784 for (j = 0; j < num_vertices; j++) { 00785 face->_vertices[j]._normal_index = faceIndices[j].i(); 00786 } 00787 } 00788 00789 return true; 00790 } 00791 00792 //////////////////////////////////////////////////////////////////// 00793 // Function: XFileMesh::fill_colors 00794 // Access: Public 00795 // Description: Fills the structure based on the raw data from the 00796 // MeshVertexColors template. 00797 //////////////////////////////////////////////////////////////////// 00798 bool XFileMesh:: 00799 fill_colors(XFileDataNode *obj) { 00800 const XFileDataObject &vertexColors = (*obj)["vertexColors"]; 00801 for (int i = 0; i < vertexColors.size(); i++) { 00802 int vertex_index = vertexColors[i]["index"].i(); 00803 if (vertex_index < 0 || vertex_index >= (int)_vertices.size()) { 00804 xfile_cat.warning() 00805 << "Vertex index out of range in MeshVertexColors within " 00806 << get_name() << "\n"; 00807 continue; 00808 } 00809 00810 XFileVertex *vertex = _vertices[vertex_index]; 00811 vertex->_color = LCAST(PN_stdfloat, vertexColors[i]["indexColor"].vec4()); 00812 vertex->_has_color = true; 00813 } 00814 00815 return true; 00816 } 00817 00818 //////////////////////////////////////////////////////////////////// 00819 // Function: XFileMesh::fill_uvs 00820 // Access: Public 00821 // Description: Fills the structure based on the raw data from the 00822 // MeshTextureCoords template. 00823 //////////////////////////////////////////////////////////////////// 00824 bool XFileMesh:: 00825 fill_uvs(XFileDataNode *obj) { 00826 const XFileDataObject &textureCoords = (*obj)["textureCoords"]; 00827 if (textureCoords.size() != (int)_vertices.size()) { 00828 xfile_cat.warning() 00829 << "Wrong number of vertices in MeshTextureCoords within " 00830 << get_name() << "\n"; 00831 } 00832 00833 int num_texcoords = min(textureCoords.size(), (int)_vertices.size()); 00834 for (int i = 0; i < num_texcoords; i++) { 00835 XFileVertex *vertex = _vertices[i]; 00836 vertex->_uv = textureCoords[i].vec2(); 00837 vertex->_has_uv = true; 00838 } 00839 00840 return true; 00841 } 00842 00843 //////////////////////////////////////////////////////////////////// 00844 // Function: XFileMesh::fill_skin_weights 00845 // Access: Public 00846 // Description: Fills the structure based on the raw data from the 00847 // SkinWeights template. 00848 //////////////////////////////////////////////////////////////////// 00849 bool XFileMesh:: 00850 fill_skin_weights(XFileDataNode *obj) { 00851 // Create a new SkinWeightsData record for the table. We'll need 00852 // this data later when we create the vertices. 00853 _skin_weights.push_back(SkinWeightsData()); 00854 SkinWeightsData &data = _skin_weights.back(); 00855 00856 data._joint_name = (*obj)["transformNodeName"].s(); 00857 00858 const XFileDataObject &vertexIndices = (*obj)["vertexIndices"]; 00859 const XFileDataObject &weights = (*obj)["weights"]; 00860 00861 if (weights.size() != vertexIndices.size()) { 00862 xfile_cat.warning() 00863 << "Inconsistent number of vertices in SkinWeights within " << get_name() << "\n"; 00864 } 00865 00866 // Unpack the weight for each vertex. 00867 size_t num_weights = min(weights.size(), vertexIndices.size()); 00868 for (size_t i = 0; i < num_weights; i++) { 00869 int vindex = vertexIndices[i].i(); 00870 double weight = weights[i].d(); 00871 00872 if (vindex < 0 || vindex > (int)_vertices.size()) { 00873 xfile_cat.warning() 00874 << "Illegal vertex index " << vindex << " in SkinWeights.\n"; 00875 continue; 00876 } 00877 data._weight_map[vindex] = weight; 00878 } 00879 00880 // Also retrieve the matrix offset. 00881 data._matrix_offset = (*obj)["matrixOffset"]["matrix"].mat4(); 00882 00883 return true; 00884 } 00885 00886 //////////////////////////////////////////////////////////////////// 00887 // Function: XFileMesh::fill_material_list 00888 // Access: Public 00889 // Description: Fills the structure based on the raw data from the 00890 // MeshMaterialList template. 00891 //////////////////////////////////////////////////////////////////// 00892 bool XFileMesh:: 00893 fill_material_list(XFileDataNode *obj) { 00894 const XFileDataObject &faceIndexes = (*obj)["faceIndexes"]; 00895 if (faceIndexes.size() > (int)_faces.size()) { 00896 xfile_cat.warning() 00897 << "Too many faces in MeshMaterialList within " << get_name() << "\n"; 00898 } 00899 00900 int material_index = -1; 00901 int i = 0; 00902 while (i < faceIndexes.size() && i < (int)_faces.size()) { 00903 XFileFace *face = _faces[i]; 00904 material_index = faceIndexes[i].i(); 00905 face->_material_index = material_index; 00906 i++; 00907 } 00908 00909 // The rest of the faces get the same material index as the last 00910 // one in the list. 00911 while (i < (int)_faces.size()) { 00912 XFileFace *face = _faces[i]; 00913 face->_material_index = material_index; 00914 i++; 00915 } 00916 00917 // Now look for children of the MaterialList object. These should 00918 // all be Material objects. 00919 int num_objects = obj->get_num_objects(); 00920 for (i = 0; i < num_objects; i++) { 00921 XFileDataNode *child = obj->get_object(i); 00922 if (child->is_standard_object("Material")) { 00923 XFileMaterial *material = new XFileMaterial; 00924 if (!material->fill_material(child)) { 00925 delete material; 00926 return false; 00927 } 00928 add_material(material); 00929 00930 } else { 00931 if (xfile_cat.is_debug()) { 00932 xfile_cat.debug() 00933 << "Ignoring material list object of unknown type: " 00934 << child->get_template_name() << "\n"; 00935 } 00936 } 00937 } 00938 00939 return true; 00940 }