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

pandatool/src/eggbase/eggReader.cxx

Go to the documentation of this file.
00001 // Filename: eggReader.cxx
00002 // Created by:  drose (14Feb00)
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 "eggReader.h"
00020 
00021 #include "pnmImage.h"
00022 #include "config_util.h"
00023 #include "eggTextureCollection.h"
00024 #include "eggGroup.h"
00025 #include "eggGroupNode.h"
00026 #include "eggSwitchCondition.h"
00027 #include "string_utils.h"
00028 #include "dcast.h"
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: EggReader::Constructor
00032 //       Access: Public
00033 //  Description:
00034 ////////////////////////////////////////////////////////////////////
00035 EggReader::
00036 EggReader() {
00037   clear_runlines();
00038   add_runline("[opts] input.egg");
00039 
00040   redescribe_option
00041     ("cs",
00042      "Specify the coordinate system to operate in.  This may be "
00043      " one of 'y-up', 'z-up', 'y-up-left', or 'z-up-left'.  The default "
00044      "is the coordinate system of the input egg file.");
00045 
00046   add_option
00047     ("f", "", 80,
00048      "Force complete loading: load up the egg file along with all of its "
00049      "external references.",
00050      &EggReader::dispatch_none, &_force_complete);
00051 
00052   _tex_type = (PNMFileType *)NULL;
00053   _delod = -1.0;
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: EggRead::add_texture_options
00058 //       Access: Public
00059 //  Description: Adds -td, -te, etc. as valid options for this
00060 //               program.  If the user specifies one of the options on
00061 //               the command line, the textures will be copied and
00062 //               converted as each egg file is read.
00063 //
00064 //               Note that if you call this function to add these
00065 //               options, you must call do_reader_options() at the
00066 //               appropriate point before or during processing to
00067 //               execute the options if the user specified them.
00068 ////////////////////////////////////////////////////////////////////
00069 void EggReader::
00070 add_texture_options() {
00071   add_option
00072     ("td", "dirname", 40,
00073      "Copy textures to the indicated directory.  The copy is performed "
00074      "only if the destination file does not exist or is older than the "
00075      "source file.",
00076      &EggReader::dispatch_filename, &_got_tex_dirname, &_tex_dirname);
00077 
00078   add_option
00079     ("te", "ext", 40,
00080      "Rename textures to have the indicated extension.  This also "
00081      "automatically copies them to the new filename (possibly in a "
00082      "different directory if -td is also specified), and may implicitly "
00083      "convert to a different image format according to the extension.",
00084      &EggReader::dispatch_string, &_got_tex_extension, &_tex_extension);
00085 
00086   add_option
00087     ("tt", "type", 40,
00088      "Explicitly specifies the image format to convert textures to "
00089      "when copying them via -td or -te.  Normally, this is unnecessary as "
00090      "the image format can be determined by the extension, but sometimes "
00091      "the extension is insufficient to unambiguously specify an image "
00092      "type.",
00093      &EggReader::dispatch_image_type, NULL, &_tex_type);
00094 }
00095 
00096 ////////////////////////////////////////////////////////////////////
00097 //     Function: EggRead::add_delod_options
00098 //       Access: Public
00099 //  Description: Adds -delod as a valid option for this program.
00100 //
00101 //               Note that if you call this function to add these
00102 //               options, you must call do_reader_options() at the
00103 //               appropriate point before or during processing to
00104 //               execute the options if the user specified them.
00105 ////////////////////////////////////////////////////////////////////
00106 void EggReader::
00107 add_delod_options(double default_delod) {
00108   _delod = default_delod;
00109 
00110   if (default_delod < 0) {
00111     add_option
00112       ("delod", "dist", 40,
00113        "Eliminate LOD's by choosing the level that would be appropriate for "
00114        "a camera at the indicated fixed distance from each LOD.  "
00115        "Use -delod -1 to keep all the LOD's as they are, which is "
00116        "the default.\n",
00117        &EggReader::dispatch_double, NULL, &_delod);
00118 
00119   } else {
00120     add_option
00121       ("delod", "dist", 40,
00122        "Eliminate LOD's by choosing the level that would be appropriate for "
00123        "a camera at the indicated fixed distance from each LOD.  "
00124        "Use -delod -1 to keep all the LOD's as they are.  The default value "
00125        "is " + format_string(default_delod) + ".",
00126        &EggReader::dispatch_double, NULL, &_delod);
00127   }
00128 }
00129 
00130 ////////////////////////////////////////////////////////////////////
00131 //     Function: EggReader::as_reader
00132 //       Access: Public, Virtual
00133 //  Description: Returns this object as an EggReader pointer, if it is
00134 //               in fact an EggReader, or NULL if it is not.
00135 //
00136 //               This is intended to work around the C++ limitation
00137 //               that prevents downcasts past virtual inheritance.
00138 //               Since both EggReader and EggWriter inherit virtually
00139 //               from EggBase, we need functions like this to downcast
00140 //               to the appropriate pointer.
00141 ////////////////////////////////////////////////////////////////////
00142 EggReader *EggReader::
00143 as_reader() {
00144   return this;
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: EggReader::handle_args
00149 //       Access: Protected, Virtual
00150 //  Description:
00151 ////////////////////////////////////////////////////////////////////
00152 bool EggReader::
00153 handle_args(ProgramBase::Args &args) {
00154   if (args.empty()) {
00155     nout << "You must specify the egg file(s) to read on the command line.\n";
00156     return false;
00157   }
00158 
00159   // Any separate egg files that are listed on the command line will
00160   // get implicitly loaded up into one big egg file.
00161 
00162   if (!args.empty()) {
00163     _data.set_egg_filename(Filename::from_os_specific(args[0]));
00164   }
00165   Args::const_iterator ai;
00166   for (ai = args.begin(); ai != args.end(); ++ai) {
00167     Filename filename = Filename::from_os_specific(*ai);
00168 
00169     EggData file_data;
00170     if (!file_data.read(filename)) {
00171       // Rather than returning false, we simply exit here, so the
00172       // ProgramBase won't try to tell the user how to run the program
00173       // just because we got a bad egg file.
00174       exit(1);
00175     }
00176 
00177     DSearchPath file_path;
00178     file_path.append_directory(filename.get_dirname());
00179 
00180     // We always resolve filenames first based on the source egg
00181     // filename, since egg files almost always store relative paths.
00182     // This is a temporary kludge around integrating the path_replace
00183     // system with the EggData better.
00184     file_data.resolve_filenames(file_path);
00185     
00186     if (_force_complete) {
00187       if (!file_data.load_externals()) {
00188         exit(1);
00189       }
00190     }
00191 
00192     // Now resolve the filenames again according to the user's
00193     // specified _path_replace.
00194     convert_paths(&file_data, _path_replace, file_path);
00195 
00196     _data.merge(file_data);
00197   }
00198 
00199   return true;
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: EggReader::post_command_line
00204 //       Access: Protected, Virtual
00205 //  Description: This is called after the command line has been
00206 //               completely processed, and it gives the program a
00207 //               chance to do some last-minute processing and
00208 //               validation of the options and arguments.  It should
00209 //               return true if everything is fine, false if there is
00210 //               an error.
00211 ////////////////////////////////////////////////////////////////////
00212 bool EggReader::
00213 post_command_line() {
00214   return EggBase::post_command_line();
00215 }
00216 
00217 ////////////////////////////////////////////////////////////////////
00218 //     Function: EggReader::do_reader_options
00219 //       Access: Protected
00220 //  Description: Postprocesses the egg file as the user requested
00221 //               according to whatever command-line options are in
00222 //               effect.  Returns true if everything is done
00223 //               correctly, false if there was some problem.
00224 ////////////////////////////////////////////////////////////////////
00225 bool EggReader::
00226 do_reader_options() {
00227   bool okflag = true;
00228 
00229   if (_got_tex_dirname || _got_tex_extension) {
00230     if (!copy_textures()) {
00231       okflag = false;
00232     }
00233   }
00234 
00235   if (_delod >= 0.0) {
00236     do_delod(&_data);
00237   }
00238 
00239   return okflag;
00240 }
00241 
00242 ////////////////////////////////////////////////////////////////////
00243 //     Function: EggReader::copy_textures
00244 //       Access: Private
00245 //  Description: Renames and copies the textures referenced in the egg
00246 //               file, if so specified by the -td and -te options.
00247 //               Returns true if all textures are copied successfully,
00248 //               false if any one of them failed.
00249 ////////////////////////////////////////////////////////////////////
00250 bool EggReader::
00251 copy_textures() {
00252   bool success = true;
00253   EggTextureCollection textures;
00254   textures.find_used_textures(&_data);
00255 
00256   EggTextureCollection::const_iterator ti;
00257   for (ti = textures.begin(); ti != textures.end(); ++ti) {
00258     EggTexture *tex = (*ti);
00259     Filename orig_filename = tex->get_filename();
00260     if (!orig_filename.exists()) {
00261       bool found = 
00262         orig_filename.resolve_filename(get_texture_path()) ||
00263         orig_filename.resolve_filename(get_model_path());
00264       if (!found) {
00265         nout << "Cannot find " << orig_filename << "\n";
00266         success = false;
00267         continue;
00268       }
00269     }
00270 
00271     Filename new_filename = orig_filename;
00272     if (_got_tex_dirname) {
00273       new_filename.set_dirname(_tex_dirname);
00274     }
00275     if (_got_tex_extension) {
00276       new_filename.set_extension(_tex_extension);
00277     }
00278 
00279     if (orig_filename != new_filename) {
00280       tex->set_filename(new_filename);
00281 
00282       // The new filename is different; does it need copying?
00283       int compare = 
00284         orig_filename.compare_timestamps(new_filename, true, true);
00285       if (compare > 0) {
00286         // Yes, it does.  Copy it!
00287         nout << "Reading " << orig_filename << "\n";
00288         PNMImage image;
00289         if (!image.read(orig_filename)) {
00290           nout << "  unable to read!\n";
00291           success = false;
00292         } else {
00293           nout << "Writing " << new_filename << "\n";
00294           if (!image.write(new_filename, _tex_type)) {
00295             nout << "  unable to write!\n";
00296             success = false;
00297           }
00298         }
00299       }
00300     }
00301   }
00302 
00303   return success;
00304 }
00305 
00306 ////////////////////////////////////////////////////////////////////
00307 //     Function: EggReader::do_delod
00308 //       Access: Private
00309 //  Description: Removes all the LOD's in the egg file by treating the
00310 //               camera as being _delod distance from each LOD.
00311 //               Returns true if this particular group should be
00312 //               preserved, false if it should be removed.
00313 ////////////////////////////////////////////////////////////////////
00314 bool EggReader::
00315 do_delod(EggNode *node) {
00316   if (node->is_of_type(EggGroup::get_class_type())) {
00317     EggGroup *group = DCAST(EggGroup, node);
00318     if (group->has_lod()) {
00319       const EggSwitchCondition &cond = group->get_lod();
00320       if (cond.is_of_type(EggSwitchConditionDistance::get_class_type())) {
00321         const EggSwitchConditionDistance *dist = 
00322           DCAST(EggSwitchConditionDistance, &cond);
00323         if (_delod >= dist->_switch_out && _delod < dist->_switch_in) {
00324           // Preserve this group node, but not the LOD information
00325           // itself.
00326           nout << "Preserving LOD " << node->get_name() 
00327                << " (" << dist->_switch_out << " to " << dist->_switch_in
00328                << ")\n";
00329           group->clear_lod();
00330         } else {
00331           // Remove this group node.
00332           nout << "Eliminating LOD " << node->get_name()
00333                << " (" << dist->_switch_out << " to " << dist->_switch_in
00334                << ")\n";
00335           return false;
00336         }
00337       }
00338     }
00339   }
00340 
00341   // Now process all the children.
00342   if (node->is_of_type(EggGroupNode::get_class_type())) {
00343     EggGroupNode *group = DCAST(EggGroupNode, node);
00344     EggGroupNode::iterator ci;
00345     ci = group->begin();
00346     while (ci != group->end()) {
00347       EggNode *child = *ci;
00348       ++ci;
00349 
00350       if (!do_delod(child)) {
00351         group->remove_child(child);
00352       }
00353     }
00354   }
00355 
00356   return true;
00357 }

Generated on Fri May 2 03:18:36 2003 for Panda-Tool by doxygen1.3