Panda3D
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â€...
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
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
XFileDataObject & add_int(int int_value)
Appends a new integer value to the data object, if it makes sense to do so.
void set_pos(double pos)
Sets the vertex position.
Definition: eggVertex.I:54
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
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
int i() const
Unambiguously returns the object&#39;s representation as an integer, or 0 if the object has no integer re...
This represents a single normal associated with an XFileFace.
Definition: xFileNormal.h:31
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
XFileDataNode * add_Mesh(const string &name)
Creates a new Mesh instance, as a child of this node.
Definition: xFileNode.cxx:357
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:424
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
void set_from_egg(EggPrimitive *egg_prim)
Sets the structure up from the indicated egg data.
iterator end() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
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
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
bool has_material() const
Returns true if this material represents something meaningful, or false if the default material is su...
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
int get_num_objects() const
Returns the list of child objects of this node.
Definition: xFileNode.I:58
iterator begin() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
void add_polygon(EggPolygon *egg_poly)
Adds the indicated polygon to the mesh.
Definition: xFileMesh.cxx:101
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
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 <Group>, <Instance>, and <Joint> 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
XFileMaterial * get_material(int n) const
Returns a pointer to the nth materials associated with the mesh.
Definition: xFileMesh.cxx:482
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.
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
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
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
int size() const
Returns the number of nested data objects within this object.
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
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...
LVecBase2d vec2() const
Returns the object&#39;s representation as an LVecBase2d.
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 "material", 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 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
int get_external_index() const
Returns the number set by set_external_index().
Definition: eggVertex.I:376
bool fill_material(XFileDataNode *obj)
Fills the structure based on the raw data from the X file&#39;s Material object.
XFileDataNode * get_object(int n) const
Returns the nth child object of this node.
Definition: xFileNode.I:71
double d() const
Unambiguously returns the object&#39;s representation as a double, or 0.0 if the object has no double rep...
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
LVecBase3d vec3() const
Returns the object&#39;s representation as an LVecBase3d.
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...
The abstract base class for a number of different types of data elements that may be stored in the X ...
int get_num_materials() const
Returns the number of distinct materials associated with the mesh.
Definition: xFileMesh.cxx:471