Panda3D
Loading...
Searching...
No Matches
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
29using std::min;
30using std::string;
31
32/**
33 *
34 */
35XFileMesh::
36XFileMesh(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 */
47XFileMesh::
48~XFileMesh() {
49 clear();
50}
51
52/**
53 * Empties all data from the mesh.
54 */
56clear() {
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 */
97add_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 */
108add_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 */
140add_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 */
168add_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 */
198add_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 */
218add_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 */
235add_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 */
251set_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 */
397has_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 */
406has_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 */
415has_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 */
424has_materials() const {
425 return _has_materials;
426}
427
428/**
429 * Returns the number of distinct materials associated with the mesh.
430 */
432get_num_materials() const {
433 return _materials.size();
434}
435
436/**
437 * Returns a pointer to the nth materials associated with the mesh.
438 */
440get_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 */
449make_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 */
506make_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 */
543make_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 */
566make_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 */
586make_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 */
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 */
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}
A base class for nodes in the hierarchy that are not leaf nodes.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group 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 main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition eggGroup.h:34
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
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
A single polygon.
Definition eggPolygon.h:24
A base class for any of a number of kinds of geometry primitives: polygons, point lights,...
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
A collection of vertices.
iterator end() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
iterator begin() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
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.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition eggVertex.h:39
void transform(const LMatrix4d &mat)
Applies the indicated transformation matrix to the vertex.
int get_external_index() const
Returns the number set by set_external_index().
Definition eggVertex.I:300
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
void set_pos(double pos)
Sets the vertex position.
Definition eggVertex.I:42
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
Definition eggVertex.I:193
This is an abstract base class for an XFileNode which is also an XFileDataObject.
const std::string & get_template_name() const
A convenience function to return the name of the template used to define this data 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,...
The abstract base class for a number of different types of data elements that may be stored in the X ...
XFileDataObject & add_int(int int_value)
Appends a new integer value to the data object, if it makes sense to do so.
double d() const
Unambiguously returns the object's representation as a double, or 0.0 if the object has no double rep...
int i() const
Unambiguously returns the object's representation as an integer, or 0 if the object has no integer re...
XFileDataObject & add_MeshFace(XFile *x_file)
Appends a new MeshFace instance.
int size() const
Returns the number of nested data objects within this object.
XFileDataObject & add_Vector(XFile *x_file, const LVecBase3d &vector)
Appends a new Vector instance.
LVecBase3d vec3() const
Returns the object's representation as an LVecBase3d.
LVecBase2d vec2() const
Returns the object's representation as an LVecBase2d.
XFileDataObject & add_IndexedColor(XFile *x_file, int index, const LColor &color)
Appends a new IndexedColor instance.
XFileDataObject & add_Coords2d(XFile *x_file, const LVecBase2d &coords)
Appends a new Coords2d instance.
This represents a single face of an XFileMesh.
Definition xFileFace.h:26
void set_from_egg(XFileMesh *mesh, EggPolygon *egg_poly)
Sets the structure up from the indicated egg data.
Definition xFileFace.cxx:30
This represents an X file "material", which consists of a color, lighting, and/or texture specificati...
XFileDataNode * make_x_material(XFileNode *x_meshMaterials, const std::string &suffix)
Creates a Material object for the material list.
void apply_to_egg(EggPrimitive *egg_prim, XFileToEggConverter *converter)
Applies the properties in the material to the indicated egg primitive.
bool fill_material(XFileDataNode *obj)
Fills the structure based on the raw data from the X file's Material object.
bool has_material() const
Returns true if this material represents something meaningful, or false if the default material is su...
void set_from_egg(EggPrimitive *egg_prim)
Sets the structure up from the indicated egg data.
void clear()
Empties all data from the mesh.
Definition xFileMesh.cxx:56
bool fill_mesh(XFileDataNode *obj)
Fills the structure based on the raw data from the X file's Mesh object.
bool fill_skin_weights(XFileDataNode *obj)
Fills the structure based on the raw data from the SkinWeights template.
bool fill_material_list(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshMaterialList template.
bool has_uvs() const
Returns true if any of the vertices added to this mesh used a texture coordinate, false otherwise.
int add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim)
Creates a new XFileVertex, if one does not already exist for the indicated vertex,...
bool fill_uvs(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshTextureCoords template.
bool has_materials() const
Returns true if any of the faces added to this mesh used a real material, false otherwise.
XFileDataNode * make_x_mesh(XFileNode *x_parent, const std::string &suffix)
Creates an X structure corresponding to the mesh.
int get_num_materials() const
Returns the number of distinct materials associated with the mesh.
int add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim)
Creates a new XFileNormal, if one does not already exist for the indicated normal,...
bool fill_colors(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshVertexColors template.
bool fill_mesh_child(XFileDataNode *obj)
Fills the structure based on one of the children of the Mesh object.
bool fill_normals(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshNormals template.
XFileDataNode * make_x_material_list(XFileNode *x_mesh, const std::string &suffix)
Creates a MeshMaterialList table for the mesh.
XFileDataNode * make_x_colors(XFileNode *x_mesh, const std::string &suffix)
Creates a MeshVertexColors table for the mesh.
void add_polygon(EggPolygon *egg_poly)
Adds the indicated polygon to the mesh.
Definition xFileMesh.cxx:97
bool create_polygons(XFileToEggConverter *converter)
Creates a slew of EggPolygons according to the faces in the mesh, and adds them to the previously-ind...
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...
XFileDataNode * make_x_uvs(XFileNode *x_mesh, const std::string &suffix)
Creates a MeshTextureCoords table for the mesh.
bool has_colors() const
Returns true if any of the vertices or faces added to this mesh used a color, false otherwise.
XFileDataNode * make_x_normals(XFileNode *x_mesh, const std::string &suffix)
Creates a MeshNormals table for the mesh.
XFileMaterial * get_material(int n) const
Returns a pointer to the nth materials associated with the mesh.
int add_material(EggPrimitive *egg_prim)
Creates a new XFileMaterial, if one does not already exist for the indicated material,...
bool has_normals() const
Returns true if any of the vertices or faces added to this mesh used a normal, false otherwise.
A single node of an X file.
Definition xFileNode.h:40
int get_num_objects() const
Returns the list of child objects of this node.
Definition xFileNode.I:57
XFileDataNode * add_MeshTextureCoords(const std::string &name)
Creates a new MeshTextureCoords instance, as a child of this node.
XFileDataNode * add_MeshVertexColors(const std::string &name)
Creates a new MeshVertexColors instance, as a child of this node.
XFileDataNode * add_MeshNormals(const std::string &name)
Creates a new MeshNormals instance, as a child of this node.
XFileDataNode * get_object(int n) const
Returns the nth child object of this node.
Definition xFileNode.I:67
XFileDataNode * add_MeshMaterialList(const std::string &name)
Creates a new MeshMaterialList instance, as a child of this node.
XFileDataNode * add_Mesh(const std::string &name)
Creates a new Mesh instance, as a child of this node.
This represents a single normal associated with an XFileFace.
Definition xFileNormal.h:28
void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim)
Sets the structure up from the indicated egg data.
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–...
This represents a single vertex associated with an XFileFace.
Definition xFileVertex.h:26
void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_poly)
Sets the structure up from the indicated egg data.
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.