Panda3D
 All Classes Functions Variables Enumerations
xFileMaker.cxx
00001 // Filename: xFileMaker.cxx
00002 // Created by:  drose (19Jun01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "xFileMaker.h"
00016 #include "xFileMesh.h"
00017 #include "xFileMaterial.h"
00018 #include "config_xfile.h"
00019 
00020 #include "pnotify.h"
00021 #include "eggGroupNode.h"
00022 #include "eggGroup.h"
00023 #include "eggBin.h"
00024 #include "eggPolysetMaker.h"
00025 #include "eggVertexPool.h"
00026 #include "eggVertex.h"
00027 #include "eggPolygon.h"
00028 #include "eggData.h"
00029 #include "pvector.h"
00030 #include "vector_int.h"
00031 #include "string_utils.h"
00032 #include "datagram.h"
00033 
00034 ////////////////////////////////////////////////////////////////////
00035 //     Function: XFileMaker::Constructor
00036 //       Access: Public
00037 //  Description:
00038 ////////////////////////////////////////////////////////////////////
00039 XFileMaker::
00040 XFileMaker() {
00041   _mesh_index = 0;
00042   _x_file = new XFile;
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: XFileMaker::Destructor
00047 //       Access: Public
00048 //  Description:
00049 ////////////////////////////////////////////////////////////////////
00050 XFileMaker::
00051 ~XFileMaker() {
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: XFileMaker::write
00056 //       Access: Public
00057 //  Description: Writes the .x file data to the indicated filename;
00058 //               returns true on success, false otherwise.
00059 ////////////////////////////////////////////////////////////////////
00060 bool XFileMaker::
00061 write(const Filename &filename) {
00062   return _x_file->write(filename);
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: XFileMaker::add_tree
00067 //       Access: Public
00068 //  Description: Adds the egg tree rooted at the indicated node to the
00069 //               X structure.  This may be somewhat destructive of
00070 //               the egg tree.  Returns true on success, false on
00071 //               failure.
00072 ////////////////////////////////////////////////////////////////////
00073 bool XFileMaker::
00074 add_tree(EggData *egg_data) {
00075   _meshes.clear();
00076 
00077   // Now collect all the polygons together into polysets.
00078   EggPolysetMaker pmaker;
00079   pmaker.make_bins(egg_data);
00080 
00081   // And now we're ready to traverse the egg hierarchy.
00082   if (!recurse_nodes(egg_data, _x_file)) {
00083     return false;
00084   }
00085 
00086   // Create X structures for all of the meshes we built up.
00087   Meshes::iterator mi;
00088   for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
00089     if (!finalize_mesh((*mi).first, (*mi).second)) {
00090       return false;
00091     }
00092   }
00093   _meshes.clear();
00094 
00095   return true;
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: XFileMaker::add_node
00100 //       Access: Private
00101 //  Description: Adds the node to the DX structure, in whatever form
00102 //               it is supported.
00103 ////////////////////////////////////////////////////////////////////
00104 bool XFileMaker::
00105 add_node(EggNode *egg_node, XFileNode *x_parent) {
00106   if (egg_node->is_of_type(EggBin::get_class_type())) {
00107     return add_bin(DCAST(EggBin, egg_node), x_parent);
00108 
00109   } else if (egg_node->is_of_type(EggGroup::get_class_type())) {
00110     return add_group(DCAST(EggGroup, egg_node), x_parent);
00111 
00112   } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
00113     // A grouping node of some kind.
00114     EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
00115 
00116     if (xfile_one_mesh) {
00117       // Don't create any additional frames representing the egg
00118       // hierarchy.
00119       if (!recurse_nodes(egg_group, x_parent)) {
00120         return false;
00121       }
00122 
00123     } else {
00124       // Create a Frame for each EggGroup.
00125       XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
00126 
00127       if (!recurse_nodes(egg_group, x_frame)) {
00128         return false;
00129       }
00130     }
00131     
00132     return true;
00133   }
00134 
00135   // Some unsupported node type.  Ignore it.
00136   return true;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: XFileMaker::add_group
00141 //       Access: Private
00142 //  Description: Adds a frame for the indicated group node.
00143 ////////////////////////////////////////////////////////////////////
00144 bool XFileMaker::
00145 add_group(EggGroup *egg_group, XFileNode *x_parent) {
00146   if (xfile_one_mesh) {
00147     // Don't create any additional frames representing the egg
00148     // hierarchy.
00149     if (!recurse_nodes(egg_group, x_parent)) {
00150       return false;
00151     }
00152 
00153   } else {
00154     // Create a frame for each EggGroup.
00155     XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
00156 
00157     // Set the transform on the frame, if we have one.
00158     if (egg_group->has_transform()) {
00159       x_frame->add_FrameTransformMatrix(egg_group->get_transform3d());
00160     }
00161 
00162     if (!recurse_nodes(egg_group, x_frame)) {
00163       return false;
00164     }
00165   }
00166 
00167   return true;
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: XFileMaker::add_bin
00172 //       Access: Private
00173 //  Description: Determines what kind of object needs to be added for
00174 //               the indicated bin node.
00175 ////////////////////////////////////////////////////////////////////
00176 bool XFileMaker::
00177 add_bin(EggBin *egg_bin, XFileNode *x_parent) {
00178   switch (egg_bin->get_bin_number()) {
00179   case EggPolysetMaker::BN_polyset:
00180     return add_polyset(egg_bin, x_parent);
00181   }
00182 
00183   xfile_cat.error()
00184     << "Unexpected bin type " << egg_bin->get_bin_number() << "\n";
00185   return false;
00186 }
00187 
00188 ////////////////////////////////////////////////////////////////////
00189 //     Function: XFileMaker::add_polyset
00190 //       Access: Private
00191 //  Description: Adds a mesh object corresponding to the collection of
00192 //               polygons within the indicated bin.
00193 ////////////////////////////////////////////////////////////////////
00194 bool XFileMaker::
00195 add_polyset(EggBin *egg_bin, XFileNode *x_parent) {
00196   // Make sure that all our polygons are reasonable.
00197   egg_bin->remove_invalid_primitives(true);
00198 
00199   XFileMesh *mesh = get_mesh(x_parent);
00200 
00201   EggGroupNode::iterator ci;
00202   for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
00203     EggPolygon *poly;
00204     DCAST_INTO_R(poly, *ci, false);
00205 
00206     mesh->add_polygon(poly);
00207   }
00208 
00209   return true;
00210 }
00211 
00212   
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: XFileMaker::recurse_nodes
00215 //       Access: Private
00216 //  Description: Adds each child of the indicated Node as a child of
00217 //               the indicated DX object.
00218 ////////////////////////////////////////////////////////////////////
00219 bool XFileMaker::
00220 recurse_nodes(EggGroupNode *egg_node, XFileNode *x_parent) {
00221   EggGroupNode::iterator ci;
00222   for (ci = egg_node->begin(); ci != egg_node->end(); ++ci) {
00223     EggNode *child = (*ci);
00224     if (!add_node(child, x_parent)) {
00225       return false;
00226     }
00227   }
00228 
00229   return true;
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: XFileMaker::get_mesh
00234 //       Access: Private
00235 //  Description: Returns a suitable XFileMesh object for creating
00236 //               meshes within the indicated x_parent object.
00237 ////////////////////////////////////////////////////////////////////
00238 XFileMesh *XFileMaker::
00239 get_mesh(XFileNode *x_parent) {
00240   Meshes::iterator mi = _meshes.find(x_parent);
00241   if (mi != _meshes.end()) {
00242     // We've already started working on this x_parent before; use the
00243     // same mesh object.
00244     return (*mi).second;
00245   }
00246 
00247   // We haven't seen this x_parent before; create a new mesh object.
00248   XFileMesh *mesh = new XFileMesh;
00249   _meshes.insert(Meshes::value_type(x_parent, mesh));
00250   return mesh;
00251 }
00252 
00253 
00254 ////////////////////////////////////////////////////////////////////
00255 //     Function: XFileMaker::finalize_mesh
00256 //       Access: Private
00257 //  Description: Creates the actual X structures corresponding to
00258 //               the indicated XFileMesh object.
00259 ////////////////////////////////////////////////////////////////////
00260 bool XFileMaker::
00261 finalize_mesh(XFileNode *x_parent, XFileMesh *mesh) {
00262   // Get a unique number for each mesh.
00263   _mesh_index++;
00264   string mesh_index = format_string(_mesh_index);
00265 
00266   // Finally, create the Mesh object.
00267   mesh->make_x_mesh(x_parent, mesh_index);
00268 
00269   return true;
00270 }
 All Classes Functions Variables Enumerations