From 3bd11c3cda1a6dedaedcfa14e15150016f044fe1 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 22 Jun 2001 01:54:52 +0000 Subject: [PATCH] *** empty log message *** --- pandatool/src/xfile/Sources.pp | 35 +- pandatool/src/xfile/xFileFace.cxx | 14 +- pandatool/src/xfile/xFileFace.h | 5 +- pandatool/src/xfile/xFileMaker.cxx | 50 ++ pandatool/src/xfile/xFileMaterial.cxx | 284 ++++++++ pandatool/src/xfile/xFileMaterial.h | 69 ++ pandatool/src/xfile/xFileMesh.cxx | 448 +++++++++++- pandatool/src/xfile/xFileMesh.h | 34 +- pandatool/src/xfile/xFileNormal.cxx | 19 +- pandatool/src/xfile/xFileNormal.h | 3 +- pandatool/src/xfile/xFileToEgg.cxx | 78 +++ pandatool/src/xfile/xFileToEgg.h | 41 ++ pandatool/src/xfile/xFileToEggConverter.cxx | 713 ++++++++++++++++++++ pandatool/src/xfile/xFileToEggConverter.h | 87 +++ pandatool/src/xfile/xFileVertex.cxx | 40 +- pandatool/src/xfile/xFileVertex.h | 3 +- 16 files changed, 1899 insertions(+), 24 deletions(-) create mode 100644 pandatool/src/xfile/xFileMaterial.cxx create mode 100644 pandatool/src/xfile/xFileMaterial.h create mode 100644 pandatool/src/xfile/xFileToEgg.cxx create mode 100644 pandatool/src/xfile/xFileToEgg.h create mode 100644 pandatool/src/xfile/xFileToEggConverter.cxx create mode 100644 pandatool/src/xfile/xFileToEggConverter.h diff --git a/pandatool/src/xfile/Sources.pp b/pandatool/src/xfile/Sources.pp index d47f7f6b31..e51db8f7ec 100644 --- a/pandatool/src/xfile/Sources.pp +++ b/pandatool/src/xfile/Sources.pp @@ -15,13 +15,46 @@ #define SOURCES \ xFileFace.cxx xFileFace.h \ - xFileMaker.cxx xFileMaker.h \ + xFileMaterial.cxx xFileMaterial.h \ xFileMesh.cxx xFileMesh.h \ xFileNormal.cxx xFileNormal.h \ xFileVertex.cxx xFileVertex.h + #define SOURCES \ + $[SOURCES] \ + xFileMaker.cxx xFileMaker.h + #define SOURCES \ $[SOURCES] \ eggToX.cxx eggToX.h #end bin_target + +#begin bin_target + #define TARGET x2egg + #define LOCAL_LIBS converter eggbase progbase pandatoolbase + #define OTHER_LIBS \ + egg:c pandaegg:m \ + mathutil:c linmath:c putil:c panda:m \ + express:c pandaexpress:m \ + dtoolconfig dtool pystub \ + + #define WIN_SYS_LIBS \ + d3dxof.lib + + #define SOURCES \ + xFileFace.cxx xFileFace.h \ + xFileMaterial.cxx xFileMaterial.h \ + xFileMesh.cxx xFileMesh.h \ + xFileNormal.cxx xFileNormal.h \ + xFileVertex.cxx xFileVertex.h + + #define SOURCES \ + $[SOURCES] \ + xFileToEggConverter.cxx xFileToEggConverter.h + + #define SOURCES \ + $[SOURCES] \ + xFileToEgg.cxx xFileToEgg.h + +#end bin_target diff --git a/pandatool/src/xfile/xFileFace.cxx b/pandatool/src/xfile/xFileFace.cxx index 5890822d37..a490503d27 100644 --- a/pandatool/src/xfile/xFileFace.cxx +++ b/pandatool/src/xfile/xFileFace.cxx @@ -26,7 +26,17 @@ // Description: //////////////////////////////////////////////////////////////////// XFileFace:: -XFileFace(XFileMesh *mesh, EggPolygon *egg_poly) { +XFileFace() { + _material_index = -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileFace::set_from_egg +// Access: Public +// Description: Sets the structure up from the indicated egg data. +//////////////////////////////////////////////////////////////////// +void XFileFace:: +set_from_egg(XFileMesh *mesh, EggPolygon *egg_poly) { // Walk through the polygon's vertices in reverse order, to change // from Egg's counter-clockwise convention to DX's clockwise. EggPolygon::reverse_iterator vi; @@ -37,4 +47,6 @@ XFileFace(XFileMesh *mesh, EggPolygon *egg_poly) { v._normal_index = mesh->add_normal(egg_vertex, egg_poly); _vertices.push_back(v); } + + _material_index = mesh->add_material(egg_poly); } diff --git a/pandatool/src/xfile/xFileFace.h b/pandatool/src/xfile/xFileFace.h index 623c81d6a3..1442f9d20c 100644 --- a/pandatool/src/xfile/xFileFace.h +++ b/pandatool/src/xfile/xFileFace.h @@ -31,7 +31,8 @@ class EggPolygon; //////////////////////////////////////////////////////////////////// class XFileFace { public: - XFileFace(XFileMesh *mesh, EggPolygon *egg_poly); + XFileFace(); + void set_from_egg(XFileMesh *mesh, EggPolygon *egg_poly); class Vertex { public: @@ -40,6 +41,8 @@ public: }; typedef pvector Vertices; Vertices _vertices; + + int _material_index; }; #endif diff --git a/pandatool/src/xfile/xFileMaker.cxx b/pandatool/src/xfile/xFileMaker.cxx index 579570ddf8..094dbd938b 100644 --- a/pandatool/src/xfile/xFileMaker.cxx +++ b/pandatool/src/xfile/xFileMaker.cxx @@ -18,6 +18,8 @@ #include "xFileMaker.h" #include "xFileMesh.h" +#include "xFileMaterial.h" + #include "notify.h" #include "eggGroupNode.h" #include "eggGroup.h" @@ -305,6 +307,54 @@ add_polyset(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) { } } + if (mesh.has_materials()) { + // Tack on material definitions. + LPDIRECTXFILEDATA xmaterial_list; + mesh.make_material_list_data(raw_data); + if (!create_object(xmaterial_list, TID_D3DRMMeshMaterialList, + "materials" + mesh_index, raw_data)) { + return false; + } + + // Now we need to iterate through the list of Materials + // themselves, and add *these* as children of the material list. + int num_materials = mesh.get_num_materials(); + for (int i = 0; i < num_materials; i++) { + XFileMaterial *material = mesh.get_material(i); + LPDIRECTXFILEDATA xmaterial; + material->make_material_data(raw_data); + if (!create_object(xmaterial, TID_D3DRMMaterial, + "material" + mesh_index + "_" + format_string(i), + raw_data)) { + return false; + } + + // Also, if the Material has a texture map, we must add *this* + // as a child of the material. What a weird system. + if (material->has_texture()) { + LPDIRECTXFILEDATA xtexture; + material->make_texture_data(raw_data); + if (!create_object(xtexture, TID_D3DRMTextureFilename, + "texture" + mesh_index + "_" + format_string(i), + raw_data)) { + return false; + } + + if (!attach_and_release(xtexture, xmaterial)) { + return false; + } + } + + if (!attach_and_release(xmaterial, xmaterial_list)) { + return false; + } + } + + if (!attach_and_release(xmaterial_list, xobj)) { + return false; + } + } + if (!attach_and_release(xobj, dx_parent)) { return false; } diff --git a/pandatool/src/xfile/xFileMaterial.cxx b/pandatool/src/xfile/xFileMaterial.cxx new file mode 100644 index 0000000000..94077f9324 --- /dev/null +++ b/pandatool/src/xfile/xFileMaterial.cxx @@ -0,0 +1,284 @@ +// Filename: xFileMaterial.cxx +// Created by: drose (19Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "xFileMaterial.h" + +#include "eggMaterial.h" +#include "eggTexture.h" +#include "eggMaterialCollection.h" +#include "eggTextureCollection.h" +#include "eggPrimitive.h" +#include "datagram.h" + +#include // for strcmp, strdup + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileMaterial:: +XFileMaterial() { + _face_color.set(1.0, 1.0, 1.0, 1.0); + _specular_color.set(0.0, 0.0, 0.0); + _emissive_color.set(0.0, 0.0, 0.0); + _power = 64.0; + + _has_material = false; + _has_texture = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileMaterial:: +~XFileMaterial() { +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::set_from_egg +// Access: Public +// Description: Sets the structure up from the indicated egg data. +//////////////////////////////////////////////////////////////////// +void XFileMaterial:: +set_from_egg(EggPrimitive *egg_prim) { + // First, determine the face color. + if (egg_prim->has_color()) { + _face_color = egg_prim->get_color(); + _has_material = true; + } + + // Do we have an actual EggMaterial, to control lighting effects? + if (egg_prim->has_material()) { + _has_material = true; + EggMaterial *egg_mat = egg_prim->get_material(); + if (egg_mat->has_diff()) { + _face_color = egg_mat->get_diff(); + } + if (egg_mat->has_spec()) { + const Colorf &spec = egg_mat->get_spec(); + _specular_color.set(spec[0], spec[1], spec[2]); + } + if (egg_mat->has_emit()) { + const Colorf &emit = egg_mat->get_emit(); + _emissive_color.set(emit[0], emit[1], emit[2]); + } + if (egg_mat->has_shininess()) { + _power = egg_mat->get_shininess(); + } + } + + // Finally, if we also have a texture, record that. + if (egg_prim->has_texture()) { + _has_material = true; + _has_texture = true; + EggTexture *egg_tex = egg_prim->get_texture(); + _texture = egg_tex->get_filename(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::apply_to_egg +// Access: Public +// Description: Applies the properties in the material to the +// indicated egg primitive. +//////////////////////////////////////////////////////////////////// +void XFileMaterial:: +apply_to_egg(EggPrimitive *egg_prim, + EggTextureCollection &textures, + EggMaterialCollection &materials) { + // Is there a texture? + if (_has_texture) { + EggTexture temp("", _texture); + EggTexture *egg_tex = + textures.create_unique_texture(temp, ~EggTexture::E_tref_name); + egg_prim->set_texture(egg_tex); + } + + // Are there any fancy lighting effects? + bool got_spec = (_specular_color != RGBColorf::zero()); + bool got_emit = (_emissive_color != RGBColorf::zero()); + if (got_spec || got_emit) { + EggMaterial temp(""); + temp.set_diff(_face_color); + if (got_spec) { + temp.set_shininess(_power); + temp.set_spec(Colorf(_specular_color[0], _specular_color[1], + _specular_color[2], 1.0)); + } + if (got_emit) { + temp.set_emit(Colorf(_emissive_color[0], _emissive_color[1], + _emissive_color[2], 1.0)); + } + EggMaterial *egg_mat = + materials.create_unique_material(temp, ~EggMaterial::E_mref_name); + egg_prim->set_material(egg_mat); + } + + // Also apply the face color. + egg_prim->set_color(_face_color); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::compare_to +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +int XFileMaterial:: +compare_to(const XFileMaterial &other) const { + int ct; + ct = _face_color.compare_to(other._face_color); + if (ct == 0) { + ct = (_power == other._power) ? 0 : ((_power < other._power) ? -1 : 1); + } + if (ct == 0) { + ct = _specular_color.compare_to(other._specular_color); + } + if (ct == 0) { + ct = _emissive_color.compare_to(other._emissive_color); + } + if (ct == 0) { + ct = strcmp(_texture.c_str(), other._texture.c_str()); + } + return ct; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::has_material +// Access: Public +// Description: Returns true if this material represents something +// meaningful, or false if the default material is +// sufficient. +//////////////////////////////////////////////////////////////////// +bool XFileMaterial:: +has_material() const { + return _has_material; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::has_texture +// Access: Public +// Description: Returns true if this material includes a texture map, +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool XFileMaterial:: +has_texture() const { + return _has_texture; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::make_material_data +// Access: Public +// Description: Fills the datagram with the raw data for the DX +// Material template. +//////////////////////////////////////////////////////////////////// +void XFileMaterial:: +make_material_data(Datagram &raw_data) { + raw_data.clear(); + raw_data.add_float32(_face_color[0]); + raw_data.add_float32(_face_color[1]); + raw_data.add_float32(_face_color[2]); + raw_data.add_float32(_face_color[3]); + raw_data.add_float32(_power); + raw_data.add_float32(_specular_color[0]); + raw_data.add_float32(_specular_color[1]); + raw_data.add_float32(_specular_color[2]); + raw_data.add_float32(_emissive_color[0]); + raw_data.add_float32(_emissive_color[1]); + raw_data.add_float32(_emissive_color[2]); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::make_texture_data +// Access: Public +// Description: Fills the datagram with the raw data for the DX +// TextureFilename template. +//////////////////////////////////////////////////////////////////// +void XFileMaterial:: +make_texture_data(Datagram &raw_data) { + raw_data.clear(); + + // Get a char * pointer to the texture filename, to pass into the + // Microsoft DX file interface. Unfortunately, we can't delete this + // again, since it needs to live longer than the life of the + // XFileMaterial object itself, so this becomes a memory leak + // (unless the DX file interface frees it, but the documentation is + // far from clear). Too bad. + string filename = _texture.to_os_specific(); + char *filename_str = strdup(filename.c_str()); + + // The Microsoft convention is to stuff a pointer into a four-byte + // field. Not terribly portable, but that's the interface. + raw_data.add_int32((int)filename_str); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::read_material_data +// Access: Public +// Description: Fills the structure based on the raw data from the +// Material template. +//////////////////////////////////////////////////////////////////// +bool XFileMaterial:: +read_material_data(const Datagram &raw_data) { + DatagramIterator di(raw_data); + + _face_color[0] = di.get_float32(); + _face_color[1] = di.get_float32(); + _face_color[2] = di.get_float32(); + _face_color[3] = di.get_float32(); + _power = di.get_float32(); + _specular_color[0] = di.get_float32(); + _specular_color[1] = di.get_float32(); + _specular_color[2] = di.get_float32(); + _emissive_color[0] = di.get_float32(); + _emissive_color[1] = di.get_float32(); + _emissive_color[2] = di.get_float32(); + _has_material = true; + + if (di.get_remaining_size() != 0) { + cerr << "Ignoring " << di.get_remaining_size() + << " trailing MeshMaterial.\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMaterial::read_texture_data +// Access: Public +// Description: Fills the structure based on the raw data from the +// TextureFilename template. +//////////////////////////////////////////////////////////////////// +bool XFileMaterial:: +read_texture_data(const Datagram &raw_data) { + DatagramIterator di(raw_data); + + // The Microsoft convention is to stuff a pointer into a four-byte + // field. Not terribly portable, but that's the interface. + const char *ptr = (const char *)di.get_int32(); + _texture = ptr; + _has_texture = true; + + if (di.get_remaining_size() != 0) { + cerr << "Ignoring " << di.get_remaining_size() + << " trailing MeshMaterial.\n"; + } + return true; +} diff --git a/pandatool/src/xfile/xFileMaterial.h b/pandatool/src/xfile/xFileMaterial.h new file mode 100644 index 0000000000..7ffcda1cfd --- /dev/null +++ b/pandatool/src/xfile/xFileMaterial.h @@ -0,0 +1,69 @@ +// Filename: xFileMaterial.h +// Created by: drose (19Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef XFILEMATERIAL_H +#define XFILEMATERIAL_H + +#include "pandatoolbase.h" +#include "luse.h" +#include "filename.h" + +class EggPrimitive; +class EggTextureCollection; +class EggMaterialCollection; +class Datagram; + +//////////////////////////////////////////////////////////////////// +// Class : XFileMaterial +// Description : This represents an X file "material", which consists +// of a color, lighting, and/or texture specification. +//////////////////////////////////////////////////////////////////// +class XFileMaterial { +public: + XFileMaterial(); + ~XFileMaterial(); + + void set_from_egg(EggPrimitive *egg_prim); + void apply_to_egg(EggPrimitive *egg_prim, + EggTextureCollection &textures, + EggMaterialCollection &materials); + + int compare_to(const XFileMaterial &other) const; + + bool has_material() const; + bool has_texture() const; + + void make_material_data(Datagram &raw_data); + void make_texture_data(Datagram &raw_data); + + bool read_material_data(const Datagram &raw_data); + bool read_texture_data(const Datagram &raw_data); + +private: + Colorf _face_color; + float _power; + RGBColorf _specular_color; + RGBColorf _emissive_color; + Filename _texture; + + bool _has_material; + bool _has_texture; +}; + +#endif + diff --git a/pandatool/src/xfile/xFileMesh.cxx b/pandatool/src/xfile/xFileMesh.cxx index 71bcc5ea6b..3ba268f7fd 100644 --- a/pandatool/src/xfile/xFileMesh.cxx +++ b/pandatool/src/xfile/xFileMesh.cxx @@ -20,6 +20,12 @@ #include "xFileFace.h" #include "xFileVertex.h" #include "xFileNormal.h" +#include "xFileMaterial.h" + +#include "eggVertexPool.h" +#include "eggVertex.h" +#include "eggPolygon.h" +#include "eggGroupNode.h" //////////////////////////////////////////////////////////////////// // Function: XFileMesh::Constructor @@ -31,6 +37,7 @@ XFileMesh() { _has_normals = false; _has_colors = false; _has_uvs = false; + _has_materials = false; } //////////////////////////////////////////////////////////////////// @@ -40,6 +47,16 @@ XFileMesh() { //////////////////////////////////////////////////////////////////// XFileMesh:: ~XFileMesh() { + clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::clear +// Access: Public +// Description: Empties all data from the mesh. +//////////////////////////////////////////////////////////////////// +void XFileMesh:: +clear() { Vertices::iterator vi; for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) { XFileVertex *vertex = (*vi); @@ -50,6 +67,25 @@ XFileMesh:: XFileNormal *normal = (*ni); delete normal; } + Materials::iterator mi; + for (mi = _materials.begin(); mi != _materials.end(); ++mi) { + XFileMaterial *material = (*mi); + delete material; + } + Faces::iterator fi; + for (fi = _faces.begin(); fi != _faces.end(); ++fi) { + XFileFace *face = (*fi); + delete face; + } + + _vertices.clear(); + _normals.clear(); + _materials.clear(); + _faces.clear(); + + _unique_vertices.clear(); + _unique_normals.clear(); + _unique_materials.clear(); } //////////////////////////////////////////////////////////////////// @@ -59,7 +95,8 @@ XFileMesh:: //////////////////////////////////////////////////////////////////// void XFileMesh:: add_polygon(EggPolygon *egg_poly) { - XFileFace *face = new XFileFace(this, egg_poly); + XFileFace *face = new XFileFace; + face->set_from_egg(this, egg_poly); _faces.push_back(face); } @@ -73,7 +110,8 @@ add_polygon(EggPolygon *egg_poly) { int XFileMesh:: add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) { int next_index = _vertices.size(); - XFileVertex *vertex = new XFileVertex(egg_vertex, egg_prim); + XFileVertex *vertex = new XFileVertex; + vertex->set_from_egg(egg_vertex, egg_prim); if (vertex->_has_color) { _has_colors = true; } @@ -107,7 +145,8 @@ add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) { int XFileMesh:: add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim) { int next_index = _normals.size(); - XFileNormal *normal = new XFileNormal(egg_vertex, egg_prim); + XFileNormal *normal = new XFileNormal; + normal->set_from_egg(egg_vertex, egg_prim); if (normal->_has_normal) { _has_normals = true; } @@ -127,6 +166,156 @@ add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim) { } } +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::add_material +// Access: Public +// Description: Creates a new XFileMaterial, if one does not already +// exist for the indicated material, and returns its +// index. +//////////////////////////////////////////////////////////////////// +int XFileMesh:: +add_material(EggPrimitive *egg_prim) { + int next_index = _materials.size(); + XFileMaterial *material = new XFileMaterial; + material->set_from_egg(egg_prim); + if (material->has_material()) { + _has_materials = true; + } + + pair result = + _unique_materials.insert(UniqueMaterials::value_type(material, next_index)); + + if (result.second) { + // Successfully added; this is a new material. + _materials.push_back(material); + return next_index; + } else { + // Not successfully added; there is already a material with these + // properties. Return that one instead. + delete material; + return (*result.first).second; + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::add_vertex +// Access: Public +// Description: Adds the newly-created XFileVertex unequivocally to +// the mesh, returning its index number. The XFileMesh +// object becomes the owner of the XFileVertex +// pointer, and will delete it when it destructs. +//////////////////////////////////////////////////////////////////// +int XFileMesh:: +add_vertex(XFileVertex *vertex) { + int next_index = _vertices.size(); + _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index)); + _vertices.push_back(vertex); + return next_index; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::add_normal +// Access: Public +// Description: Adds the newly-created XFileNormal unequivocally to +// the mesh, returning its index number. The XFileMesh +// object becomes the owner of the XFileNormal +// pointer, and will delete it when it destructs. +//////////////////////////////////////////////////////////////////// +int XFileMesh:: +add_normal(XFileNormal *normal) { + int next_index = _normals.size(); + _unique_normals.insert(UniqueNormals::value_type(normal, next_index)); + _normals.push_back(normal); + return next_index; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::add_material +// Access: Public +// Description: Adds the newly-created XFileMaterial unequivocally to +// the mesh, returning its index number. The XFileMesh +// object becomes the owner of the XFileMaterial +// pointer, and will delete it when it destructs. +//////////////////////////////////////////////////////////////////// +int XFileMesh:: +add_material(XFileMaterial *material) { + int next_index = _materials.size(); + _unique_materials.insert(UniqueMaterials::value_type(material, next_index)); + _materials.push_back(material); + return next_index; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::create_polygons +// Access: Public +// Description: Creates a slew of EggPolygons according to the faces +// in the mesh, and adds them to the indicated parent +// node. +//////////////////////////////////////////////////////////////////// +bool XFileMesh:: +create_polygons(EggGroupNode *egg_parent, + EggTextureCollection &textures, + EggMaterialCollection &materials) { + EggVertexPool *vpool = new EggVertexPool(get_name()); + egg_parent->add_child(vpool); + Faces::const_iterator fi; + for (fi = _faces.begin(); fi != _faces.end(); ++fi) { + XFileFace *face = (*fi); + + EggPolygon *egg_poly = new EggPolygon; + egg_parent->add_child(egg_poly); + + // Set up the vertices for the polygon. + XFileFace::Vertices::reverse_iterator vi; + for (vi = face->_vertices.rbegin(); vi != face->_vertices.rend(); ++vi) { + int vertex_index = (*vi)._vertex_index; + int normal_index = (*vi)._normal_index; + if (vertex_index < 0 || vertex_index >= (int)_vertices.size()) { + cerr << "Vertex index out of range in Mesh.\n"; + return false; + } + XFileVertex *vertex = _vertices[vertex_index]; + XFileNormal *normal = (XFileNormal *)NULL; + + if (normal_index >= 0 && normal_index < (int)_normals.size()) { + normal = _normals[normal_index]; + } + + // Create a temporary EggVertex before adding it to the pool. + EggVertex temp_vtx; + temp_vtx.set_pos(LCAST(double, vertex->_point)); + if (vertex->_has_color) { + temp_vtx.set_color(vertex->_color); + } + if (vertex->_has_uv) { + TexCoordd uv = LCAST(double, vertex->_uv); + // Windows draws the UV's upside-down. + uv[1] = 1.0 - uv[1]; + temp_vtx.set_uv(uv); + } + + if (normal != (XFileNormal *)NULL && normal->_has_normal) { + temp_vtx.set_normal(LCAST(double, normal->_normal)); + } + + // Now get a real EggVertex matching our template. + EggVertex *egg_vtx = vpool->create_unique_vertex(temp_vtx); + egg_poly->add_vertex(egg_vtx); + } + + // And apply the material for the polygon. + int material_index = face->_material_index; + if (material_index >= 0 && material_index < (int)_materials.size()) { + XFileMaterial *material = _materials[material_index]; + material->apply_to_egg(egg_poly, textures, materials); + } + + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: XFileMesh::has_normals // Access: Public @@ -160,6 +349,40 @@ has_uvs() const { return _has_uvs; } +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::has_materials +// Access: Public +// Description: Returns true if any of the faces added to this mesh +// used a real material, false otherwise. +//////////////////////////////////////////////////////////////////// +bool XFileMesh:: +has_materials() const { + return _has_materials; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::get_num_materials +// Access: Public +// Description: Returns the number of distinct materials associated +// with the mesh. +//////////////////////////////////////////////////////////////////// +int XFileMesh:: +get_num_materials() const { + return _materials.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::get_material +// Access: Public +// Description: Returns a pointer to the nth materials associated +// with the mesh. +//////////////////////////////////////////////////////////////////// +XFileMaterial *XFileMesh:: +get_material(int n) const { + nassertr(n >= 0 && n < (int)_materials.size(), (XFileMaterial *)NULL); + return _materials[n]; +} + //////////////////////////////////////////////////////////////////// // Function: XFileMesh::make_mesh_data // Access: Public @@ -274,3 +497,222 @@ make_uv_data(Datagram &raw_data) { raw_data.add_float32(uv[1]); } } + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::make_material_list_data +// Access: Public +// Description: Fills the datagram with the raw data for the DX +// MeshMaterialList template. +//////////////////////////////////////////////////////////////////// +void XFileMesh:: +make_material_list_data(Datagram &raw_data) { + raw_data.clear(); + raw_data.add_int32(_materials.size()); + raw_data.add_int32(_faces.size()); + Faces::const_iterator fi; + for (fi = _faces.begin(); fi != _faces.end(); ++fi) { + XFileFace *face = (*fi); + raw_data.add_int32(face->_material_index); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::read_mesh_data +// Access: Public +// Description: Fills the structure based on the raw data from the +// Mesh template. +//////////////////////////////////////////////////////////////////// +bool XFileMesh:: +read_mesh_data(const Datagram &raw_data) { + DatagramIterator di(raw_data); + + clear(); + + int i, j; + int num_vertices = di.get_int32(); + for (i = 0; i < num_vertices; i++) { + XFileVertex *vertex = new XFileVertex; + vertex->_point[0] = di.get_float32(); + vertex->_point[1] = di.get_float32(); + vertex->_point[2] = di.get_float32(); + add_vertex(vertex); + } + + int num_faces = di.get_int32(); + for (i = 0; i < num_faces; i++) { + XFileFace *face = new XFileFace; + + num_vertices = di.get_int32(); + for (j = 0; j < num_vertices; j++) { + XFileFace::Vertex vertex; + vertex._vertex_index = di.get_int32(); + vertex._normal_index = -1; + + face->_vertices.push_back(vertex); + } + _faces.push_back(face); + } + + if (di.get_remaining_size() != 0) { + cerr << "Ignoring " << di.get_remaining_size() << " trailing Mesh.\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::read_normal_data +// Access: Public +// Description: Fills the structure based on the raw data from the +// MeshNormals template. +//////////////////////////////////////////////////////////////////// +bool XFileMesh:: +read_normal_data(const Datagram &raw_data) { + DatagramIterator di(raw_data); + + int num_normals = di.get_int32(); + int i; + for (i = 0; i < num_normals; i++) { + XFileNormal *normal = new XFileNormal; + normal->_normal[0] = di.get_float32(); + normal->_normal[1] = di.get_float32(); + normal->_normal[2] = di.get_float32(); + normal->_has_normal = true; + add_normal(normal); + } + + int num_faces = di.get_int32(); + + if (num_faces != _faces.size()) { + cerr << "Incorrect number of faces in MeshNormals.\n"; + return false; + } + + for (i = 0; i < num_faces; i++) { + XFileFace *face = _faces[i]; + int num_vertices = di.get_int32(); + if (num_vertices != face->_vertices.size()) { + cerr << "Incorrect number of vertices for face in MeshNormals.\n"; + return false; + } + for (int j = 0; j < num_vertices; j++) { + face->_vertices[j]._normal_index = di.get_int32(); + } + } + + if (di.get_remaining_size() != 0) { + cerr << "Ignoring " << di.get_remaining_size() + << " trailing MeshNormals.\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::read_color_data +// Access: Public +// Description: Fills the structure based on the raw data from the +// MeshVertexColors template. +//////////////////////////////////////////////////////////////////// +bool XFileMesh:: +read_color_data(const Datagram &raw_data) { + DatagramIterator di(raw_data); + + int num_colors = di.get_int32(); + int i; + for (i = 0; i < num_colors; i++) { + int vertex_index = di.get_int32(); + if (vertex_index < 0 || vertex_index >= _vertices.size()) { + cerr << "Vertex index out of range in MeshVertexColors.\n"; + return false; + } + XFileVertex *vertex = _vertices[vertex_index]; + vertex->_color[0] = di.get_float32(); + vertex->_color[1] = di.get_float32(); + vertex->_color[2] = di.get_float32(); + vertex->_color[3] = di.get_float32(); + vertex->_has_color = true; + } + + if (di.get_remaining_size() != 0) { + cerr << "Ignoring " << di.get_remaining_size() + << " trailing MeshVertexColors.\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::read_uv_data +// Access: Public +// Description: Fills the structure based on the raw data from the +// MeshTextureCoords template. +//////////////////////////////////////////////////////////////////// +bool XFileMesh:: +read_uv_data(const Datagram &raw_data) { + DatagramIterator di(raw_data); + + int num_vertices = di.get_int32(); + if (num_vertices != _vertices.size()) { + cerr << "Wrong number of vertices in MeshTextureCoords.\n"; + return false; + } + + int i; + for (i = 0; i < num_vertices; i++) { + XFileVertex *vertex = _vertices[i]; + vertex->_uv[0] = di.get_float32(); + vertex->_uv[1] = di.get_float32(); + vertex->_has_uv = true; + } + + if (di.get_remaining_size() != 0) { + cerr << "Ignoring " << di.get_remaining_size() + << " trailing MeshTextureCoords.\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileMesh::read_material_list_data +// Access: Public +// Description: Fills the structure based on the raw data from the +// MaterialList template. +//////////////////////////////////////////////////////////////////// +bool XFileMesh:: +read_material_list_data(const Datagram &raw_data) { + DatagramIterator di(raw_data); + + di.get_int32(); /* num_materials */ + int num_faces = di.get_int32(); + + if (num_faces > _faces.size()) { + cerr << "Too many faces in MaterialList.\n"; + return false; + } + + int material_index = -1; + int i = 0; + while (i < num_faces) { + XFileFace *face = _faces[i]; + material_index = di.get_int32(); + face->_material_index = material_index; + i++; + } + + // The rest of the faces get the same material index as the last + // one in the list. + while (i < (int)_faces.size()) { + XFileFace *face = _faces[i]; + face->_material_index = material_index; + i++; + } + + if (di.get_remaining_size() != 0) { + cerr << "Ignoring " << di.get_remaining_size() + << " trailing MeshMaterialList.\n"; + } + + return true; +} diff --git a/pandatool/src/xfile/xFileMesh.h b/pandatool/src/xfile/xFileMesh.h index ce9fad5cfc..307e6ea253 100644 --- a/pandatool/src/xfile/xFileMesh.h +++ b/pandatool/src/xfile/xFileMesh.h @@ -23,56 +23,88 @@ #include "pvector.h" #include "pmap.h" #include "indirectCompareTo.h" +#include "namable.h" class XFileMesh; class XFileVertex; class XFileNormal; +class XFileMaterial; class XFileFace; +class EggGroupNode; class EggVertex; class EggPolygon; class EggPrimitive; +class EggTextureCollection; +class EggMaterialCollection; class Datagram; //////////////////////////////////////////////////////////////////// // Class : XFileMesh // Description : This is a collection of polygons; i.e. a polyset. //////////////////////////////////////////////////////////////////// -class XFileMesh { +class XFileMesh : public Namable { public: XFileMesh(); ~XFileMesh(); + void clear(); + void add_polygon(EggPolygon *egg_poly); int add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim); int add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim); + int add_material(EggPrimitive *egg_prim); + + int add_vertex(XFileVertex *vertex); + int add_normal(XFileNormal *normal); + int add_material(XFileMaterial *material); + + bool create_polygons(EggGroupNode *egg_parent, + EggTextureCollection &textures, + EggMaterialCollection &materials); bool has_normals() const; bool has_colors() const; bool has_uvs() const; + bool has_materials() const; + + int get_num_materials() const; + XFileMaterial *get_material(int n) const; void make_mesh_data(Datagram &raw_data); void make_normal_data(Datagram &raw_data); void make_color_data(Datagram &raw_data); void make_uv_data(Datagram &raw_data); + void make_material_list_data(Datagram &raw_data); + + bool read_mesh_data(const Datagram &raw_data); + bool read_normal_data(const Datagram &raw_data); + bool read_color_data(const Datagram &raw_data); + bool read_uv_data(const Datagram &raw_data); + bool read_material_list_data(const Datagram &raw_data); private: typedef pvector Vertices; typedef pvector Normals; + typedef pvector Materials; typedef pvector Faces; Vertices _vertices; Normals _normals; + Materials _materials; Faces _faces; private: typedef pmap > UniqueVertices; typedef pmap > UniqueNormals; + typedef pmap > UniqueMaterials; UniqueVertices _unique_vertices; UniqueNormals _unique_normals; + UniqueMaterials _unique_materials; bool _has_normals; bool _has_colors; bool _has_uvs; + bool _has_materials; }; #endif diff --git a/pandatool/src/xfile/xFileNormal.cxx b/pandatool/src/xfile/xFileNormal.cxx index 4efa3003db..5719630d4f 100644 --- a/pandatool/src/xfile/xFileNormal.cxx +++ b/pandatool/src/xfile/xFileNormal.cxx @@ -26,15 +26,24 @@ // Description: //////////////////////////////////////////////////////////////////// XFileNormal:: -XFileNormal(EggVertex *egg_vertex, EggPrimitive *egg_prim) { - _has_normal = true; +XFileNormal() { + _normal.set(0.0, 0.0, 0.0); + _has_normal = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileNormal::set_from_egg +// Access: Public +// Description: Sets the structure up from the indicated egg data. +//////////////////////////////////////////////////////////////////// +void XFileNormal:: +set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim) { if (egg_vertex->has_normal()) { _normal = LCAST(float, egg_vertex->get_normal()); + _has_normal = true; } else if (egg_prim->has_normal()) { _normal = LCAST(float, egg_prim->get_normal()); - } else { - _normal.set(0.0, 0.0, 0.0); - _has_normal = false; + _has_normal = true; } } diff --git a/pandatool/src/xfile/xFileNormal.h b/pandatool/src/xfile/xFileNormal.h index 85ced209a4..66f42e6a97 100644 --- a/pandatool/src/xfile/xFileNormal.h +++ b/pandatool/src/xfile/xFileNormal.h @@ -34,7 +34,8 @@ class EggPrimitive; //////////////////////////////////////////////////////////////////// class XFileNormal { public: - XFileNormal(EggVertex *egg_vertex, EggPrimitive *egg_prim); + XFileNormal(); + void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim); int compare_to(const XFileNormal &other) const; Normalf _normal; diff --git a/pandatool/src/xfile/xFileToEgg.cxx b/pandatool/src/xfile/xFileToEgg.cxx new file mode 100644 index 0000000000..85196b523a --- /dev/null +++ b/pandatool/src/xfile/xFileToEgg.cxx @@ -0,0 +1,78 @@ +// Filename: xFileToEgg.cxx +// Created by: drose (21Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "xFileToEgg.h" +#include "xFileToEggConverter.h" + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEgg::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileToEgg:: +XFileToEgg() : + SomethingToEgg("DirectX", ".x") +{ + add_normals_options(); + add_transform_options(); + add_texture_path_options(); + add_rel_dir_options(); + add_search_path_options(false); + + set_program_description + ("This program converts DirectX retained-mode (.x) files to egg. This " + "is a simple file format that only supports basic polygons, materials, " + "and textures, in a hierarchy."); + + redescribe_option + ("cs", + "Specify the coordinate system of the input " + _format_name + + " file. Normally, this is y-up-left."); + + _coordinate_system = CS_yup_left; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEgg::run +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void XFileToEgg:: +run() { + _data.set_coordinate_system(_coordinate_system); + + XFileToEggConverter converter; + converter.set_egg_data(&_data, false); + converter.set_texture_path_convert(_texture_path_convert, _make_rel_dir); + + if (!converter.convert_file(_input_filename)) { + nout << "Unable to read " << _input_filename << "\n"; + exit(1); + } + + write_egg_file(); + nout << "\n"; +} + + +int main(int argc, char *argv[]) { + XFileToEgg prog; + prog.parse_command_line(argc, argv); + prog.run(); + return 0; +} diff --git a/pandatool/src/xfile/xFileToEgg.h b/pandatool/src/xfile/xFileToEgg.h new file mode 100644 index 0000000000..6ee3deec3c --- /dev/null +++ b/pandatool/src/xfile/xFileToEgg.h @@ -0,0 +1,41 @@ +// Filename: xFileToEgg.h +// Created by: drose (21Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef XFILETOEGG_H +#define XFILETOEGG_H + +#include "pandatoolbase.h" +#include "somethingToEgg.h" +#include "xFileToEggConverter.h" + +#include "dSearchPath.h" + +//////////////////////////////////////////////////////////////////// +// Class : XFileToEgg +// Description : A program to read a DirectX "x" file and generate an +// egg file. +//////////////////////////////////////////////////////////////////// +class XFileToEgg : public SomethingToEgg { +public: + XFileToEgg(); + + void run(); +}; + +#endif + diff --git a/pandatool/src/xfile/xFileToEggConverter.cxx b/pandatool/src/xfile/xFileToEggConverter.cxx new file mode 100644 index 0000000000..08830278a9 --- /dev/null +++ b/pandatool/src/xfile/xFileToEggConverter.cxx @@ -0,0 +1,713 @@ +// Filename: xFileToEggConverter.cxx +// Created by: drose (21Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "xFileToEggConverter.h" +#include "xFileMesh.h" +#include "xFileMaterial.h" +#include "eggData.h" +#include "eggGroup.h" +#include "datagram.h" + +// This must be included only in exactly one .cxx file, since +// including defines the structure! +#include + + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileToEggConverter:: +XFileToEggConverter() { + _dx_file = NULL; + _dx_file_enum = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileToEggConverter:: +XFileToEggConverter(const XFileToEggConverter ©) : + SomethingToEggConverter(copy) +{ + _dx_file = NULL; + _dx_file_enum = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileToEggConverter:: +~XFileToEggConverter() { + close(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::make_copy +// Access: Public, Virtual +// Description: Allocates and returns a new copy of the converter. +//////////////////////////////////////////////////////////////////// +SomethingToEggConverter *XFileToEggConverter:: +make_copy() { + return new XFileToEggConverter(*this); +} + + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::get_name +// Access: Public, Virtual +// Description: Returns the English name of the file type this +// converter supports. +//////////////////////////////////////////////////////////////////// +string XFileToEggConverter:: +get_name() const { + return "DirectX"; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::get_extension +// Access: Public, Virtual +// Description: Returns the common extension of the file type this +// converter supports. +//////////////////////////////////////////////////////////////////// +string XFileToEggConverter:: +get_extension() const { + return "x"; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_file +// Access: Public, Virtual +// Description: Handles the reading of the input file and converting +// it to egg. Returns true if successful, false +// otherwise. +// +// This is designed to be as generic as possible, +// generally in support of run-time loading. +// Command-line converters may choose to use +// convert_flt() instead, as it provides more control. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_file(const Filename &filename) { + HRESULT hr; + + close(); + hr = DirectXFileCreate(&_dx_file); + if (hr != DXFILE_OK) { + nout << "Unable to create X interface.\n"; + return false; + } + + // Register our templates. + hr = _dx_file->RegisterTemplates(D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES); + if (hr != DXFILE_OK) { + nout << "Unable to register templates.\n"; + return false; + } + + string os_file = filename.to_os_specific(); + hr = _dx_file->CreateEnumObject + ((void *)os_file.c_str(), DXFILELOAD_FROMFILE, &_dx_file_enum); + if (hr != DXFILE_OK) { + nout << "Unable to open X file: " << os_file << "\n"; + return false; + } + + return get_toplevel(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::close +// Access: Public +// Description: Finalizes and closes the file previously opened via +// convert_file(). +//////////////////////////////////////////////////////////////////// +void XFileToEggConverter:: +close() { + if (_dx_file != NULL) { + if (_dx_file_enum != NULL) { + _dx_file_enum->Release(); + _dx_file_enum = NULL; + } + _dx_file->Release(); + _dx_file = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::get_toplevel +// Access: Private +// Description: Pulls off all of the top-level objects in the .x file +// and converts them, and their descendents, to the +// appropriate egg structures. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +get_toplevel() { + HRESULT hr; + LPDIRECTXFILEDATA obj; + + hr = _dx_file_enum->GetNextDataObject(&obj); + while (hr == DXFILE_OK) { + if (!convert_data_object(obj, _egg_data)) { + return false; + } + hr = _dx_file_enum->GetNextDataObject(&obj); + } + + if (hr != DXFILEERR_NOMOREOBJECTS) { + cerr << "Error extracting top-level objects.\n"; + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_object +// Access: Private +// Description: Converts the indicated object to the appropriate egg +// structures. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent) { + HRESULT hr; + LPDIRECTXFILEDATA data_obj; + + // See if the object is a data object. + hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj); + if (hr == DD_OK) { + // It is. + return convert_data_object(data_obj, egg_parent); + } + + // It isn't. + cerr << "Ignoring object of unknown type: " << get_object_name(obj) + << "\n"; + return true; +} + + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_data_object +// Access: Private +// Description: Converts the indicated object to the appropriate egg +// structures. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) { + HRESULT hr; + + // Determine what type of data object we have. + const GUID *type; + hr = obj->GetType(&type); + if (hr != DXFILE_OK) { + cerr << "Unable to get type of template\n"; + return false; + } + + if (*type == TID_D3DRMFrame) { + if (!convert_frame(obj, egg_parent)) { + return false; + } + } else if (*type == TID_D3DRMMesh) { + if (!convert_mesh(obj, egg_parent)) { + return false; + } + } else { + cerr << "Ignoring data object of unknown type: " << get_object_name(obj) + << "\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_frame +// Access: Private +// Description: Converts the indicated frame to the appropriate egg +// structures. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) { + HRESULT hr; + + string name = get_object_name(obj); + EggGroup *group = new EggGroup(name); + egg_parent->add_child(group); + + // Now walk through the children of the frame. + LPDIRECTXFILEOBJECT child_obj; + + hr = obj->GetNextObject(&child_obj); + while (hr == DXFILE_OK) { + if (!convert_object(child_obj, group)) { + return false; + } + hr = obj->GetNextObject(&child_obj); + } + + if (hr != DXFILEERR_NOMOREOBJECTS) { + cerr << "Error extracting children of frame " << name << ".\n"; + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_mesh +// Access: Private +// Description: Converts the indicated mesh to the appropriate egg +// structures. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) { + HRESULT hr; + + Datagram raw_data; + if (!get_data(obj, raw_data)) { + return false; + } + + XFileMesh mesh; + mesh.set_name(get_object_name(obj)); + if (!mesh.read_mesh_data(raw_data)) { + return false; + } + + // Now process all the child objects of the mesh. + LPDIRECTXFILEOBJECT child_obj; + + hr = obj->GetNextObject(&child_obj); + while (hr == DXFILE_OK) { + if (!convert_mesh_object(child_obj, mesh)) { + return false; + } + hr = obj->GetNextObject(&child_obj); + } + + if (hr != DXFILEERR_NOMOREOBJECTS) { + cerr << "Error extracting children of mesh " << get_object_name(obj) + << ".\n"; + return false; + } + + if (!mesh.create_polygons(egg_parent, _textures, _materials)) { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_mesh_object +// Access: Private +// Description: Converts the indicated object, a child of a Mesh, to +// the appropriate egg structures. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) { + HRESULT hr; + LPDIRECTXFILEDATA data_obj; + + // See if the object is a data object. + hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj); + if (hr == DD_OK) { + // It is. + return convert_mesh_data_object(data_obj, mesh); + } + + // It isn't. + cerr << "Ignoring object of unknown type: " << get_object_name(obj) + << "\n"; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_mesh_data_object +// Access: Private +// Description: Converts the indicated data object, a child of a +// Mesh, to the appropriate egg structures. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) { + HRESULT hr; + + // Determine what type of data object we have. + const GUID *type; + hr = obj->GetType(&type); + if (hr != DXFILE_OK) { + cerr << "Unable to get type of template\n"; + return false; + } + + if (*type == TID_D3DRMMeshNormals) { + if (!convert_mesh_normals(obj, mesh)) { + return false; + } + + } else if (*type == TID_D3DRMMeshVertexColors) { + if (!convert_mesh_colors(obj, mesh)) { + return false; + } + + } else if (*type == TID_D3DRMMeshTextureCoords) { + if (!convert_mesh_uvs(obj, mesh)) { + return false; + } + + } else if (*type == TID_D3DRMMeshMaterialList) { + if (!convert_mesh_material_list(obj, mesh)) { + return false; + } + + } else { + cerr << "Ignoring data object of unknown type: " << get_object_name(obj) + << "\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_mesh_normals +// Access: Private +// Description: Converts the indicated MeshNormals template +// object. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_mesh_normals(LPDIRECTXFILEDATA obj, XFileMesh &mesh) { + Datagram raw_data; + if (!get_data(obj, raw_data)) { + return false; + } + + if (!mesh.read_normal_data(raw_data)) { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_mesh_colors +// Access: Private +// Description: Converts the indicated MeshVertexColors template +// object. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_mesh_colors(LPDIRECTXFILEDATA obj, XFileMesh &mesh) { + Datagram raw_data; + if (!get_data(obj, raw_data)) { + return false; + } + + if (!mesh.read_color_data(raw_data)) { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_mesh_uvs +// Access: Private +// Description: Converts the indicated MeshTextureCoords template +// object. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_mesh_uvs(LPDIRECTXFILEDATA obj, XFileMesh &mesh) { + Datagram raw_data; + if (!get_data(obj, raw_data)) { + return false; + } + + if (!mesh.read_uv_data(raw_data)) { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_mesh_material_list +// Access: Private +// Description: Converts the indicated MeshMaterialList template +// object. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_mesh_material_list(LPDIRECTXFILEDATA obj, XFileMesh &mesh) { + HRESULT hr; + + Datagram raw_data; + if (!get_data(obj, raw_data)) { + return false; + } + + if (!mesh.read_material_list_data(raw_data)) { + return false; + } + + // Now we need to process the children of the material list. These + // will be the materials. + LPDIRECTXFILEOBJECT child_obj; + + hr = obj->GetNextObject(&child_obj); + while (hr == DXFILE_OK) { + if (!convert_material_list_object(child_obj, mesh)) { + return false; + } + hr = obj->GetNextObject(&child_obj); + } + + if (hr != DXFILEERR_NOMOREOBJECTS) { + cerr << "Error extracting children of MeshMaterialList " + << get_object_name(obj) << ".\n"; + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_material_list_object +// Access: Private +// Description: Converts the indicated object, a child of a +// MeshMaterialList. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_material_list_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) { + HRESULT hr; + LPDIRECTXFILEDATA data_obj; + + // See if the object is a data object. + hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj); + if (hr == DD_OK) { + // It is. + return convert_material_list_data_object(data_obj, mesh); + } + + // It isn't. + cerr << "Ignoring object of unknown type: " << get_object_name(obj) + << "\n"; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_material_list_data_object +// Access: Private +// Description: Converts the indicated data object, a child of a +// MeshMaterialList. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_material_list_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) { + HRESULT hr; + + // Determine what type of data object we have. + const GUID *type; + hr = obj->GetType(&type); + if (hr != DXFILE_OK) { + cerr << "Unable to get type of template\n"; + return false; + } + + if (*type == TID_D3DRMMaterial) { + if (!convert_material(obj, mesh)) { + return false; + } + } else { + cerr << "Ignoring data object of unknown type: " << get_object_name(obj) + << "\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_material +// Access: Private +// Description: Converts the indicated Material template object. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_material(LPDIRECTXFILEDATA obj, XFileMesh &mesh) { + HRESULT hr; + + Datagram raw_data; + if (!get_data(obj, raw_data)) { + return false; + } + + XFileMaterial *material = new XFileMaterial; + + if (!material->read_material_data(raw_data)) { + delete material; + return false; + } + + mesh.add_material(material); + + // Now we need to process the children of the material. There + // should only be one, and it will be a texture. + LPDIRECTXFILEOBJECT child_obj; + + hr = obj->GetNextObject(&child_obj); + while (hr == DXFILE_OK) { + if (!convert_material_object(child_obj, *material)) { + return false; + } + hr = obj->GetNextObject(&child_obj); + } + + if (hr != DXFILEERR_NOMOREOBJECTS) { + cerr << "Error extracting children of Material " + << get_object_name(obj) << ".\n"; + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_material_object +// Access: Private +// Description: Converts the indicated object, a child of a +// Material. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material) { + HRESULT hr; + LPDIRECTXFILEDATA data_obj; + + // See if the object is a data object. + hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj); + if (hr == DD_OK) { + // It is. + return convert_material_data_object(data_obj, material); + } + + // It isn't. + cerr << "Ignoring object of unknown type: " << get_object_name(obj) + << "\n"; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_material_data_object +// Access: Private +// Description: Converts the indicated data object, a child of a +// Material. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_material_data_object(LPDIRECTXFILEDATA obj, XFileMaterial &material) { + HRESULT hr; + + // Determine what type of data object we have. + const GUID *type; + hr = obj->GetType(&type); + if (hr != DXFILE_OK) { + cerr << "Unable to get type of template\n"; + return false; + } + + if (*type == TID_D3DRMTextureFilename) { + if (!convert_texture(obj, material)) { + return false; + } + } else { + cerr << "Ignoring data object of unknown type: " << get_object_name(obj) + << "\n"; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::convert_texture +// Access: Private +// Description: Converts the indicated TextureFilename template object. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +convert_texture(LPDIRECTXFILEDATA obj, XFileMaterial &material) { + Datagram raw_data; + if (!get_data(obj, raw_data)) { + return false; + } + + if (!material.read_texture_data(raw_data)) { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::get_object_name +// Access: Private +// Description: Returns the name of the indicated object. +//////////////////////////////////////////////////////////////////// +string XFileToEggConverter:: +get_object_name(LPDIRECTXFILEOBJECT obj) { + HRESULT hr; + + DWORD length = 0; + obj->GetName(NULL, &length); + + if (length == 0) { + return string(); + } + + char *buffer = new char[length]; + hr = obj->GetName(buffer, &length); + + string result; + if (hr != DXFILE_OK) { + cerr << "Unable to get object name.\n"; + } else { + result = buffer; + } + + delete[] buffer; + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileToEggConverter::get_data +// Access: Private +// Description: Extracts out the raw data for the indicated object. +//////////////////////////////////////////////////////////////////// +bool XFileToEggConverter:: +get_data(LPDIRECTXFILEDATA obj, Datagram &raw_data) { + HRESULT hr; + DWORD length; + void *data; + hr = obj->GetData(NULL, &length, &data); + if (hr != DXFILE_OK) { + cerr << "Unable to get data for " << get_object_name(obj) << "\n"; + return false; + } + + raw_data.clear(); + raw_data.append_data(data, length); + + return true; +} diff --git a/pandatool/src/xfile/xFileToEggConverter.h b/pandatool/src/xfile/xFileToEggConverter.h new file mode 100644 index 0000000000..a0963af7e1 --- /dev/null +++ b/pandatool/src/xfile/xFileToEggConverter.h @@ -0,0 +1,87 @@ +// Filename: xFileToEggConverter.h +// Created by: drose (21Jun01) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef XFILETOEGGCONVERTER_H +#define XFILETOEGGCONVERTER_H + +#include "pandatoolbase.h" +#include "somethingToEggConverter.h" +#include "eggTextureCollection.h" +#include "eggMaterialCollection.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#undef WIN32_LEAN_AND_MEAN + +class EggGroupNode; +class Datagram; +class XFileMesh; +class XFileMaterial; + +//////////////////////////////////////////////////////////////////// +// Class : XFileToEggConverter +// Description : +//////////////////////////////////////////////////////////////////// +class XFileToEggConverter : public SomethingToEggConverter { +public: + XFileToEggConverter(); + XFileToEggConverter(const XFileToEggConverter ©); + ~XFileToEggConverter(); + + virtual SomethingToEggConverter *make_copy(); + + virtual string get_name() const; + virtual string get_extension() const; + + virtual bool convert_file(const Filename &filename); + void close(); + +private: + bool get_toplevel(); + bool convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent); + bool convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent); + bool convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent); + bool convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent); + + bool convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh); + bool convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh); + bool convert_mesh_normals(LPDIRECTXFILEDATA obj, XFileMesh &mesh); + bool convert_mesh_colors(LPDIRECTXFILEDATA obj, XFileMesh &mesh); + bool convert_mesh_uvs(LPDIRECTXFILEDATA obj, XFileMesh &mesh); + bool convert_mesh_material_list(LPDIRECTXFILEDATA obj, XFileMesh &mesh); + bool convert_material_list_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh); + bool convert_material_list_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh); + bool convert_material(LPDIRECTXFILEDATA obj, XFileMesh &mesh); + bool convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material); + bool convert_material_data_object(LPDIRECTXFILEDATA obj, XFileMaterial &material); + bool convert_texture(LPDIRECTXFILEDATA obj, XFileMaterial &material); + + string get_object_name(LPDIRECTXFILEOBJECT obj); + bool get_data(LPDIRECTXFILEDATA obj, Datagram &raw_data); + + LPDIRECTXFILE _dx_file; + LPDIRECTXFILEENUMOBJECT _dx_file_enum; + + EggTextureCollection _textures; + EggMaterialCollection _materials; +}; + +#endif diff --git a/pandatool/src/xfile/xFileVertex.cxx b/pandatool/src/xfile/xFileVertex.cxx index b960dd5633..c14696293f 100644 --- a/pandatool/src/xfile/xFileVertex.cxx +++ b/pandatool/src/xfile/xFileVertex.cxx @@ -26,25 +26,45 @@ // Description: //////////////////////////////////////////////////////////////////// XFileVertex:: -XFileVertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) { - _has_color = true; - _has_uv = true; +XFileVertex() { + _has_color = false; + _has_uv = false; + _point.set(0.0, 0.0, 0.0); + _uv.set(0.0, 0.0); + _color.set(1.0, 1.0, 1.0, 1.0); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileVertex::set_from_egg +// Access: Public +// Description: Sets the structure up from the indicated egg data. +//////////////////////////////////////////////////////////////////// +void XFileVertex:: +set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim) { _point = LCAST(float, egg_vertex->get_pos3()); if (egg_vertex->has_uv()) { - _uv = LCAST(float, egg_vertex->get_uv()); - } else { - _uv.set(0.0, 0.0); - _has_uv = false; + TexCoordd uv = egg_vertex->get_uv(); + if (egg_prim->has_texture()) { + // Check if there's a texture matrix on the texture. + EggTexture *egg_tex = egg_prim->get_texture(); + if (egg_tex->has_transform()) { + uv = uv * egg_tex->get_transform(); + } + } + + _uv[0] = uv[0]; + // Windows draws the UV's upside-down. + _uv[1] = 1.0 - uv[1]; + _has_uv = true; } if (egg_vertex->has_color()) { _color = egg_vertex->get_color(); + _has_color = true; } else if (egg_prim->has_color()) { _color = egg_prim->get_color(); - } else { - _color.set(1.0, 1.0, 1.0, 1.0); - _has_color = false; + _has_color = true; } } diff --git a/pandatool/src/xfile/xFileVertex.h b/pandatool/src/xfile/xFileVertex.h index a8284c22c4..a757d97404 100644 --- a/pandatool/src/xfile/xFileVertex.h +++ b/pandatool/src/xfile/xFileVertex.h @@ -32,7 +32,8 @@ class EggPrimitive; //////////////////////////////////////////////////////////////////// class XFileVertex { public: - XFileVertex(EggVertex *egg_vertex, EggPrimitive *egg_poly); + XFileVertex(); + void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_poly); int compare_to(const XFileVertex &other) const; Vertexf _point;