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"
34 XFileMesh(CoordinateSystem cs) : _cs(cs) {
38 _has_materials =
false;
59 Vertices::iterator vi;
60 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
65 for (ni = _normals.begin(); ni != _normals.end(); ++ni) {
69 Materials::iterator mi;
70 for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
75 for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
85 _unique_vertices.clear();
86 _unique_normals.clear();
87 _unique_materials.clear();
92 _has_materials =
false;
104 _faces.push_back(face);
116 int next_index = _vertices.size();
119 if (vertex->_has_color) {
122 if (vertex->_has_uv) {
126 pair<UniqueVertices::iterator, bool> result =
127 _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index));
131 _vertices.push_back(vertex);
137 return (*result.first).second;
151 int next_index = _normals.size();
154 if (normal->_has_normal) {
158 pair<UniqueNormals::iterator, bool> result =
159 _unique_normals.insert(UniqueNormals::value_type(normal, next_index));
163 _normals.push_back(normal);
169 return (*result.first).second;
182 int next_index = _materials.size();
186 _has_materials =
true;
189 pair<UniqueMaterials::iterator, bool> result =
190 _unique_materials.insert(UniqueMaterials::value_type(material, next_index));
194 _materials.push_back(material);
200 return (*result.first).second;
215 if (vertex->_has_color) {
218 if (vertex->_has_uv) {
222 int next_index = _vertices.size();
223 _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index));
224 _vertices.push_back(vertex);
238 if (normal->_has_normal) {
242 int next_index = _normals.size();
243 _unique_normals.insert(UniqueNormals::value_type(normal, next_index));
244 _normals.push_back(normal);
259 _has_materials =
true;
262 int next_index = _materials.size();
263 _unique_materials.insert(UniqueMaterials::value_type(material, next_index));
264 _materials.push_back(material);
281 _egg_parent = egg_group;
297 Faces::const_iterator fi;
298 for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
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()) {
311 <<
"Vertex index out of range in Mesh " << get_name() <<
"\n";
317 if (normal_index >= 0 && normal_index < (
int)_normals.size()) {
318 normal = _normals[normal_index];
324 temp_vtx.
set_pos(vertex->_point);
325 if (vertex->_has_color) {
326 temp_vtx.set_color(vertex->_color);
328 if (vertex->_has_uv) {
335 if (normal != (
XFileNormal *)NULL && normal->_has_normal) {
336 temp_vtx.set_normal(normal->_normal);
343 double net_weight = 0.0;
344 LMatrix4d weighted_transform(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()) {
355 double weight = (*wmi).second;
358 weighted_transform += mat * weight;
359 net_weight += weight;
364 if (net_weight == 0.0) {
373 weighted_transform /= net_weight;
383 int material_index = face->_material_index;
384 if (material_index >= 0 && material_index < (
int)_materials.size()) {
392 for (vi = vpool->
begin(); vi != vpool->
end(); ++vi) {
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()) {
403 double weight = (*wmi).second;
461 return _has_materials;
472 return _materials.size();
483 nassertr(n >= 0 && n < (
int)_materials.size(), (
XFileMaterial *)NULL);
484 return _materials[n];
499 Vertices::const_iterator vi;
500 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
502 x_vertices.
add_Vector(x_mesh->get_x_file(), vertex->_point);
504 (*x_mesh)[
"nVertices"] = x_vertices.
size();
508 Faces::const_iterator fi;
509 for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
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();
518 x_faceVertexIndices.
add_int((*fvi)._vertex_index);
520 x_mesh_face[
"nFaceVertexIndices"] = x_faceVertexIndices.
size();
522 (*x_mesh)[
"nFaces"] = x_faces.
size();
557 Normals::const_iterator ni;
558 for (ni = _normals.begin(); ni != _normals.end(); ++ni) {
560 x_normals.
add_Vector(x_mesh->get_x_file(), normal->_normal);
562 (*x_meshNormals)[
"nNormals"] = x_normals.
size();
566 Faces::const_iterator fi;
567 for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
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();
576 x_faceVertexIndices.
add_int((*fvi)._normal_index);
578 x_normals_face[
"nFaceVertexIndices"] = x_faceVertexIndices.
size();
580 (*x_meshNormals)[
"nFaceNormals"] = x_faces.
size();
582 return x_meshNormals;
596 Vertices::const_iterator vi;
598 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
605 (*x_meshColors)[
"nVertexColors"] = x_colors.
size();
621 Vertices::const_iterator vi;
622 for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
627 (*x_meshUvs)[
"nTextureCoords"] = x_uvs.
size();
645 Faces::const_iterator fi;
646 for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
648 x_indexes.
add_int(face->_material_index);
651 (*x_meshMaterials)[
"nFaceIndexes"] = x_indexes.
size();
656 for (
size_t i = 0; i < _materials.size(); i++) {
660 suffix +
"_" + format_string(i));
663 (*x_meshMaterials)[
"nMaterials"] = (int)_materials.size();
665 return x_meshMaterials;
681 for (i = 0; i < vertices.
size(); i++) {
683 vertex->_point = vertices[i].
vec3();
688 for (i = 0; i < faces.
size(); i++) {
693 for (j = 0; j < faceIndices.
size(); j++) {
695 vertex._vertex_index = faceIndices[j].
i();
696 vertex._normal_index = -1;
698 face->_vertices.push_back(vertex);
700 _faces.push_back(face);
705 for (i = 0; i < num_objects; i++) {
751 if (xfile_cat.is_debug()) {
753 <<
"Ignoring mesh data object of unknown type: "
772 for (i = 0; i < normals.
size(); i++) {
774 normal->_normal = normals[i].
vec3();
775 normal->_has_normal =
true;
780 if (faceNormals.
size() != (int)_faces.size()) {
782 <<
"Incorrect number of faces in MeshNormals within "
783 << get_name() <<
"\n";
786 int num_normals = min(faceNormals.
size(), (int)_faces.size());
787 for (i = 0; i < num_normals; i++) {
790 const XFileDataObject &faceIndices = faceNormals[i][
"faceVertexIndices"];
792 if (faceIndices.
size() != (int)face->_vertices.size()) {
794 <<
"Incorrect number of vertices for face in MeshNormals within "
795 << get_name() <<
"\n";
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();
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()) {
820 <<
"Vertex index out of range in MeshVertexColors within "
821 << get_name() <<
"\n";
826 vertex->_color = LCAST(PN_stdfloat, vertexColors[i][
"indexColor"].vec4());
827 vertex->_has_color =
true;
842 if (textureCoords.
size() != (int)_vertices.size()) {
844 <<
"Wrong number of vertices in MeshTextureCoords within "
845 << get_name() <<
"\n";
848 int num_texcoords = min(textureCoords.
size(), (int)_vertices.size());
849 for (
int i = 0; i < num_texcoords; i++) {
851 vertex->_uv = textureCoords[i].
vec2();
852 vertex->_has_uv =
true;
868 _skin_weights.push_back(SkinWeightsData());
869 SkinWeightsData &data = _skin_weights.back();
871 data._joint_name = (*obj)[
"transformNodeName"].s();
876 if (weights.
size() != vertexIndices.
size()) {
878 <<
"Inconsistent number of vertices in SkinWeights within " << get_name() <<
"\n";
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();
887 if (vindex < 0 || vindex > (
int)_vertices.size()) {
889 <<
"Illegal vertex index " << vindex <<
" in SkinWeights.\n";
892 data._weight_map[vindex] = weight;
896 data._matrix_offset = (*obj)[
"matrixOffset"][
"matrix"].mat4();
910 if (faceIndexes.
size() > (int)_faces.size()) {
912 <<
"Too many faces in MeshMaterialList within " << get_name() <<
"\n";
915 int material_index = -1;
917 while (i < faceIndexes.
size() && i < (int)_faces.size()) {
919 material_index = faceIndexes[i].
i();
920 face->_material_index = material_index;
926 while (i < (
int)_faces.size()) {
928 face->_material_index = material_index;
935 for (i = 0; i < num_objects; i++) {
946 if (xfile_cat.is_debug()) {
948 <<
"Ignoring material list object of unknown type: "
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
void clear()
Empties all data from the mesh.
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
EggGroup * find_joint(const string &joint_name)
This is called by set_animation_frame, for the purposes of building the frame data for the animation–...
XFileDataNode * get_object(int n) const
Returns the nth child object of this node.
bool fill_mesh(XFileDataNode *obj)
Fills the structure based on the raw data from the X file's Mesh object.
const string & get_template_name() const
A convenience function to return the name of the template used to define this data object...
This is a 4-by-4 transform matrix.
XFileMaterial * get_material(int n) const
Returns a pointer to the nth materials associated with the mesh.
XFileDataObject & add_int(int int_value)
Appends a new integer value to the data object, if it makes sense to do so.
virtual bool is_standard_object(const string &template_name) const
Returns true if this node represents an instance of the standard template with the indicated name...
void set_pos(double pos)
Sets the vertex position.
A base class for nodes in the hierarchy that are not leaf nodes.
This represents a single normal associated with an XFileFace.
LVecBase3d vec3() const
Returns the object's representation as an LVecBase3d.
bool has_colors() const
Returns true if any of the vertices or faces added to this mesh used a color, false otherwise...
XFileDataNode * add_Mesh(const string &name)
Creates a new Mesh instance, as a child of this node.
bool has_normals() const
Returns true if any of the vertices or faces added to this mesh used a normal, false otherwise...
bool fill_normals(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshNormals template.
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.
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.
XFileDataNode * add_MeshNormals(const string &name)
Creates a new MeshNormals instance, as a child of this node.
XFileDataNode * make_x_material_list(XFileNode *x_mesh, const string &suffix)
Creates a MeshMaterialList table for the mesh.
XFileDataObject & add_MeshFace(XFile *x_file)
Appends a new MeshFace instance.
This is a two-component point in space.
bool has_uvs() const
Returns true if any of the vertices added to this mesh used a texture coordinate, false otherwise...
int get_num_materials() const
Returns the number of distinct materials associated with the mesh.
const LMatrix4d & get_node_to_vertex() const
Returns the transformation matrix suitable for converting vertices in the coordinate space of the nod...
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...
int size() const
Returns the number of nested data objects within this object.
void set_from_egg(EggPrimitive *egg_prim)
Sets the structure up from the indicated egg data.
int get_num_objects() const
Returns the list of child objects of this node.
bool fill_material_list(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshMaterialList template.
bool fill_skin_weights(XFileDataNode *obj)
Fills the structure based on the raw data from the SkinWeights template.
int get_external_index() const
Returns the number set by set_external_index().
void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_poly)
Sets the structure up from the indicated egg data.
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.
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.
bool has_materials() const
Returns true if any of the faces added to this mesh used a real material, false otherwise.
void add_polygon(EggPolygon *egg_poly)
Adds the indicated polygon to the mesh.
void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim)
Sets the structure up from the indicated egg data.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
XFileDataNode * make_x_normals(XFileNode *x_mesh, const string &suffix)
Creates a MeshNormals table for the mesh.
XFileDataObject & add_Vector(XFile *x_file, const LVecBase3d &vector)
Appends a new Vector instance.
A single node of an X file.
bool fill_colors(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshVertexColors template.
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.
XFileDataObject & add_IndexedColor(XFile *x_file, int index, const LColor &color)
Appends a new IndexedColor instance.
iterator end() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
void transform(const LMatrix4d &mat)
Applies the indicated transformation matrix to the vertex.
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_colors(XFileNode *x_mesh, const string &suffix)
Creates a MeshVertexColors table for the mesh.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
bool fill_uvs(XFileDataNode *obj)
Fills the structure based on the raw data from the MeshTextureCoords template.
LVecBase2d vec2() const
Returns the object's representation as an LVecBase2d.
bool fill_mesh_child(XFileDataNode *obj)
Fills the structure based on one of the children of the Mesh object.
void set_from_egg(XFileMesh *mesh, EggPolygon *egg_poly)
Sets the structure up from the indicated egg data.
This represents a single vertex associated with an XFileFace.
XFileDataNode * make_x_mesh(XFileNode *x_parent, const string &suffix)
Creates an X structure corresponding to the mesh.
This represents a single face of an XFileMesh.
This is the base class for all three-component vectors and points.
bool has_material() const
Returns true if this material represents something meaningful, or false if the default material is su...
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
bool create_polygons(XFileToEggConverter *converter)
Creates a slew of EggPolygons according to the faces in the mesh, and adds them to the previously-ind...
This represents an X file "material", which consists of a color, lighting, and/or texture specificati...
This is an abstract base class for an XFileNode which is also an XFileDataObject. ...
XFileDataNode * add_MeshMaterialList(const string &name)
Creates a new MeshMaterialList instance, as a child of this node.
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...
bool fill_material(XFileDataNode *obj)
Fills the structure based on the raw data from the X file's Material object.
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
EggVertex * create_unique_vertex(const EggVertex ©)
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.
A collection of vertices.
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it...
void recompute_vertex_normals(double threshold, CoordinateSystem cs=CS_default)
Recomputes all the vertex normals for polygon geometry at this group node and below so that they accu...
iterator begin() const
Returns an iterator that can be used to traverse through all the vertices in the pool.
The abstract base class for a number of different types of data elements that may be stored in the X ...
int i() const
Unambiguously returns the object's representation as an integer, or 0 if the object has no integer re...
double d() const
Unambiguously returns the object's representation as a double, or 0.0 if the object has no double rep...