Panda3D

lwoToEggConverter.cxx

00001 // Filename: lwoToEggConverter.cxx
00002 // Created by:  drose (25Apr01)
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 "lwoToEggConverter.h"
00016 #include "cLwoLayer.h"
00017 #include "cLwoClip.h"
00018 #include "cLwoPoints.h"
00019 #include "cLwoPolygons.h"
00020 #include "cLwoSurface.h"
00021 
00022 #include "eggData.h"
00023 #include "lwoHeader.h"
00024 #include "lwoLayer.h"
00025 #include "lwoClip.h"
00026 #include "lwoPoints.h"
00027 #include "lwoPolygons.h"
00028 #include "lwoVertexMap.h"
00029 #include "lwoDiscontinuousVertexMap.h"
00030 #include "lwoTags.h"
00031 #include "lwoPolygonTags.h"
00032 #include "lwoInputFile.h"
00033 #include "dcast.h"
00034 
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: LwoToEggConverter::Constructor
00038 //       Access: Public
00039 //  Description:
00040 ////////////////////////////////////////////////////////////////////
00041 LwoToEggConverter::
00042 LwoToEggConverter() {
00043   _generic_layer = (CLwoLayer *)NULL;
00044   _make_materials = true;
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: LwoToEggConverter::Copy Constructor
00049 //       Access: Public
00050 //  Description:
00051 ////////////////////////////////////////////////////////////////////
00052 LwoToEggConverter::
00053 LwoToEggConverter(const LwoToEggConverter &copy) :
00054   SomethingToEggConverter(copy)
00055 {
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: LwoToEggConverter::Destructor
00060 //       Access: Public, Virtual
00061 //  Description:
00062 ////////////////////////////////////////////////////////////////////
00063 LwoToEggConverter::
00064 ~LwoToEggConverter() {
00065   cleanup();
00066 }
00067 
00068 ////////////////////////////////////////////////////////////////////
00069 //     Function: LwoToEggConverter::make_copy
00070 //       Access: Public, Virtual
00071 //  Description: Allocates and returns a new copy of the converter.
00072 ////////////////////////////////////////////////////////////////////
00073 SomethingToEggConverter *LwoToEggConverter::
00074 make_copy() {
00075   return new LwoToEggConverter(*this);
00076 }
00077 
00078 ////////////////////////////////////////////////////////////////////
00079 //     Function: LwoToEggConverter::get_name
00080 //       Access: Public, Virtual
00081 //  Description: Returns the English name of the file type this
00082 //               converter supports.
00083 ////////////////////////////////////////////////////////////////////
00084 string LwoToEggConverter::
00085 get_name() const {
00086   return "Lightwave";
00087 }
00088 
00089 ////////////////////////////////////////////////////////////////////
00090 //     Function: LwoToEggConverter::get_extension
00091 //       Access: Public, Virtual
00092 //  Description: Returns the common extension of the file type this
00093 //               converter supports.
00094 ////////////////////////////////////////////////////////////////////
00095 string LwoToEggConverter::
00096 get_extension() const {
00097   return "lwo";
00098 }
00099 
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: LwoToEggConverter::supports_compressed
00102 //       Access: Published, Virtual
00103 //  Description: Returns true if this file type can transparently load
00104 //               compressed files (with a .pz extension), false
00105 //               otherwise.
00106 ////////////////////////////////////////////////////////////////////
00107 bool LwoToEggConverter::
00108 supports_compressed() const {
00109   return true;
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: LwoToEggConverter::convert_file
00114 //       Access: Public, Virtual
00115 //  Description: Handles the reading of the input file and converting
00116 //               it to egg.  Returns true if successful, false
00117 //               otherwise.
00118 //
00119 //               This is designed to be as generic as possible,
00120 //               generally in support of run-time loading.
00121 //               Command-line converters may choose to use
00122 //               convert_lwo() instead, as it provides more control.
00123 ////////////////////////////////////////////////////////////////////
00124 bool LwoToEggConverter::
00125 convert_file(const Filename &filename) {
00126   LwoInputFile in;
00127 
00128   nout << "Reading " << filename << "\n";
00129   if (!in.open_read(filename)) {
00130     nout << "Unable to open " << filename << "\n";
00131     return false;
00132   }
00133 
00134   PT(IffChunk) chunk = in.get_chunk();
00135   if (chunk == (IffChunk *)NULL) {
00136     nout << "Unable to read " << filename << "\n";
00137     return false;
00138   }
00139 
00140   if (!chunk->is_of_type(LwoHeader::get_class_type())) {
00141     nout << "File " << filename << " is not a Lightwave Object file.\n";
00142     return false;
00143   }
00144 
00145   LwoHeader *header = DCAST(LwoHeader, chunk);
00146   if (!header->is_valid()) {
00147     nout << "File " << filename
00148          << " is not recognized as a Lightwave Object file.  "
00149          << "Perhaps the version is too recent.\n";
00150     return false;
00151   }
00152 
00153   return convert_lwo(header);
00154 }
00155 
00156 ////////////////////////////////////////////////////////////////////
00157 //     Function: LwoToEggConverter::convert_lwo
00158 //       Access: Public
00159 //  Description: Fills up the egg_data structure according to the
00160 //               indicated lwo structure.
00161 ////////////////////////////////////////////////////////////////////
00162 bool LwoToEggConverter::
00163 convert_lwo(const LwoHeader *lwo_header) {
00164   if (_egg_data->get_coordinate_system() == CS_default) {
00165     _egg_data->set_coordinate_system(CS_yup_left);
00166   }
00167 
00168   _error = false;
00169   _lwo_header = lwo_header;
00170 
00171   collect_lwo();
00172   make_egg();
00173   connect_egg();
00174 
00175   _egg_data->remove_unused_vertices(true);
00176   cleanup();
00177 
00178   return !had_error();
00179 }
00180 
00181 ////////////////////////////////////////////////////////////////////
00182 //     Function: LwoToEggConverter::get_layer
00183 //       Access: Public
00184 //  Description: Returns a pointer to the layer with the given index
00185 //               number, or NULL if there is no such layer.
00186 ////////////////////////////////////////////////////////////////////
00187 CLwoLayer *LwoToEggConverter::
00188 get_layer(int number) const {
00189   if (number >= 0 && number < (int)_layers.size()) {
00190     return _layers[number];
00191   }
00192   return (CLwoLayer *)NULL;
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: LwoToEggConverter::get_clip
00197 //       Access: Public
00198 //  Description: Returns a pointer to the clip with the given index
00199 //               number, or NULL if there is no such clip.
00200 ////////////////////////////////////////////////////////////////////
00201 CLwoClip *LwoToEggConverter::
00202 get_clip(int number) const {
00203   if (number >= 0 && number < (int)_clips.size()) {
00204     return _clips[number];
00205   }
00206   return (CLwoClip *)NULL;
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: LwoToEggConverter::get_surface
00211 //       Access: Public
00212 //  Description: Returns a pointer to the surface definition with the
00213 //               given name, or NULL if there is no such surface.
00214 ////////////////////////////////////////////////////////////////////
00215 CLwoSurface *LwoToEggConverter::
00216 get_surface(const string &name) const {
00217   Surfaces::const_iterator si;
00218   si = _surfaces.find(name);
00219   if (si != _surfaces.end()) {
00220     return (*si).second;
00221   }
00222   return (CLwoSurface *)NULL;
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: LwoToEggConverter::cleanup
00227 //       Access: Private
00228 //  Description: Frees all the internal data structures after we're
00229 //               done converting, and resets the converter to its
00230 //               initial state.
00231 ////////////////////////////////////////////////////////////////////
00232 void LwoToEggConverter::
00233 cleanup() {
00234   _lwo_header.clear();
00235 
00236   if (_generic_layer != (CLwoLayer *)NULL) {
00237     delete _generic_layer;
00238     _generic_layer = (CLwoLayer *)NULL;
00239   }
00240 
00241   Layers::iterator li;
00242   for (li = _layers.begin(); li != _layers.end(); ++li) {
00243     CLwoLayer *layer = (*li);
00244     if (layer != (CLwoLayer *)NULL) {
00245       delete layer;
00246     }
00247   }
00248   _layers.clear();
00249 
00250   Clips::iterator ci;
00251   for (ci = _clips.begin(); ci != _clips.end(); ++ci) {
00252     CLwoClip *clip = (*ci);
00253     if (clip != (CLwoClip *)NULL) {
00254       delete clip;
00255     }
00256   }
00257   _clips.clear();
00258 
00259   Points::iterator pi;
00260   for (pi = _points.begin(); pi != _points.end(); ++pi) {
00261     CLwoPoints *points = (*pi);
00262     delete points;
00263   }
00264   _points.clear();
00265 
00266   Polygons::iterator gi;
00267   for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
00268     CLwoPolygons *polygons = (*gi);
00269     delete polygons;
00270   }
00271   _polygons.clear();
00272 
00273   Surfaces::iterator si;
00274   for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
00275     CLwoSurface *surface = (*si).second;
00276     delete surface;
00277   }
00278   _surfaces.clear();
00279 }
00280 
00281 ////////////////////////////////////////////////////////////////////
00282 //     Function: LwoToEggConverter::collect_lwo
00283 //       Access: Private
00284 //  Description: Walks through the chunks in the Lightwave data and
00285 //               creates wrapper objects for each relevant piece.
00286 ////////////////////////////////////////////////////////////////////
00287 void LwoToEggConverter::
00288 collect_lwo() {
00289   CLwoLayer *last_layer = (CLwoLayer *)NULL;
00290   CLwoPoints *last_points = (CLwoPoints *)NULL;
00291   CLwoPolygons *last_polygons = (CLwoPolygons *)NULL;
00292 
00293   const LwoTags *tags = (const LwoTags *)NULL;
00294 
00295   int num_chunks = _lwo_header->get_num_chunks();
00296   for (int i = 0; i < num_chunks; i++) {
00297     const IffChunk *chunk = _lwo_header->get_chunk(i);
00298 
00299     if (chunk->is_of_type(LwoLayer::get_class_type())) {
00300       const LwoLayer *lwo_layer = DCAST(LwoLayer, chunk);
00301       CLwoLayer *layer = new CLwoLayer(this, lwo_layer);
00302       int number = layer->get_number();
00303       slot_layer(number);
00304 
00305       if (_layers[number] != (CLwoLayer *)NULL) {
00306         nout << "Warning: multiple layers with number " << number << "\n";
00307       }
00308       _layers[number] = layer;
00309       last_layer = layer;
00310       last_points = (CLwoPoints *)NULL;
00311       last_polygons = (CLwoPolygons *)NULL;
00312 
00313     } else if (chunk->is_of_type(LwoClip::get_class_type())) {
00314       const LwoClip *lwo_clip = DCAST(LwoClip, chunk);
00315       CLwoClip *clip = new CLwoClip(this, lwo_clip);
00316 
00317       int index = clip->get_index();
00318       slot_clip(index);
00319 
00320       if (_clips[index] != (CLwoClip *)NULL) {
00321         nout << "Warning: multiple clips with index " << index << "\n";
00322       }
00323       _clips[index] = clip;
00324 
00325     } else if (chunk->is_of_type(LwoPoints::get_class_type())) {
00326       if (last_layer == (CLwoLayer *)NULL) {
00327         last_layer = make_generic_layer();
00328       }
00329 
00330       const LwoPoints *lwo_points = DCAST(LwoPoints, chunk);
00331       CLwoPoints *points = new CLwoPoints(this, lwo_points, last_layer);
00332       _points.push_back(points);
00333       last_points = points;
00334 
00335     } else if (chunk->is_of_type(LwoVertexMap::get_class_type())) {
00336       if (last_points == (CLwoPoints *)NULL) {
00337         nout << "Vertex map chunk encountered without a preceding points chunk.\n";
00338       } else {
00339         const LwoVertexMap *lwo_vmap = DCAST(LwoVertexMap, chunk);
00340         last_points->add_vmap(lwo_vmap);
00341       }
00342 
00343     } else if (chunk->is_of_type(LwoDiscontinuousVertexMap::get_class_type())) {
00344       if (last_polygons == (CLwoPolygons *)NULL) {
00345         nout << "Discontinous vertex map chunk encountered without a preceding polygons chunk.\n";
00346       } else {
00347         const LwoDiscontinuousVertexMap *lwo_vmad = DCAST(LwoDiscontinuousVertexMap, chunk);
00348         last_polygons->add_vmad(lwo_vmad);
00349       }
00350 
00351     } else if (chunk->is_of_type(LwoTags::get_class_type())) {
00352       tags = DCAST(LwoTags, chunk);
00353 
00354     } else if (chunk->is_of_type(LwoPolygons::get_class_type())) {
00355       if (last_points == (CLwoPoints *)NULL) {
00356         nout << "Polygon chunk encountered without a preceding points chunk.\n";
00357       } else {
00358         const LwoPolygons *lwo_polygons = DCAST(LwoPolygons, chunk);
00359         CLwoPolygons *polygons =
00360           new CLwoPolygons(this, lwo_polygons, last_points);
00361         _polygons.push_back(polygons);
00362         last_polygons = polygons;
00363       }
00364 
00365     } else if (chunk->is_of_type(LwoPolygonTags::get_class_type())) {
00366       if (last_polygons == (CLwoPolygons *)NULL) {
00367         nout << "Polygon tags chunk encountered without a preceding polygons chunk.\n";
00368       } else if (tags == (LwoTags *)NULL) {
00369         nout << "Polygon tags chunk encountered without a preceding tags chunk.\n";
00370       } else {
00371         const LwoPolygonTags *lwo_ptags = DCAST(LwoPolygonTags, chunk);
00372         last_polygons->add_ptags(lwo_ptags, tags);
00373       }
00374 
00375     } else if (chunk->is_of_type(LwoSurface::get_class_type())) {
00376       if (last_layer == (CLwoLayer *)NULL) {
00377         last_layer = make_generic_layer();
00378       }
00379 
00380       const LwoSurface *lwo_surface = DCAST(LwoSurface, chunk);
00381       CLwoSurface *surface = new CLwoSurface(this, lwo_surface);
00382 
00383       bool inserted = _surfaces.insert(Surfaces::value_type(surface->get_name(), surface)).second;
00384       if (!inserted) {
00385         nout << "Multiple surface definitions named " << surface->get_name() << "\n";
00386         delete surface;
00387       }
00388     }
00389   }
00390 }
00391 
00392 ////////////////////////////////////////////////////////////////////
00393 //     Function: LwoToEggConverter::make_egg
00394 //       Access: Private
00395 //  Description: Makes egg structures for all of the conversion
00396 //               wrapper objects.
00397 ////////////////////////////////////////////////////////////////////
00398 void LwoToEggConverter::
00399 make_egg() {
00400   if (_generic_layer != (CLwoLayer *)NULL) {
00401     _generic_layer->make_egg();
00402   }
00403 
00404   Layers::iterator li;
00405   for (li = _layers.begin(); li != _layers.end(); ++li) {
00406     CLwoLayer *layer = (*li);
00407     if (layer != (CLwoLayer *)NULL) {
00408       layer->make_egg();
00409     }
00410   }
00411 
00412   Points::iterator pi;
00413   for (pi = _points.begin(); pi != _points.end(); ++pi) {
00414     CLwoPoints *points = (*pi);
00415     points->make_egg();
00416   }
00417 
00418   Polygons::iterator gi;
00419   for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
00420     CLwoPolygons *polygons = (*gi);
00421     polygons->make_egg();
00422   }
00423 }
00424 
00425 ////////////////////////////////////////////////////////////////////
00426 //     Function: LwoToEggConverter::connect_egg
00427 //       Access: Private
00428 //  Description: Connects together all of the egg structures.
00429 ////////////////////////////////////////////////////////////////////
00430 void LwoToEggConverter::
00431 connect_egg() {
00432   if (_generic_layer != (CLwoLayer *)NULL) {
00433     _generic_layer->connect_egg();
00434   }
00435 
00436   Layers::iterator li;
00437   for (li = _layers.begin(); li != _layers.end(); ++li) {
00438     CLwoLayer *layer = (*li);
00439     if (layer != (CLwoLayer *)NULL) {
00440       layer->connect_egg();
00441     }
00442   }
00443 
00444   Points::iterator pi;
00445   for (pi = _points.begin(); pi != _points.end(); ++pi) {
00446     CLwoPoints *points = (*pi);
00447     points->connect_egg();
00448   }
00449 
00450   Polygons::iterator gi;
00451   for (gi = _polygons.begin(); gi != _polygons.end(); ++gi) {
00452     CLwoPolygons *polygons = (*gi);
00453     polygons->connect_egg();
00454   }
00455 }
00456 
00457 ////////////////////////////////////////////////////////////////////
00458 //     Function: LwoToEggConverter::slot_layer
00459 //       Access: Private
00460 //  Description: Ensures that there is space in the _layers array to
00461 //               store an element at position number.
00462 ////////////////////////////////////////////////////////////////////
00463 void LwoToEggConverter::
00464 slot_layer(int number) {
00465   nassertv(number - (int)_layers.size() < 1000);
00466   while (number >= (int)_layers.size()) {
00467     _layers.push_back((CLwoLayer *)NULL);
00468   }
00469   nassertv(number >= 0 && number < (int)_layers.size());
00470 }
00471 
00472 ////////////////////////////////////////////////////////////////////
00473 //     Function: LwoToEggConverter::slot_clip
00474 //       Access: Private
00475 //  Description: Ensures that there is space in the _clips array to
00476 //               store an element at position number.
00477 ////////////////////////////////////////////////////////////////////
00478 void LwoToEggConverter::
00479 slot_clip(int number) {
00480   nassertv(number - (int)_clips.size() < 1000);
00481   while (number >= (int)_clips.size()) {
00482     _clips.push_back((CLwoClip *)NULL);
00483   }
00484   nassertv(number >= 0 && number < (int)_clips.size());
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: LwoToEggConverter::make_generic_layer
00489 //       Access: Private
00490 //  Description: If a geometry definition is encountered in the
00491 //               Lightwave file before a layer definition, we should
00492 //               make a generic layer to hold the geometry.  This
00493 //               makes and returns a single layer for this purpose.
00494 //               It should not be called twice.
00495 ////////////////////////////////////////////////////////////////////
00496 CLwoLayer *LwoToEggConverter::
00497 make_generic_layer() {
00498   nassertr(_generic_layer == (CLwoLayer *)NULL, _generic_layer);
00499 
00500   PT(LwoLayer) layer = new LwoLayer;
00501   layer->make_generic();
00502 
00503   _generic_layer = new CLwoLayer(this, layer);
00504   return _generic_layer;
00505 }
 All Classes Functions Variables Enumerations