Panda3D
 All Classes Functions Variables Enumerations
xFileMesh.cxx
1 // Filename: xFileMesh.cxx
2 // Created by: drose (19Jun01)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "xFileMesh.h"
16 #include "xFileFace.h"
17 #include "xFileVertex.h"
18 #include "xFileNormal.h"
19 #include "xFileMaterial.h"
20 #include "xFileDataNode.h"
21 #include "config_xfile.h"
22 #include "string_utils.h"
23 #include "eggVertexPool.h"
24 #include "eggVertex.h"
25 #include "eggPolygon.h"
26 #include "eggGroupNode.h"
27 
28 ////////////////////////////////////////////////////////////////////
29 // Function: XFileMesh::Constructor
30 // Access: Public
31 // Description:
32 ////////////////////////////////////////////////////////////////////
33 XFileMesh::
34 XFileMesh(CoordinateSystem cs) : _cs(cs) {
35  _has_normals = false;
36  _has_colors = false;
37  _has_uvs = false;
38  _has_materials = false;
39  _egg_parent = NULL;
40 }
41 
42 ////////////////////////////////////////////////////////////////////
43 // Function: XFileMesh::Destructor
44 // Access: Public
45 // Description:
46 ////////////////////////////////////////////////////////////////////
47 XFileMesh::
48 ~XFileMesh() {
49  clear();
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: XFileMesh::clear
54 // Access: Public
55 // Description: Empties all data from the mesh.
56 ////////////////////////////////////////////////////////////////////
57 void XFileMesh::
58 clear() {
59  Vertices::iterator vi;
60  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
61  XFileVertex *vertex = (*vi);
62  delete vertex;
63  }
64  Normals::iterator ni;
65  for (ni = _normals.begin(); ni != _normals.end(); ++ni) {
66  XFileNormal *normal = (*ni);
67  delete normal;
68  }
69  Materials::iterator mi;
70  for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
71  XFileMaterial *material = (*mi);
72  delete material;
73  }
74  Faces::iterator fi;
75  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
76  XFileFace *face = (*fi);
77  delete face;
78  }
79 
80  _vertices.clear();
81  _normals.clear();
82  _materials.clear();
83  _faces.clear();
84 
85  _unique_vertices.clear();
86  _unique_normals.clear();
87  _unique_materials.clear();
88 
89  _has_normals = false;
90  _has_colors = false;
91  _has_uvs = false;
92  _has_materials = false;
93 }
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: XFileMesh::add_polygon
97 // Access: Public
98 // Description: Adds the indicated polygon to the mesh.
99 ////////////////////////////////////////////////////////////////////
100 void XFileMesh::
102  XFileFace *face = new XFileFace;
103  face->set_from_egg(this, egg_poly);
104  _faces.push_back(face);
105 }
106 
107 ////////////////////////////////////////////////////////////////////
108 // Function: XFileMesh::add_vertex
109 // Access: Public
110 // Description: Creates a new XFileVertex, if one does not already
111 // exist for the indicated vertex, and returns its
112 // index.
113 ////////////////////////////////////////////////////////////////////
114 int XFileMesh::
115 add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
116  int next_index = _vertices.size();
117  XFileVertex *vertex = new XFileVertex;
118  vertex->set_from_egg(egg_vertex, egg_prim);
119  if (vertex->_has_color) {
120  _has_colors = true;
121  }
122  if (vertex->_has_uv) {
123  _has_uvs = true;
124  }
125 
126  pair<UniqueVertices::iterator, bool> result =
127  _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index));
128 
129  if (result.second) {
130  // Successfully added; this is a new vertex.
131  _vertices.push_back(vertex);
132  return next_index;
133  } else {
134  // Not successfully added; there is already a vertex with these
135  // properties. Return that one instead.
136  delete vertex;
137  return (*result.first).second;
138  }
139 }
140 
141 
142 ////////////////////////////////////////////////////////////////////
143 // Function: XFileMesh::add_normal
144 // Access: Public
145 // Description: Creates a new XFileNormal, if one does not already
146 // exist for the indicated normal, and returns its
147 // index.
148 ////////////////////////////////////////////////////////////////////
149 int XFileMesh::
150 add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
151  int next_index = _normals.size();
152  XFileNormal *normal = new XFileNormal;
153  normal->set_from_egg(egg_vertex, egg_prim);
154  if (normal->_has_normal) {
155  _has_normals = true;
156  }
157 
158  pair<UniqueNormals::iterator, bool> result =
159  _unique_normals.insert(UniqueNormals::value_type(normal, next_index));
160 
161  if (result.second) {
162  // Successfully added; this is a new normal.
163  _normals.push_back(normal);
164  return next_index;
165  } else {
166  // Not successfully added; there is already a normal with these
167  // properties. Return that one instead.
168  delete normal;
169  return (*result.first).second;
170  }
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: XFileMesh::add_material
175 // Access: Public
176 // Description: Creates a new XFileMaterial, if one does not already
177 // exist for the indicated material, and returns its
178 // index.
179 ////////////////////////////////////////////////////////////////////
180 int XFileMesh::
182  int next_index = _materials.size();
183  XFileMaterial *material = new XFileMaterial;
184  material->set_from_egg(egg_prim);
185  if (material->has_material()) {
186  _has_materials = true;
187  }
188 
189  pair<UniqueMaterials::iterator, bool> result =
190  _unique_materials.insert(UniqueMaterials::value_type(material, next_index));
191 
192  if (result.second) {
193  // Successfully added; this is a new material.
194  _materials.push_back(material);
195  return next_index;
196  } else {
197  // Not successfully added; there is already a material with these
198  // properties. Return that one instead.
199  delete material;
200  return (*result.first).second;
201  }
202 }
203 
204 
205 ////////////////////////////////////////////////////////////////////
206 // Function: XFileMesh::add_vertex
207 // Access: Public
208 // Description: Adds the newly-created XFileVertex unequivocally to
209 // the mesh, returning its index number. The XFileMesh
210 // object becomes the owner of the XFileVertex
211 // pointer, and will delete it when it destructs.
212 ////////////////////////////////////////////////////////////////////
213 int XFileMesh::
215  if (vertex->_has_color) {
216  _has_colors = true;
217  }
218  if (vertex->_has_uv) {
219  _has_uvs = true;
220  }
221 
222  int next_index = _vertices.size();
223  _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index));
224  _vertices.push_back(vertex);
225  return next_index;
226 }
227 
228 ////////////////////////////////////////////////////////////////////
229 // Function: XFileMesh::add_normal
230 // Access: Public
231 // Description: Adds the newly-created XFileNormal unequivocally to
232 // the mesh, returning its index number. The XFileMesh
233 // object becomes the owner of the XFileNormal
234 // pointer, and will delete it when it destructs.
235 ////////////////////////////////////////////////////////////////////
236 int XFileMesh::
238  if (normal->_has_normal) {
239  _has_normals = true;
240  }
241 
242  int next_index = _normals.size();
243  _unique_normals.insert(UniqueNormals::value_type(normal, next_index));
244  _normals.push_back(normal);
245  return next_index;
246 }
247 
248 ////////////////////////////////////////////////////////////////////
249 // Function: XFileMesh::add_material
250 // Access: Public
251 // Description: Adds the newly-created XFileMaterial unequivocally to
252 // the mesh, returning its index number. The XFileMesh
253 // object becomes the owner of the XFileMaterial
254 // pointer, and will delete it when it destructs.
255 ////////////////////////////////////////////////////////////////////
256 int XFileMesh::
258  if (material->has_material()) {
259  _has_materials = true;
260  }
261 
262  int next_index = _materials.size();
263  _unique_materials.insert(UniqueMaterials::value_type(material, next_index));
264  _materials.push_back(material);
265  return next_index;
266 }
267 
268 ////////////////////////////////////////////////////////////////////
269 // Function: XFileMesh::set_egg_parent
270 // Access: Public
271 // Description: Specifies the egg node that will eventually be the
272 // parent of this mesh, when create_polygons() is later
273 // called.
274 ////////////////////////////////////////////////////////////////////
275 void XFileMesh::
277  // We actually put the mesh under its own group.
278  EggGroup *egg_group = new EggGroup(get_name());
279  egg_parent->add_child(egg_group);
280 
281  _egg_parent = egg_group;
282 }
283 
284 ////////////////////////////////////////////////////////////////////
285 // Function: XFileMesh::create_polygons
286 // Access: Public
287 // Description: Creates a slew of EggPolygons according to the faces
288 // in the mesh, and adds them to the
289 // previously-indicated parent node.
290 ////////////////////////////////////////////////////////////////////
291 bool XFileMesh::
293  nassertr(_egg_parent != (EggGroupNode *)NULL, false);
294 
295  EggVertexPool *vpool = new EggVertexPool(get_name());
296  _egg_parent->add_child(vpool);
297  Faces::const_iterator fi;
298  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
299  XFileFace *face = (*fi);
300 
301  EggPolygon *egg_poly = new EggPolygon;
302  _egg_parent->add_child(egg_poly);
303 
304  // Set up the vertices for the polygon.
305  XFileFace::Vertices::reverse_iterator vi;
306  for (vi = face->_vertices.rbegin(); vi != face->_vertices.rend(); ++vi) {
307  int vertex_index = (*vi)._vertex_index;
308  int normal_index = (*vi)._normal_index;
309  if (vertex_index < 0 || vertex_index >= (int)_vertices.size()) {
310  xfile_cat.warning()
311  << "Vertex index out of range in Mesh " << get_name() << "\n";
312  continue;
313  }
314  XFileVertex *vertex = _vertices[vertex_index];
315  XFileNormal *normal = (XFileNormal *)NULL;
316 
317  if (normal_index >= 0 && normal_index < (int)_normals.size()) {
318  normal = _normals[normal_index];
319  }
320 
321  // Create a temporary EggVertex before adding it to the pool.
322  EggVertex temp_vtx;
323  temp_vtx.set_external_index(vertex_index);
324  temp_vtx.set_pos(vertex->_point);
325  if (vertex->_has_color) {
326  temp_vtx.set_color(vertex->_color);
327  }
328  if (vertex->_has_uv) {
329  LTexCoordd uv = vertex->_uv;
330  // Windows draws the UV's upside-down.
331  uv[1] = 1.0 - uv[1];
332  temp_vtx.set_uv(uv);
333  }
334 
335  if (normal != (XFileNormal *)NULL && normal->_has_normal) {
336  temp_vtx.set_normal(normal->_normal);
337  }
338 
339  // We are given the vertex in local space; we need to transform
340  // it into global space. If the vertex has been skinned, that
341  // means the global space of all of its joints (modified by the
342  // matrix_offset provided in the skinning data).
343  double net_weight = 0.0;
344  LMatrix4d weighted_transform(0.0, 0.0, 0.0, 0.0,
345  0.0, 0.0, 0.0, 0.0,
346  0.0, 0.0, 0.0, 0.0,
347  0.0, 0.0, 0.0, 0.0);
348  SkinWeights::const_iterator swi;
349  for (swi = _skin_weights.begin(); swi != _skin_weights.end(); ++swi) {
350  const SkinWeightsData &data = (*swi);
351  WeightMap::const_iterator wmi = data._weight_map.find(vertex_index);
352  if (wmi != data._weight_map.end()) {
353  EggGroup *joint = converter->find_joint(data._joint_name);
354  if (joint != (EggGroup *)NULL) {
355  double weight = (*wmi).second;
356  LMatrix4d mat = data._matrix_offset;
357  mat *= joint->get_node_to_vertex();
358  weighted_transform += mat * weight;
359  net_weight += weight;
360  }
361  }
362  }
363 
364  if (net_weight == 0.0) {
365  // The vertex had no joint membership. Transform it into the
366  // appropriate (global) space based on its parent.
367  temp_vtx.transform(_egg_parent->get_node_to_vertex());
368 
369  } else {
370  // The vertex was skinned into one or more joints. Therefore,
371  // transform it according to the blended matrix_offset from
372  // the skinning data.
373  weighted_transform /= net_weight;
374  temp_vtx.transform(weighted_transform);
375  }
376 
377  // Now get a real EggVertex matching our template.
378  EggVertex *egg_vtx = vpool->create_unique_vertex(temp_vtx);
379  egg_poly->add_vertex(egg_vtx);
380  }
381 
382  // And apply the material for the polygon.
383  int material_index = face->_material_index;
384  if (material_index >= 0 && material_index < (int)_materials.size()) {
385  XFileMaterial *material = _materials[material_index];
386  material->apply_to_egg(egg_poly, converter);
387  }
388  }
389 
390  // Now go through all of the vertices and skin them up.
392  for (vi = vpool->begin(); vi != vpool->end(); ++vi) {
393  EggVertex *egg_vtx = (*vi);
394  int vertex_index = egg_vtx->get_external_index();
395 
396  SkinWeights::const_iterator swi;
397  for (swi = _skin_weights.begin(); swi != _skin_weights.end(); ++swi) {
398  const SkinWeightsData &data = (*swi);
399  WeightMap::const_iterator wmi = data._weight_map.find(vertex_index);
400  if (wmi != data._weight_map.end()) {
401  EggGroup *joint = converter->find_joint(data._joint_name);
402  if (joint != (EggGroup *)NULL) {
403  double weight = (*wmi).second;
404  joint->ref_vertex(egg_vtx, weight);
405  }
406  }
407  }
408  }
409 
410  if (!has_normals()) {
411  // If we don't have explicit normals, make some up, per the DX
412  // spec. Since the DX spec doesn't mention anything about a
413  // crease angle, we should be as generous as possible.
414  _egg_parent->recompute_vertex_normals(180.0, _cs);
415  }
416 
417  return true;
418 }
419 
420 ////////////////////////////////////////////////////////////////////
421 // Function: XFileMesh::has_normals
422 // Access: Public
423 // Description: Returns true if any of the vertices or faces added to
424 // this mesh used a normal, false otherwise.
425 ////////////////////////////////////////////////////////////////////
426 bool XFileMesh::
427 has_normals() const {
428  return _has_normals;
429 }
430 
431 ////////////////////////////////////////////////////////////////////
432 // Function: XFileMesh::has_colors
433 // Access: Public
434 // Description: Returns true if any of the vertices or faces added to
435 // this mesh used a color, false otherwise.
436 ////////////////////////////////////////////////////////////////////
437 bool XFileMesh::
438 has_colors() const {
439  return _has_colors;
440 }
441 
442 ////////////////////////////////////////////////////////////////////
443 // Function: XFileMesh::has_uvs
444 // Access: Public
445 // Description: Returns true if any of the vertices added to this
446 // mesh used a texture coordinate, false otherwise.
447 ////////////////////////////////////////////////////////////////////
448 bool XFileMesh::
449 has_uvs() const {
450  return _has_uvs;
451 }
452 
453 ////////////////////////////////////////////////////////////////////
454 // Function: XFileMesh::has_materials
455 // Access: Public
456 // Description: Returns true if any of the faces added to this mesh
457 // used a real material, false otherwise.
458 ////////////////////////////////////////////////////////////////////
459 bool XFileMesh::
460 has_materials() const {
461  return _has_materials;
462 }
463 
464 ////////////////////////////////////////////////////////////////////
465 // Function: XFileMesh::get_num_materials
466 // Access: Public
467 // Description: Returns the number of distinct materials associated
468 // with the mesh.
469 ////////////////////////////////////////////////////////////////////
470 int XFileMesh::
472  return _materials.size();
473 }
474 
475 ////////////////////////////////////////////////////////////////////
476 // Function: XFileMesh::get_material
477 // Access: Public
478 // Description: Returns a pointer to the nth materials associated
479 // with the mesh.
480 ////////////////////////////////////////////////////////////////////
482 get_material(int n) const {
483  nassertr(n >= 0 && n < (int)_materials.size(), (XFileMaterial *)NULL);
484  return _materials[n];
485 }
486 
487 ////////////////////////////////////////////////////////////////////
488 // Function: XFileMesh::make_x_mesh
489 // Access: Public
490 // Description: Creates an X structure corresponding to the mesh.
491 ////////////////////////////////////////////////////////////////////
493 make_x_mesh(XFileNode *x_parent, const string &suffix) {
494  XFileDataNode *x_mesh = x_parent->add_Mesh("mesh" + suffix);
495 
496  // First, fill in the table of vertices.
497  XFileDataObject &x_vertices = (*x_mesh)["vertices"];
498 
499  Vertices::const_iterator vi;
500  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
501  XFileVertex *vertex = (*vi);
502  x_vertices.add_Vector(x_mesh->get_x_file(), vertex->_point);
503  }
504  (*x_mesh)["nVertices"] = x_vertices.size();
505 
506  // Then, create the list of faces that index into the above vertices.
507  XFileDataObject &x_faces = (*x_mesh)["faces"];
508  Faces::const_iterator fi;
509  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
510  XFileFace *face = (*fi);
511 
512  XFileDataObject &x_mesh_face = x_faces.add_MeshFace(x_mesh->get_x_file());
513  XFileDataObject &x_faceVertexIndices = x_mesh_face["faceVertexIndices"];
514  XFileFace::Vertices::const_iterator fvi;
515  for (fvi = face->_vertices.begin();
516  fvi != face->_vertices.end();
517  ++fvi) {
518  x_faceVertexIndices.add_int((*fvi)._vertex_index);
519  }
520  x_mesh_face["nFaceVertexIndices"] = x_faceVertexIndices.size();
521  }
522  (*x_mesh)["nFaces"] = x_faces.size();
523 
524  // Now, add in any supplemental data.
525 
526  if (has_normals()) {
527  // Tack on normals.
528  make_x_normals(x_mesh, suffix);
529  }
530  if (has_colors()) {
531  // Tack on colors.
532  make_x_colors(x_mesh, suffix);
533  }
534  if (has_uvs()) {
535  // Tack on uvs.
536  make_x_uvs(x_mesh, suffix);
537  }
538  if (has_materials()) {
539  // Tack on materials.
540  make_x_material_list(x_mesh, suffix);
541  }
542 
543  return x_mesh;
544 }
545 
546 ////////////////////////////////////////////////////////////////////
547 // Function: XFileMesh::make_x_normals
548 // Access: Public
549 // Description: Creates a MeshNormals table for the mesh.
550 ////////////////////////////////////////////////////////////////////
552 make_x_normals(XFileNode *x_mesh, const string &suffix) {
553  XFileDataNode *x_meshNormals = x_mesh->add_MeshNormals("norms" + suffix);
554 
555  XFileDataObject &x_normals = (*x_meshNormals)["normals"];
556 
557  Normals::const_iterator ni;
558  for (ni = _normals.begin(); ni != _normals.end(); ++ni) {
559  XFileNormal *normal = (*ni);
560  x_normals.add_Vector(x_mesh->get_x_file(), normal->_normal);
561  }
562  (*x_meshNormals)["nNormals"] = x_normals.size();
563 
564  // Then, create the list of faces that index into the above normals.
565  XFileDataObject &x_faces = (*x_meshNormals)["faceNormals"];
566  Faces::const_iterator fi;
567  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
568  XFileFace *face = (*fi);
569 
570  XFileDataObject &x_normals_face = x_faces.add_MeshFace(x_mesh->get_x_file());
571  XFileDataObject &x_faceVertexIndices = x_normals_face["faceVertexIndices"];
572  XFileFace::Vertices::const_iterator fvi;
573  for (fvi = face->_vertices.begin();
574  fvi != face->_vertices.end();
575  ++fvi) {
576  x_faceVertexIndices.add_int((*fvi)._normal_index);
577  }
578  x_normals_face["nFaceVertexIndices"] = x_faceVertexIndices.size();
579  }
580  (*x_meshNormals)["nFaceNormals"] = x_faces.size();
581 
582  return x_meshNormals;
583 }
584 
585 ////////////////////////////////////////////////////////////////////
586 // Function: XFileMesh::make_x_colors
587 // Access: Public
588 // Description: Creates a MeshVertexColors table for the mesh.
589 ////////////////////////////////////////////////////////////////////
591 make_x_colors(XFileNode *x_mesh, const string &suffix) {
592  XFileDataNode *x_meshColors = x_mesh->add_MeshVertexColors("colors" + suffix);
593 
594  XFileDataObject &x_colors = (*x_meshColors)["vertexColors"];
595 
596  Vertices::const_iterator vi;
597  int i = 0;
598  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
599  XFileVertex *vertex = (*vi);
600  const LColor &color = vertex->_color;
601  x_colors.add_IndexedColor(x_mesh->get_x_file(), i, color);
602  i++;
603  }
604 
605  (*x_meshColors)["nVertexColors"] = x_colors.size();
606 
607  return x_meshColors;
608 }
609 
610 ////////////////////////////////////////////////////////////////////
611 // Function: XFileMesh::make_x_uvs
612 // Access: Public
613 // Description: Creates a MeshTextureCoords table for the mesh.
614 ////////////////////////////////////////////////////////////////////
616 make_x_uvs(XFileNode *x_mesh, const string &suffix) {
617  XFileDataNode *x_meshUvs = x_mesh->add_MeshTextureCoords("uvs" + suffix);
618 
619  XFileDataObject &x_uvs = (*x_meshUvs)["textureCoords"];
620 
621  Vertices::const_iterator vi;
622  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
623  XFileVertex *vertex = (*vi);
624  x_uvs.add_Coords2d(x_mesh->get_x_file(), vertex->_uv);
625  }
626 
627  (*x_meshUvs)["nTextureCoords"] = x_uvs.size();
628 
629  return x_meshUvs;
630 }
631 
632 ////////////////////////////////////////////////////////////////////
633 // Function: XFileMesh::make_x_material_list
634 // Access: Public
635 // Description: Creates a MeshMaterialList table for the mesh.
636 ////////////////////////////////////////////////////////////////////
638 make_x_material_list(XFileNode *x_mesh, const string &suffix) {
639  XFileDataNode *x_meshMaterials =
640  x_mesh->add_MeshMaterialList("materials" + suffix);
641 
642  // First, build up the list of faces the reference the materials.
643  XFileDataObject &x_indexes = (*x_meshMaterials)["faceIndexes"];
644 
645  Faces::const_iterator fi;
646  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
647  XFileFace *face = (*fi);
648  x_indexes.add_int(face->_material_index);
649  }
650 
651  (*x_meshMaterials)["nFaceIndexes"] = x_indexes.size();
652 
653  // Now, build up the list of materials themselves. Each material is
654  // a child of the MeshMaterialList node, rather than an element of
655  // an array.
656  for (size_t i = 0; i < _materials.size(); i++) {
657  XFileMaterial *material = _materials[i];
658 
659  material->make_x_material(x_meshMaterials,
660  suffix + "_" + format_string(i));
661  }
662 
663  (*x_meshMaterials)["nMaterials"] = (int)_materials.size();
664 
665  return x_meshMaterials;
666 }
667 
668 ////////////////////////////////////////////////////////////////////
669 // Function: XFileMesh::fill_mesh
670 // Access: Public
671 // Description: Fills the structure based on the raw data from the
672 // X file's Mesh object.
673 ////////////////////////////////////////////////////////////////////
674 bool XFileMesh::
676  clear();
677 
678  int i, j;
679 
680  const XFileDataObject &vertices = (*obj)["vertices"];
681  for (i = 0; i < vertices.size(); i++) {
682  XFileVertex *vertex = new XFileVertex;
683  vertex->_point = vertices[i].vec3();
684  add_vertex(vertex);
685  }
686 
687  const XFileDataObject &faces = (*obj)["faces"];
688  for (i = 0; i < faces.size(); i++) {
689  XFileFace *face = new XFileFace;
690 
691  const XFileDataObject &faceIndices = faces[i]["faceVertexIndices"];
692 
693  for (j = 0; j < faceIndices.size(); j++) {
694  XFileFace::Vertex vertex;
695  vertex._vertex_index = faceIndices[j].i();
696  vertex._normal_index = -1;
697 
698  face->_vertices.push_back(vertex);
699  }
700  _faces.push_back(face);
701  }
702 
703  // Some properties are stored as children of the mesh.
704  int num_objects = obj->get_num_objects();
705  for (i = 0; i < num_objects; i++) {
706  if (!fill_mesh_child(obj->get_object(i))) {
707  return false;
708  }
709  }
710 
711  return true;
712 }
713 
714 ////////////////////////////////////////////////////////////////////
715 // Function: XFileMesh::fill_mesh_child
716 // Access: Public
717 // Description: Fills the structure based on one of the children of
718 // the Mesh object.
719 ////////////////////////////////////////////////////////////////////
720 bool XFileMesh::
722  if (obj->is_standard_object("MeshNormals")) {
723  if (!fill_normals(obj)) {
724  return false;
725  }
726 
727  } else if (obj->is_standard_object("MeshVertexColors")) {
728  if (!fill_colors(obj)) {
729  return false;
730  }
731 
732  } else if (obj->is_standard_object("MeshTextureCoords")) {
733  if (!fill_uvs(obj)) {
734  return false;
735  }
736 
737  } else if (obj->is_standard_object("MeshMaterialList")) {
738  if (!fill_material_list(obj)) {
739  return false;
740  }
741 
742  } else if (obj->is_standard_object("XSkinMeshHeader")) {
743  // Quietly ignore a skin mesh header.
744 
745  } else if (obj->is_standard_object("SkinWeights")) {
746  if (!fill_skin_weights(obj)) {
747  return false;
748  }
749 
750  } else {
751  if (xfile_cat.is_debug()) {
752  xfile_cat.debug()
753  << "Ignoring mesh data object of unknown type: "
754  << obj->get_template_name() << "\n";
755  }
756  }
757 
758  return true;
759 }
760 
761 ////////////////////////////////////////////////////////////////////
762 // Function: XFileMesh::fill_normals
763 // Access: Public
764 // Description: Fills the structure based on the raw data from the
765 // MeshNormals template.
766 ////////////////////////////////////////////////////////////////////
767 bool XFileMesh::
769  int i, j;
770 
771  const XFileDataObject &normals = (*obj)["normals"];
772  for (i = 0; i < normals.size(); i++) {
773  XFileNormal *normal = new XFileNormal;
774  normal->_normal = normals[i].vec3();
775  normal->_has_normal = true;
776  add_normal(normal);
777  }
778 
779  const XFileDataObject &faceNormals = (*obj)["faceNormals"];
780  if (faceNormals.size() != (int)_faces.size()) {
781  xfile_cat.warning()
782  << "Incorrect number of faces in MeshNormals within "
783  << get_name() << "\n";
784  }
785 
786  int num_normals = min(faceNormals.size(), (int)_faces.size());
787  for (i = 0; i < num_normals; i++) {
788  XFileFace *face = _faces[i];
789 
790  const XFileDataObject &faceIndices = faceNormals[i]["faceVertexIndices"];
791 
792  if (faceIndices.size() != (int)face->_vertices.size()) {
793  xfile_cat.warning()
794  << "Incorrect number of vertices for face in MeshNormals within "
795  << get_name() << "\n";
796  }
797 
798  int num_vertices = min(faceIndices.size(), (int)face->_vertices.size());
799  for (j = 0; j < num_vertices; j++) {
800  face->_vertices[j]._normal_index = faceIndices[j].i();
801  }
802  }
803 
804  return true;
805 }
806 
807 ////////////////////////////////////////////////////////////////////
808 // Function: XFileMesh::fill_colors
809 // Access: Public
810 // Description: Fills the structure based on the raw data from the
811 // MeshVertexColors template.
812 ////////////////////////////////////////////////////////////////////
813 bool XFileMesh::
815  const XFileDataObject &vertexColors = (*obj)["vertexColors"];
816  for (int i = 0; i < vertexColors.size(); i++) {
817  int vertex_index = vertexColors[i]["index"].i();
818  if (vertex_index < 0 || vertex_index >= (int)_vertices.size()) {
819  xfile_cat.warning()
820  << "Vertex index out of range in MeshVertexColors within "
821  << get_name() << "\n";
822  continue;
823  }
824 
825  XFileVertex *vertex = _vertices[vertex_index];
826  vertex->_color = LCAST(PN_stdfloat, vertexColors[i]["indexColor"].vec4());
827  vertex->_has_color = true;
828  }
829 
830  return true;
831 }
832 
833 ////////////////////////////////////////////////////////////////////
834 // Function: XFileMesh::fill_uvs
835 // Access: Public
836 // Description: Fills the structure based on the raw data from the
837 // MeshTextureCoords template.
838 ////////////////////////////////////////////////////////////////////
839 bool XFileMesh::
841  const XFileDataObject &textureCoords = (*obj)["textureCoords"];
842  if (textureCoords.size() != (int)_vertices.size()) {
843  xfile_cat.warning()
844  << "Wrong number of vertices in MeshTextureCoords within "
845  << get_name() << "\n";
846  }
847 
848  int num_texcoords = min(textureCoords.size(), (int)_vertices.size());
849  for (int i = 0; i < num_texcoords; i++) {
850  XFileVertex *vertex = _vertices[i];
851  vertex->_uv = textureCoords[i].vec2();
852  vertex->_has_uv = true;
853  }
854 
855  return true;
856 }
857 
858 ////////////////////////////////////////////////////////////////////
859 // Function: XFileMesh::fill_skin_weights
860 // Access: Public
861 // Description: Fills the structure based on the raw data from the
862 // SkinWeights template.
863 ////////////////////////////////////////////////////////////////////
864 bool XFileMesh::
866  // Create a new SkinWeightsData record for the table. We'll need
867  // this data later when we create the vertices.
868  _skin_weights.push_back(SkinWeightsData());
869  SkinWeightsData &data = _skin_weights.back();
870 
871  data._joint_name = (*obj)["transformNodeName"].s();
872 
873  const XFileDataObject &vertexIndices = (*obj)["vertexIndices"];
874  const XFileDataObject &weights = (*obj)["weights"];
875 
876  if (weights.size() != vertexIndices.size()) {
877  xfile_cat.warning()
878  << "Inconsistent number of vertices in SkinWeights within " << get_name() << "\n";
879  }
880 
881  // Unpack the weight for each vertex.
882  size_t num_weights = min(weights.size(), vertexIndices.size());
883  for (size_t i = 0; i < num_weights; i++) {
884  int vindex = vertexIndices[i].i();
885  double weight = weights[i].d();
886 
887  if (vindex < 0 || vindex > (int)_vertices.size()) {
888  xfile_cat.warning()
889  << "Illegal vertex index " << vindex << " in SkinWeights.\n";
890  continue;
891  }
892  data._weight_map[vindex] = weight;
893  }
894 
895  // Also retrieve the matrix offset.
896  data._matrix_offset = (*obj)["matrixOffset"]["matrix"].mat4();
897 
898  return true;
899 }
900 
901 ////////////////////////////////////////////////////////////////////
902 // Function: XFileMesh::fill_material_list
903 // Access: Public
904 // Description: Fills the structure based on the raw data from the
905 // MeshMaterialList template.
906 ////////////////////////////////////////////////////////////////////
907 bool XFileMesh::
909  const XFileDataObject &faceIndexes = (*obj)["faceIndexes"];
910  if (faceIndexes.size() > (int)_faces.size()) {
911  xfile_cat.warning()
912  << "Too many faces in MeshMaterialList within " << get_name() << "\n";
913  }
914 
915  int material_index = -1;
916  int i = 0;
917  while (i < faceIndexes.size() && i < (int)_faces.size()) {
918  XFileFace *face = _faces[i];
919  material_index = faceIndexes[i].i();
920  face->_material_index = material_index;
921  i++;
922  }
923 
924  // The rest of the faces get the same material index as the last
925  // one in the list.
926  while (i < (int)_faces.size()) {
927  XFileFace *face = _faces[i];
928  face->_material_index = material_index;
929  i++;
930  }
931 
932  // Now look for children of the MaterialList object. These should
933  // all be Material objects.
934  int num_objects = obj->get_num_objects();
935  for (i = 0; i < num_objects; i++) {
936  XFileDataNode *child = obj->get_object(i);
937  if (child->is_standard_object("Material")) {
938  XFileMaterial *material = new XFileMaterial;
939  if (!material->fill_material(child)) {
940  delete material;
941  return false;
942  }
943  add_material(material);
944 
945  } else {
946  if (xfile_cat.is_debug()) {
947  xfile_cat.debug()
948  << "Ignoring material list object of unknown type: "
949  << child->get_template_name() << "\n";
950  }
951  }
952  }
953 
954  return true;
955 }
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
Definition: eggPrimitive.h:51
void clear()
Empties all data from the mesh.
Definition: xFileMesh.cxx:58
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
EggGroup * find_joint(const string &joint_name)
This is called by set_animation_frame, for the purposes of building the frame data for the animation–...
XFileDataNode * get_object(int n) const
Returns the nth child object of this node.
Definition: xFileNode.I:71
bool fill_mesh(XFileDataNode *obj)
Fills the structure based on the raw data from the X file&#39;s Mesh object.
Definition: xFileMesh.cxx:675
const string & get_template_name() const
A convenience function to return the name of the template used to define this data object...
Definition: xFileDataNode.I:53
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
XFileMaterial * get_material(int n) const
Returns a pointer to the nth materials associated with the mesh.
Definition: xFileMesh.cxx:482
XFileDataObject & add_int(int int_value)
Appends a new integer value to the data object, if it makes sense to do so.
virtual bool is_standard_object(const string &template_name) const
Returns true if this node represents an instance of the standard template with the indicated name...
void set_pos(double pos)
Sets the vertex position.
Definition: eggVertex.I:54
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
This represents a single normal associated with an XFileFace.
Definition: xFileNormal.h:31
LVecBase3d vec3() const
Returns the object&#39;s representation as an LVecBase3d.
bool has_colors() const
Returns true if any of the vertices or faces added to this mesh used a color, false otherwise...
Definition: xFileMesh.cxx:438
XFileDataNode * add_Mesh(const string &name)
Creates a new Mesh instance, as a child of this node.
Definition: xFileNode.cxx:357
bool has_normals() const
Returns true if any of the vertices or faces added to this mesh used a normal, false otherwise...
Definition: xFileMesh.cxx:427
bool fill_normals(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshNormals template.
Definition: xFileMesh.cxx:768
int add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim)
Creates a new XFileVertex, if one does not already exist for the indicated vertex, and returns its index.
Definition: xFileMesh.cxx:115
void apply_to_egg(EggPrimitive *egg_prim, XFileToEggConverter *converter)
Applies the properties in the material to the indicated egg primitive.
int add_material(EggPrimitive *egg_prim)
Creates a new XFileMaterial, if one does not already exist for the indicated material, and returns its index.
Definition: xFileMesh.cxx:181
XFileDataNode * add_MeshNormals(const string &name)
Creates a new MeshNormals instance, as a child of this node.
Definition: xFileNode.cxx:375
XFileDataNode * make_x_material_list(XFileNode *x_mesh, const string &suffix)
Creates a MeshMaterialList table for the mesh.
Definition: xFileMesh.cxx:638
XFileDataObject & add_MeshFace(XFile *x_file)
Appends a new MeshFace instance.
This is a two-component point in space.
Definition: lpoint2.h:411
bool has_uvs() const
Returns true if any of the vertices added to this mesh used a texture coordinate, false otherwise...
Definition: xFileMesh.cxx:449
int get_num_materials() const
Returns the number of distinct materials associated with the mesh.
Definition: xFileMesh.cxx:471
const LMatrix4d & get_node_to_vertex() const
Returns the transformation matrix suitable for converting vertices in the coordinate space of the nod...
Definition: eggNode.I:223
void set_external_index(int external_index)
Sets a special index number that is associated with the EggVertex (but is not written to the egg file...
Definition: eggVertex.I:365
int size() const
Returns the number of nested data objects within this object.
void set_from_egg(EggPrimitive *egg_prim)
Sets the structure up from the indicated egg data.
int get_num_objects() const
Returns the list of child objects of this node.
Definition: xFileNode.I:58
bool fill_material_list(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshMaterialList template.
Definition: xFileMesh.cxx:908
bool fill_skin_weights(XFileDataNode *obj)
Fills the structure based on the raw data from the SkinWeights template.
Definition: xFileMesh.cxx:865
int get_external_index() const
Returns the number set by set_external_index().
Definition: eggVertex.I:376
void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_poly)
Sets the structure up from the indicated egg data.
Definition: xFileVertex.cxx:40
int add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim)
Creates a new XFileNormal, if one does not already exist for the indicated normal, and returns its index.
Definition: xFileMesh.cxx:150
XFileDataNode * make_x_material(XFileNode *x_meshMaterials, const string &suffix)
Creates a Material object for the material list.
XFileDataNode * add_MeshTextureCoords(const string &name)
Creates a new MeshTextureCoords instance, as a child of this node.
Definition: xFileNode.cxx:411
bool has_materials() const
Returns true if any of the faces added to this mesh used a real material, false otherwise.
Definition: xFileMesh.cxx:460
void add_polygon(EggPolygon *egg_poly)
Adds the indicated polygon to the mesh.
Definition: xFileMesh.cxx:101
void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim)
Sets the structure up from the indicated egg data.
Definition: xFileNormal.cxx:37
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
XFileDataNode * make_x_normals(XFileNode *x_mesh, const string &suffix)
Creates a MeshNormals table for the mesh.
Definition: xFileMesh.cxx:552
XFileDataObject & add_Vector(XFile *x_file, const LVecBase3d &vector)
Appends a new Vector instance.
A single node of an X file.
Definition: xFileNode.h:42
bool fill_colors(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshVertexColors template.
Definition: xFileMesh.cxx:814
XFileDataObject & add_Coords2d(XFile *x_file, const LVecBase2d &coords)
Appends a new Coords2d instance.
XFileDataNode * add_MeshVertexColors(const string &name)
Creates a new MeshVertexColors instance, as a child of this node.
Definition: xFileNode.cxx:393
XFileDataObject & add_IndexedColor(XFile *x_file, int index, const LColor &color)
Appends a new IndexedColor instance.
iterator end() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
void transform(const LMatrix4d &mat)
Applies the indicated transformation matrix to the vertex.
Definition: eggVertex.cxx:755
void set_egg_parent(EggGroupNode *egg_parent)
Specifies the egg node that will eventually be the parent of this mesh, when create_polygons() is lat...
Definition: xFileMesh.cxx:276
XFileDataNode * make_x_colors(XFileNode *x_mesh, const string &suffix)
Creates a MeshVertexColors table for the mesh.
Definition: xFileMesh.cxx:591
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
bool fill_uvs(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshTextureCoords template.
Definition: xFileMesh.cxx:840
LVecBase2d vec2() const
Returns the object&#39;s representation as an LVecBase2d.
bool fill_mesh_child(XFileDataNode *obj)
Fills the structure based on one of the children of the Mesh object.
Definition: xFileMesh.cxx:721
void set_from_egg(XFileMesh *mesh, EggPolygon *egg_poly)
Sets the structure up from the indicated egg data.
Definition: xFileFace.cxx:35
A single polygon.
Definition: eggPolygon.h:26
This represents a single vertex associated with an XFileFace.
Definition: xFileVertex.h:29
XFileDataNode * make_x_mesh(XFileNode *x_parent, const string &suffix)
Creates an X structure corresponding to the mesh.
Definition: xFileMesh.cxx:493
This represents a single face of an XFileMesh.
Definition: xFileFace.h:28
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
bool has_material() const
Returns true if this material represents something meaningful, or false if the default material is su...
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
bool create_polygons(XFileToEggConverter *converter)
Creates a slew of EggPolygons according to the faces in the mesh, and adds them to the previously-ind...
Definition: xFileMesh.cxx:292
This represents an X file &quot;material&quot;, which consists of a color, lighting, and/or texture specificati...
Definition: xFileMaterial.h:33
This is an abstract base class for an XFileNode which is also an XFileDataObject. ...
Definition: xFileDataNode.h:36
XFileDataNode * add_MeshMaterialList(const string &name)
Creates a new MeshMaterialList instance, as a child of this node.
Definition: xFileNode.cxx:429
void ref_vertex(EggVertex *vert, double membership=1.0)
Adds the vertex to the set of those referenced by the group, at the indicated membership level...
Definition: eggGroup.cxx:678
bool fill_material(XFileDataNode *obj)
Fills the structure based on the raw data from the X file&#39;s Material object.
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
Definition: eggVertex.I:239
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.
XFileDataNode * make_x_uvs(XFileNode *x_mesh, const string &suffix)
Creates a MeshTextureCoords table for the mesh.
Definition: xFileMesh.cxx:616
A collection of vertices.
Definition: eggVertexPool.h:46
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive&#39;s list of vertices, and returns it...
void recompute_vertex_normals(double threshold, CoordinateSystem cs=CS_default)
Recomputes all the vertex normals for polygon geometry at this group node and below so that they accu...
iterator begin() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
The abstract base class for a number of different types of data elements that may be stored in the X ...
int i() const
Unambiguously returns the object&#39;s representation as an integer, or 0 if the object has no integer re...
double d() const
Unambiguously returns the object&#39;s representation as a double, or 0.0 if the object has no double rep...