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