Panda3D
 All Classes Functions Variables Enumerations
somethingToEgg.cxx
00001 // Filename: somethingToEgg.cxx
00002 // Created by:  drose (15Feb00)
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 "somethingToEgg.h"
00016 #include "somethingToEggConverter.h"
00017 
00018 #include "config_util.h"
00019 
00020 ////////////////////////////////////////////////////////////////////
00021 //     Function: SomethingToEgg::Constructor
00022 //       Access: Public
00023 //  Description: The first parameter to the constructor should be the
00024 //               one-word name of the file format that is to be read,
00025 //               for instance "OpenFlight" or "Alias".  It's just used
00026 //               in printing error messages and such.
00027 ////////////////////////////////////////////////////////////////////
00028 SomethingToEgg::
00029 SomethingToEgg(const string &format_name,
00030                const string &preferred_extension,
00031                bool allow_last_param, bool allow_stdout) :
00032   EggConverter(format_name, preferred_extension, allow_last_param, allow_stdout)
00033 {
00034   clear_runlines();
00035   if (_allow_last_param) {
00036     add_runline("[opts] input" + _preferred_extension + " output.egg");
00037   }
00038   add_runline("[opts] -o output.egg input" + _preferred_extension);
00039   if (_allow_stdout) {
00040     add_runline("[opts] input" + _preferred_extension + " >output.egg");
00041   }
00042 
00043   // -f doesn't make sense if we aren't reading egg files.
00044   remove_option("f");
00045 
00046   redescribe_option
00047     ("cs",
00048      "Specify the coordinate system of the input " + _format_name +
00049      " file.  Normally, this can inferred from the file itself.");
00050 
00051   add_option
00052     ("noabs", "", 0,
00053      "Don't allow the input " + _format_name + " file to have absolute pathnames.  "
00054      "If it does, abort with an error.  This option is designed to help "
00055      "detect errors when populating or building a standalone model tree, "
00056      "which should be self-contained and include only relative pathnames.",
00057      &SomethingToEgg::dispatch_none, &_noabs);
00058 
00059   add_option
00060     ("noexist", "", 0,
00061      "Don't treat it as an error if the input file references pathnames "
00062      "(e.g. textures) that don't exist.  Normally, this will be flagged as "
00063      "an error and the command aborted; with this option, an egg file will "
00064      "be generated anyway, referencing pathnames that do not exist.",
00065      &SomethingToEgg::dispatch_none, &_noexist);
00066 
00067   add_option
00068     ("ignore", "", 0,
00069      "Ignore non-fatal errors and generate an egg file anyway.",
00070      &SomethingToEgg::dispatch_none, &_allow_errors);
00071 
00072   _input_units = DU_invalid;
00073   _output_units = DU_invalid;
00074   _animation_convert = AC_none;
00075   _got_start_frame = false;
00076   _got_end_frame = false;
00077   _got_frame_inc = false;
00078   _got_neutral_frame = false;
00079   _got_input_frame_rate = false;
00080   _got_output_frame_rate = false;
00081   _merge_externals = false;
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: SomethingToEgg::add_units_options
00086 //       Access: Public
00087 //  Description: Adds -ui and -uo as valid options for this program.
00088 //               If the user specifies -uo and -ui, or just -uo and
00089 //               the program specifies -ui by setting _input_units,
00090 //               the indicated units conversion will be automatically
00091 //               applied before writing out the egg file.
00092 ////////////////////////////////////////////////////////////////////
00093 void SomethingToEgg::
00094 add_units_options() {
00095   add_option
00096     ("ui", "units", 40,
00097      "Specify the units of the input " + _format_name +
00098      " file.  Normally, this can be inferred from the file itself.",
00099      &SomethingToEgg::dispatch_units, NULL, &_input_units);
00100 
00101   add_option
00102     ("uo", "units", 40,
00103      "Specify the units of the resulting egg file.  If this is "
00104      "specified, the vertices in the egg file will be scaled as "
00105      "necessary to make the appropriate units conversion; otherwise, "
00106      "the vertices will be left as they are.",
00107      &SomethingToEgg::dispatch_units, NULL, &_output_units);
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: SomethingToEgg::add_animation_options
00112 //       Access: Public
00113 //  Description: Adds options appropriate to animation packages.
00114 ////////////////////////////////////////////////////////////////////
00115 void SomethingToEgg::
00116 add_animation_options() {
00117   add_option
00118     ("a", "animation-mode", 40,
00119      "Specifies how animation from the " + _format_name + " file is "
00120      "converted to egg, if at all.  At present, the following keywords "
00121      "are supported: none, pose, flip, strobe, model, chan, or both.  "
00122      "The default is none, which means not to convert animation.",
00123      &SomethingToEgg::dispatch_animation_convert, NULL, &_animation_convert);
00124 
00125   add_option
00126     ("cn", "name", 40,
00127      "Specifies the name of the animation character.  This should match "
00128      "between all of the model files and all of the channel files for a "
00129      "particular model and its associated channels.",
00130      &SomethingToEgg::dispatch_string, NULL, &_character_name);
00131 
00132   add_option
00133     ("sf", "start-frame", 40,
00134      "Specifies the starting frame of animation to extract.  If omitted, "
00135      "the first frame of the time slider will be used.  For -a pose, this "
00136      "is the one frame of animation to extract.",
00137      &SomethingToEgg::dispatch_double, &_got_start_frame, &_start_frame);
00138 
00139   add_option
00140     ("ef", "end-frame", 40,
00141      "Specifies the ending frame of animation to extract.  If omitted, "
00142      "the last frame of the time slider will be used.",
00143      &SomethingToEgg::dispatch_double, &_got_end_frame, &_end_frame);
00144 
00145   add_option
00146     ("if", "frame-inc", 40,
00147      "Specifies the increment between successive frames.  If omitted, "
00148      "this is taken from the time slider settings, or 1.0 if the time "
00149      "slider does not specify.",
00150      &SomethingToEgg::dispatch_double, &_got_frame_inc, &_frame_inc);
00151 
00152   add_option
00153     ("nf", "neutral-frame", 40,
00154      "Specifies the frame number to use for the neutral pose.  The model "
00155      "will be set to this frame before extracting out the neutral character.  "
00156      "If omitted, the current frame of the model is used.  This is only "
00157      "relevant for -a model or -a both.",
00158      &SomethingToEgg::dispatch_double, &_got_neutral_frame, &_neutral_frame);
00159 
00160   add_option
00161     ("fri", "fps", 40,
00162      "Specify the frame rate (frames per second) of the input " + _format_name +
00163      " file.  Normally, this can be inferred from the file itself.",
00164      &SomethingToEgg::dispatch_double, &_got_input_frame_rate, &_input_frame_rate);
00165 
00166   add_option
00167     ("fro", "fps", 40,
00168      "Specify the frame rate (frames per second) of the generated animation.  "
00169      "If this is specified, the animation speed is scaled by the appropriate "
00170      "factor based on the frame rate of the input file (see -fri).",
00171      &SomethingToEgg::dispatch_double, &_got_output_frame_rate, &_output_frame_rate);
00172 }
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: SomethingToEgg::add_merge_externals_options
00176 //       Access: Public
00177 //  Description: Adds -f.
00178 ////////////////////////////////////////////////////////////////////
00179 void SomethingToEgg::
00180 add_merge_externals_options() {
00181   add_option
00182     ("f", "", 40,
00183      "Follow and convert all external references in the source file.",
00184      &SomethingToEgg::dispatch_none, &_merge_externals);
00185 }
00186 
00187 ////////////////////////////////////////////////////////////////////
00188 //     Function: SomethingToEgg::apply_units_scale
00189 //       Access: Protected
00190 //  Description: Applies the scale indicated by the input and output
00191 //               units to the indicated egg file.  This is normally
00192 //               done automatically when the file is written out.
00193 ////////////////////////////////////////////////////////////////////
00194 void SomethingToEgg::
00195 apply_units_scale(EggData *data) {
00196   if (_output_units != DU_invalid && _input_units != DU_invalid &&
00197       _input_units != _output_units) {
00198     nout << "Converting from " << format_long_unit(_input_units)
00199          << " to " << format_long_unit(_output_units) << "\n";
00200     double scale = convert_units(_input_units, _output_units);
00201     data->transform(LMatrix4d::scale_mat(scale));
00202   }
00203 }
00204 
00205 ////////////////////////////////////////////////////////////////////
00206 //     Function: SomethingToEgg::apply_parameters
00207 //       Access: Protected
00208 //  Description: Copies the relevant parameters specified by the user
00209 //               on the command line (if add_path_replace_options(),
00210 //               add_path_store_options(), or add_animation_options()
00211 //               was used) to the converter.
00212 ////////////////////////////////////////////////////////////////////
00213 void SomethingToEgg::
00214 apply_parameters(SomethingToEggConverter &converter) {
00215   _path_replace->_noabs = _noabs;
00216   _path_replace->_exists = !_noexist;
00217   converter.set_path_replace(_path_replace);
00218 
00219   converter.set_animation_convert(_animation_convert);
00220   converter.set_character_name(_character_name);
00221   if (_got_start_frame) {
00222     converter.set_start_frame(_start_frame);
00223   }
00224   if (_got_end_frame) {
00225     converter.set_end_frame(_end_frame);
00226   }
00227   if (_got_frame_inc) {
00228     converter.set_frame_inc(_frame_inc);
00229   }
00230   if (_got_neutral_frame) {
00231     converter.set_neutral_frame(_neutral_frame);
00232   }
00233   if (_got_input_frame_rate) {
00234     converter.set_input_frame_rate(_input_frame_rate);
00235   }
00236   if (_got_output_frame_rate) {
00237     converter.set_output_frame_rate(_output_frame_rate);
00238   }
00239 }
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: SomethingToEgg::handle_args
00243 //       Access: Protected
00244 //  Description:
00245 ////////////////////////////////////////////////////////////////////
00246 bool SomethingToEgg::
00247 handle_args(Args &args) {
00248   if (_allow_last_param && !_got_output_filename && args.size() > 1) {
00249     _got_output_filename = true;
00250     _output_filename = Filename::from_os_specific(args.back());
00251     args.pop_back();
00252 
00253     if (!(_output_filename.get_extension() == "egg")) {
00254       nout << "Output filename " << _output_filename
00255            << " does not end in .egg.  If this is really what you intended, "
00256         "use the -o output_file syntax.\n";
00257       return false;
00258     }
00259 
00260     if (!verify_output_file_safe()) {
00261       return false;
00262     }
00263   }
00264 
00265   if (args.empty()) {
00266     nout << "You must specify the " << _format_name
00267           << " file to read on the command line.\n";
00268     return false;
00269   }
00270 
00271   if (args.size() != 1) {
00272     nout << "You may only specify one " << _format_name
00273          << " file to read on the command line.  "
00274          << "You specified: ";
00275     Args::const_iterator ai;
00276     for (ai = args.begin(); ai != args.end(); ++ai) {
00277       nout << (*ai) << " ";
00278     }
00279     nout << "\n";
00280     return false;
00281   }
00282 
00283   _input_filename = Filename::from_os_specific(args[0]);
00284 
00285   if (!_input_filename.exists()) {
00286     nout << "Cannot find input file " << _input_filename << "\n";
00287     return false;
00288   }
00289 
00290   if (!_got_path_directory && _got_output_filename) {
00291     // Put in the name of the output directory.
00292     _path_replace->_path_directory = _output_filename.get_dirname();
00293   }
00294 
00295   return true;
00296 }
00297 
00298 ////////////////////////////////////////////////////////////////////
00299 //     Function: SomethingToEgg::post_command_line
00300 //       Access: Protected, Virtual
00301 //  Description: This is called after the command line has been
00302 //               completely processed, and it gives the program a
00303 //               chance to do some last-minute processing and
00304 //               validation of the options and arguments.  It should
00305 //               return true if everything is fine, false if there is
00306 //               an error.
00307 ////////////////////////////////////////////////////////////////////
00308 bool SomethingToEgg::
00309 post_command_line() {
00310   // Prepend the source filename to the model path.
00311   ConfigVariableSearchPath &model_path = get_model_path();
00312   Filename directory = _input_filename.get_dirname();
00313   if (directory.empty()) {
00314     directory = ".";
00315   }
00316   model_path.prepend_directory(directory);
00317 
00318   return EggConverter::post_command_line();
00319 }
00320 
00321 ////////////////////////////////////////////////////////////////////
00322 //     Function: SomethingToEgg::post_process_egg_file
00323 //       Access: Protected, Virtual
00324 //  Description: Performs any processing of the egg file that is
00325 //               appropriate before writing it out.  This includes any
00326 //               normal adjustments the user requested via -np, etc.
00327 //
00328 //               Normally, you should not need to call this function
00329 //               directly; write_egg_file() calls it for you.  You
00330 //               should call this only if you do not use
00331 //               write_egg_file() to write out the resulting egg file.
00332 ////////////////////////////////////////////////////////////////////
00333 void SomethingToEgg::
00334 post_process_egg_file() {
00335   apply_units_scale(_data);
00336   EggConverter::post_process_egg_file();
00337 }
00338 
00339 ////////////////////////////////////////////////////////////////////
00340 //     Function: SomethingToEgg::dispatch_animation_convert
00341 //       Access: Protected, Static
00342 //  Description: Dispatch function to set the given animation convert mode
00343 //               according to the specified parameter.  var is a
00344 //               pointer to an AnimationConvert variable.
00345 ////////////////////////////////////////////////////////////////////
00346 bool SomethingToEgg::
00347 dispatch_animation_convert(const string &opt, const string &arg, void *var) {
00348   AnimationConvert *ip = (AnimationConvert *)var;
00349   (*ip) = string_animation_convert(arg);
00350   if ((*ip) == AC_invalid) {
00351     nout << "Invalid keyword for -" << opt << ": " << arg << "\n";
00352     return false;
00353   }    
00354 
00355   return true;
00356 }
 All Classes Functions Variables Enumerations