Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/egg/eggData.cxx

Go to the documentation of this file.
00001 // Filename: eggData.cxx
00002 // Created by:  drose (20Jan99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "eggData.h"
00020 #include "eggCoordinateSystem.h"
00021 #include "eggTextureCollection.h"
00022 #include "eggMaterialCollection.h"
00023 #include "eggComment.h"
00024 #include "eggPoolUniquifier.h"
00025 #include "config_egg.h"
00026 
00027 #include "config_util.h"
00028 #include "config_express.h"
00029 #include "string_utils.h"
00030 #include "dSearchPath.h"
00031 #include "virtualFileSystem.h"
00032 
00033 extern int eggyyparse(void);
00034 #include "parserDefs.h"
00035 #include "lexerDefs.h"
00036 
00037 TypeHandle EggData::_type_handle;
00038 
00039 ////////////////////////////////////////////////////////////////////
00040 //     Function: EggData::resolve_egg_filename
00041 //       Access: Public, Static
00042 //  Description: Looks for the indicated filename, first along the
00043 //               indicated searchpath, and then along the egg_path and
00044 //               finally along the model_path.  If found, updates the
00045 //               filename to the full path and returns true;
00046 //               otherwise, returns false.
00047 ////////////////////////////////////////////////////////////////////
00048 bool EggData::
00049 resolve_egg_filename(Filename &egg_filename, const DSearchPath &searchpath) {
00050   if (use_vfs) {
00051     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00052 
00053     if (egg_filename.is_fully_qualified() && vfs->exists(egg_filename)) {
00054       return true;
00055     }
00056 
00057     vfs->resolve_filename(egg_filename, searchpath, "egg") ||
00058       vfs->resolve_filename(egg_filename, get_egg_path(), "egg") ||
00059       vfs->resolve_filename(egg_filename, get_model_path(), "egg");
00060 
00061     return vfs->exists(egg_filename);
00062 
00063   } else {
00064     if (egg_filename.is_fully_qualified() && egg_filename.exists()) {
00065       return true;
00066     }
00067 
00068     egg_filename.resolve_filename(searchpath, "egg") ||
00069       egg_filename.resolve_filename(get_egg_path(), "egg") ||
00070       egg_filename.resolve_filename(get_model_path(), "egg");
00071     
00072     return egg_filename.exists();
00073   }
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: EggData::read
00078 //       Access: Public
00079 //  Description: Opens the indicated filename and reads the egg data
00080 //               contents from it.  Returns true if the file was
00081 //               successfully opened and read, false if there were
00082 //               some errors, in which case the data may be partially
00083 //               read.
00084 //
00085 //               error is the output stream to which to write error
00086 //               messages.
00087 ////////////////////////////////////////////////////////////////////
00088 bool EggData::
00089 read(Filename filename) {
00090   filename.set_text();
00091   set_egg_filename(filename);
00092 
00093   if (use_vfs) {
00094     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00095     
00096     istream *file = vfs->open_read_file(filename);
00097     if (file == (istream *)NULL) {
00098       egg_cat.error() << "Unable to open " << filename << "\n";
00099       return false;
00100     }
00101     
00102     egg_cat.info()
00103       << "Reading " << filename << "\n";
00104 
00105     bool read_ok = read(*file);
00106     delete file;
00107     return read_ok;
00108 
00109   } else {
00110     ifstream file;
00111     if (!filename.open_read(file)) {
00112       egg_cat.error() << "Unable to open " << filename << "\n";
00113       return false;
00114     }
00115     
00116     egg_cat.info()
00117       << "Reading " << filename << "\n";
00118     
00119     return read(file);
00120   }
00121 }
00122 
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: EggData::read
00126 //       Access: Public
00127 //  Description: Parses the egg syntax contained in the indicated
00128 //               input stream.  Returns true if the stream was a
00129 //               completely valid egg file, false if there were some
00130 //               errors, in which case the data may be partially read.
00131 //
00132 //               Before you call this routine, you should probably
00133 //               call set_egg_filename() to set the name of the egg
00134 //               file we're processing, if at all possible.  If there
00135 //               is no such filename, you may set it to the empty
00136 //               string.
00137 ////////////////////////////////////////////////////////////////////
00138 bool EggData::
00139 read(istream &in) {
00140   // First, dispense with any children we had previously.  We will
00141   // replace them with the new data.
00142   clear();
00143 
00144   // Create a temporary EggData structure to read into.  We initialize
00145   // it with a copy of ourselves, so that it will get our _coordsys
00146   // value, if the user set it.
00147   PT(EggData) data = new EggData(*this);
00148   egg_init_parser(in, get_egg_filename(), data, data);
00149   eggyyparse();
00150   egg_cleanup_parser();
00151 
00152   data->post_read();
00153 
00154   steal_children(*data);
00155   (*this) = *data;
00156 
00157   return (egg_error_count() == 0);
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: EggData::merge
00162 //       Access: Public
00163 //  Description: Appends the other egg structure to the end of this
00164 //               one.  The other egg structure is invalidated.
00165 ////////////////////////////////////////////////////////////////////
00166 void EggData::
00167 merge(EggData &other) {
00168   if (get_coordinate_system() == CS_default) {
00169     // If we haven't specified a coordinate system yet, we inherit the
00170     // other one's.
00171     set_coordinate_system(other.get_coordinate_system());
00172 
00173   } else {
00174     // Otherwise, the other one is forced into our coordinate system
00175     // before we merge.
00176     other.set_coordinate_system(get_coordinate_system());
00177   }
00178   steal_children(other);
00179 }
00180 
00181 
00182 ////////////////////////////////////////////////////////////////////
00183 //     Function: EggData::load_externals
00184 //       Access: Public
00185 //  Description: Loads up all the egg files referenced by <File>
00186 //               entries within the egg structure, and inserts their
00187 //               contents in place of the <File> entries.  Searches
00188 //               for files in the searchpath, if not found directly,
00189 //               and writes error messages to the indicated output
00190 //               stream.  Returns true if all externals were loaded
00191 //               successfully, false otherwise.
00192 ////////////////////////////////////////////////////////////////////
00193 bool EggData::
00194 load_externals(const DSearchPath &searchpath) {
00195   return
00196     r_load_externals(searchpath, get_coordinate_system());
00197 }
00198 
00199 ////////////////////////////////////////////////////////////////////
00200 //     Function: EggData::collapse_equivalent_textures
00201 //       Access: Public
00202 //  Description: Removes duplicate references to the same texture
00203 //               image with the same properties.  Considers two
00204 //               texture references with identical properties, but
00205 //               different tref names, to be equivalent, and collapses
00206 //               them, choosing one tref name to keep arbitrarily.
00207 //               Returns the number of textures removed.
00208 ////////////////////////////////////////////////////////////////////
00209 int EggData::
00210 collapse_equivalent_textures() {
00211   EggTextureCollection textures;
00212   textures.find_used_textures(this);
00213   return
00214     textures.collapse_equivalent_textures(~EggTexture::E_tref_name, this);
00215 }
00216 
00217 ////////////////////////////////////////////////////////////////////
00218 //     Function: EggData::collapse_equivalent_materials
00219 //       Access: Public
00220 //  Description: Removes duplicate references to the same material
00221 //               with the same properties.  Considers two material
00222 //               references with identical properties, but different
00223 //               mref names, to be equivalent, and collapses them,
00224 //               choosing one mref name to keep arbitrarily.  Returns
00225 //               the number of materials removed.
00226 ////////////////////////////////////////////////////////////////////
00227 int EggData::
00228 collapse_equivalent_materials() {
00229   EggMaterialCollection materials;
00230   materials.find_used_materials(this);
00231   return
00232     materials.collapse_equivalent_materials(~EggMaterial::E_mref_name, this);
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: EggData::write_egg
00237 //       Access: Public
00238 //  Description: The main interface for writing complete egg files.
00239 ////////////////////////////////////////////////////////////////////
00240 bool EggData::
00241 write_egg(Filename filename) {
00242   filename.set_text();
00243   filename.unlink();
00244 
00245   ofstream file;
00246   if (!filename.open_write(file)) {
00247     egg_cat.error() << "Unable to open " << filename << " for writing.\n";
00248     return false;
00249   }
00250 
00251   return write_egg(file);
00252 }
00253 
00254 ////////////////////////////////////////////////////////////////////
00255 //     Function: EggData::write_egg
00256 //       Access: Public
00257 //  Description: The main interface for writing complete egg files.
00258 ////////////////////////////////////////////////////////////////////
00259 bool EggData::
00260 write_egg(ostream &out) {
00261   pre_write();
00262   write(out, 0);
00263   return true;
00264 }
00265 
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: EggData::set_coordinate_system
00269 //       Access: Public
00270 //  Description: Changes the coordinate system of the EggData.  If the
00271 //               coordinate system was previously different, this may
00272 //               result in a conversion of the data.
00273 ////////////////////////////////////////////////////////////////////
00274 void EggData::
00275 set_coordinate_system(CoordinateSystem new_coordsys) {
00276   if (new_coordsys == CS_default) {
00277     new_coordsys = default_coordinate_system;
00278   }
00279   if (new_coordsys != _coordsys &&
00280       (_coordsys != CS_default && _coordsys != CS_invalid)) {
00281     // Time to convert the data.
00282     r_transform(LMatrix4d::convert_mat(_coordsys, new_coordsys),
00283                 LMatrix4d::convert_mat(new_coordsys, _coordsys),
00284                 new_coordsys);
00285 
00286     // Now we have to update the under_flags to ensure that all the
00287     // cached relative matrices are correct.
00288     update_under(0);
00289   }
00290 
00291   _coordsys = new_coordsys;
00292 }
00293 
00294 ////////////////////////////////////////////////////////////////////
00295 //     Function: EggData::write
00296 //       Access: Protected, Virtual
00297 //  Description: Writes the egg data out to the indicated output
00298 //               stream.
00299 ////////////////////////////////////////////////////////////////////
00300 void EggData::
00301 write(ostream &out, int indent_level) const {
00302   EggCoordinateSystem ecs(_coordsys);
00303   ecs.write(out, indent_level);
00304   EggGroupNode::write(out, indent_level);
00305   out << flush;
00306 }
00307 
00308 
00309 ////////////////////////////////////////////////////////////////////
00310 //     Function: EggData::post_read
00311 //       Access: Private
00312 //  Description: Does whatever processing is appropriate after reading
00313 //               the data in from an egg file.
00314 ////////////////////////////////////////////////////////////////////
00315 void EggData::
00316 post_read() {
00317   CoordinateSystem old_coordsys = _coordsys;
00318   _coordsys = find_coordsys_entry();
00319 
00320   if (_coordsys == CS_default) {
00321     // If the egg file didn't contain a <CoordinateSystem> entry,
00322     // assume it's Y-up, by convention.
00323     _coordsys = CS_yup_right;
00324 
00325   } else if (_coordsys == CS_invalid) {
00326     egg_cat.warning()
00327       << "Contradictory <CoordinateSystem> entries encountered.\n";
00328     _coordsys = CS_yup_right;
00329   }
00330 
00331   r_mark_coordsys(_coordsys);
00332 
00333   if (old_coordsys != CS_default) {
00334     // Now if we had a previous definition, enforce it.  This might
00335     // convert the data to the given coordinate system.
00336     set_coordinate_system(old_coordsys);
00337   }
00338 
00339   if (get_auto_resolve_externals()) {
00340     // Resolve filenames that are relative to the egg file.
00341     DSearchPath dir;
00342     dir.append_directory(get_egg_filename().get_dirname());
00343     resolve_filenames(dir);
00344   }
00345 }
00346 
00347 ////////////////////////////////////////////////////////////////////
00348 //     Function: EggData::pre_write
00349 //       Access: Private
00350 //  Description: Does whatever processing is appropriate just before
00351 //               writing the data out to an egg file.  This includes
00352 //               verifying that vertex pool names are unique, etc.
00353 ////////////////////////////////////////////////////////////////////
00354 void EggData::
00355 pre_write() {
00356   // Pull out all of the texture definitions in the file and massage
00357   // them a bit.
00358   EggTextureCollection textures;
00359   textures.extract_textures(this);
00360 
00361   // Remove any textures that aren't being used.
00362   textures.remove_unused_textures(this);
00363 
00364   // Collapse out any textures that are completely equivalent.  For
00365   // this purpose, we consider two textures with identical properties
00366   // but different tref names to be different.
00367   textures.collapse_equivalent_textures(~0, this);
00368 
00369   // Make sure all of the textures have unique TRef names.
00370   textures.uniquify_trefs();
00371   textures.sort_by_tref();
00372 
00373   // Do the same thing with the materials.
00374   EggMaterialCollection materials;
00375   materials.extract_materials(this);
00376   materials.remove_unused_materials(this);
00377   materials.collapse_equivalent_materials(~0, this);
00378   materials.uniquify_mrefs();
00379   materials.sort_by_mref();
00380 
00381   // Now put them all back at the head of the file, after any initial
00382   // comment records.
00383   iterator ci = begin();
00384   while (ci != end() && (*ci)->is_of_type(EggComment::get_class_type())) {
00385     ++ci;
00386   }
00387   textures.insert_textures(this, ci);
00388   materials.insert_materials(this, ci);
00389 
00390   // Also make sure that the vertex pools are uniquely named.  This
00391   // also checks textures and materials, which is kind of redundant
00392   // since we just did that, but we don't mind.
00393   EggPoolUniquifier pu;
00394   pu.uniquify(this);
00395 }

Generated on Fri May 2 00:37:32 2003 for Panda by doxygen1.3