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

pandatool/src/eggbase/eggWriter.cxx

Go to the documentation of this file.
00001 // Filename: eggWriter.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 "eggWriter.h"
00020 
00021 #include "string_utils.h"
00022 #include "compose_matrix.h"
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: EggWriter::Constructor
00026 //       Access: Public
00027 //  Description: Egg-writing type programs may specify their output
00028 //               file using either the last-filename convention, the
00029 //               -o convention, and/or implicitly writing the result
00030 //               to standard output.  Not all interfaces are
00031 //               appropriate for all applications; some may be
00032 //               confusing or dangerous.
00033 //
00034 //               The calling application should pass allow_last_param
00035 //               true to allow the user to specify the output filename
00036 //               as the last parameter on the command line (the most
00037 //               dangerous, but convenient, method), and allow_stdout
00038 //               true to allow the user to omit the output filename
00039 //               altogether and have the output implicitly go to
00040 //               standard output (not terribly dangerous, but
00041 //               inappropriate when writing binary file formats).
00042 ////////////////////////////////////////////////////////////////////
00043 EggWriter::
00044 EggWriter(bool allow_last_param, bool allow_stdout) :
00045   WithOutputFile(allow_last_param, allow_stdout, false)
00046 {
00047   // Indicate the extension name we expect the user to supply for
00048   // output files.
00049   _preferred_extension = ".egg";
00050 
00051   clear_runlines();
00052   if (_allow_last_param) {
00053     add_runline("[opts] output.egg");
00054   }
00055   add_runline("[opts] -o output.egg");
00056   if (_allow_stdout) {
00057     add_runline("[opts] >output.egg");
00058   }
00059 
00060   string o_description;
00061 
00062   if (_allow_stdout) {
00063     if (_allow_last_param) {
00064       o_description =
00065         "Specify the filename to which the resulting egg file will be written.  "
00066         "If this option is omitted, the last parameter name is taken to be the "
00067         "name of the output file, or standard output is used if there are no "
00068         "other parameters.";
00069     } else {
00070       o_description =
00071         "Specify the filename to which the resulting egg file will be written.  "
00072         "If this option is omitted, the egg file is written to standard output.";
00073     }
00074   } else {
00075     if (_allow_last_param) {
00076       o_description =
00077         "Specify the filename to which the resulting egg file will be written.  "
00078         "If this option is omitted, the last parameter name is taken to be the "
00079         "name of the output file.";
00080     } else {
00081       o_description =
00082         "Specify the filename to which the resulting egg file will be written.";
00083     }
00084   }
00085 
00086   add_option
00087     ("o", "filename", 50, o_description,
00088      &EggWriter::dispatch_filename, &_got_output_filename, &_output_filename);
00089 
00090   redescribe_option
00091     ("cs",
00092      "Specify the coordinate system of the resulting egg file.  This may be "
00093      "one of 'y-up', 'z-up', 'y-up-left', or 'z-up-left'.  The default is "
00094      "y-up.");
00095 
00096   _normals_mode = NM_preserve;
00097   _normals_threshold = 0.0;
00098 
00099   _got_transform = false;
00100   _transform = LMatrix4d::ident_mat();
00101 }
00102 
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: EggWriter::add_normals_options
00106 //       Access: Public
00107 //  Description: Adds -no, -np, etc. as valid options for this
00108 //               program.  If the user specifies one of the options on
00109 //               the command line, the normals will be adjusted when
00110 //               the egg file is written out.
00111 ////////////////////////////////////////////////////////////////////
00112 void EggWriter::
00113 add_normals_options() {
00114   static NormalsMode strip = NM_strip;
00115   static NormalsMode polygon = NM_polygon;
00116   static NormalsMode vertex = NM_vertex;
00117   static NormalsMode preserve = NM_preserve;
00118 
00119   add_option
00120     ("no", "", 48,
00121      "Strip all normals.",
00122      &EggWriter::dispatch_normals, NULL, &strip);
00123 
00124   add_option
00125     ("np", "", 48,
00126      "Strip existing normals and redefine polygon normals.",
00127      &EggWriter::dispatch_normals, NULL, &polygon);
00128 
00129   add_option
00130     ("nv", "threshold", 48,
00131      "Strip existing normals and redefine vertex normals.  Consider an edge "
00132      "between adjacent polygons to be smooth if the angle between them "
00133      "is less than threshold degrees.",
00134      &EggWriter::dispatch_normals, NULL, &vertex);
00135 
00136   add_option
00137     ("nn", "", 48,
00138      "Preserve normals exactly as they are.  This is the default.",
00139      &EggWriter::dispatch_normals, NULL, &preserve);
00140 }
00141 
00142 ////////////////////////////////////////////////////////////////////
00143 //     Function: EggWriter::add_transform_options
00144 //       Access: Public
00145 //  Description: Adds -TS, -TT, etc. as valid options for this
00146 //               program.  If the user specifies one of the options on
00147 //               the command line, the data will be transformed when
00148 //               the egg file is written out.
00149 ////////////////////////////////////////////////////////////////////
00150 void EggWriter::
00151 add_transform_options() {
00152   add_option
00153     ("TS", "sx[,sy,sz]", 49,
00154      "Scale the model uniformly by the given factor (if only one number "
00155      "is given) or in each axis by sx, sy, sz (if three numbers are given).",
00156      &EggWriter::dispatch_scale, &_got_transform, &_transform);
00157 
00158   add_option
00159     ("TR", "x,y,z", 49,
00160      "Rotate the model x degrees about the x axis, then y degrees about the "
00161      "y axis, and then z degrees about the z axis.",
00162      &EggWriter::dispatch_rotate_xyz, &_got_transform, &_transform);
00163 
00164   add_option
00165     ("TA", "angle,x,y,z", 49,
00166      "Rotate the model angle degrees counterclockwise about the given "
00167      "axis.",
00168      &EggWriter::dispatch_rotate_axis, &_got_transform, &_transform);
00169 
00170   add_option
00171     ("TT", "x,y,z", 49,
00172      "Translate the model by the indicated amount.\n\n"
00173      "All transformation options (-TS, -TR, -TA, -TT) are cumulative and are "
00174      "applied in the order they are encountered on the command line.",
00175      &EggWriter::dispatch_translate, &_got_transform, &_transform);
00176 }
00177 
00178 ////////////////////////////////////////////////////////////////////
00179 //     Function: EggWriter::as_writer
00180 //       Access: Public, Virtual
00181 //  Description: Returns this object as an EggWriter pointer, if it is
00182 //               in fact an EggWriter, or NULL if it is not.
00183 //
00184 //               This is intended to work around the C++ limitation
00185 //               that prevents downcasts past virtual inheritance.
00186 //               Since both EggReader and EggWriter inherit virtually
00187 //               from EggBase, we need functions like this to downcast
00188 //               to the appropriate pointer.
00189 ////////////////////////////////////////////////////////////////////
00190 EggWriter *EggWriter::
00191 as_writer() {
00192   return this;
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: EggWriter::post_process_egg_file
00197 //       Access: Public, Virtual
00198 //  Description: Performs any processing of the egg file that is
00199 //               appropriate before writing it out.  This includes any
00200 //               normal adjustments the user requested via -np, etc.
00201 //
00202 //               Normally, you should not need to call this function
00203 //               directly; write_egg_file() calls it for you.  You
00204 //               should call this only if you do not use
00205 //               write_egg_file() to write out the resulting egg file.
00206 ////////////////////////////////////////////////////////////////////
00207 void EggWriter::
00208 post_process_egg_file() {
00209   if (_got_transform) {
00210     nout << "Applying transform matrix:\n";
00211     _transform.write(nout, 2);
00212     LVecBase3d scale, hpr, translate;
00213     if (decompose_matrix(_transform, scale, hpr, translate,
00214                          _data.get_coordinate_system())) {
00215       nout << "(scale " << scale << ", hpr " << hpr << ", translate "
00216            << translate << ")\n";
00217     }
00218     _data.transform(_transform);
00219   }
00220 
00221   switch (_normals_mode) {
00222   case NM_strip:
00223     nout << "Stripping normals.\n";
00224     _data.strip_normals();
00225     _data.remove_unused_vertices();
00226     break;
00227 
00228   case NM_polygon:
00229     nout << "Recomputing polygon normals.\n";
00230     _data.recompute_polygon_normals();
00231     _data.remove_unused_vertices();
00232     break;
00233 
00234   case NM_vertex:
00235     nout << "Recomputing vertex normals.\n";
00236     _data.recompute_vertex_normals(_normals_threshold);
00237     _data.remove_unused_vertices();
00238     break;
00239 
00240   case NM_preserve:
00241     // Do nothing.
00242     break;
00243   }
00244 }
00245 
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: EggWriter::write_egg_file
00248 //       Access: Public
00249 //  Description: Writes out the egg file as the normal result of the
00250 //               program.  This calls post_process_egg_file() to
00251 //               perform any last minute processing (like normal
00252 //               computation) and then writes out the file to the
00253 //               output stream returned by get_output().
00254 ////////////////////////////////////////////////////////////////////
00255 void EggWriter::
00256 write_egg_file() {
00257   post_process_egg_file();
00258   _data.write_egg(get_output());
00259 }
00260 
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: EggWriter::handle_args
00263 //       Access: Protected, Virtual
00264 //  Description: Does something with the additional arguments on the
00265 //               command line (after all the -options have been
00266 //               parsed).  Returns true if the arguments are good,
00267 //               false otherwise.
00268 ////////////////////////////////////////////////////////////////////
00269 bool EggWriter::
00270 handle_args(ProgramBase::Args &args) {
00271   if (!check_last_arg(args, 0)) {
00272     return false;
00273   }
00274 
00275   if (!args.empty()) {
00276     nout << "Unexpected arguments on command line:\n";
00277     Args::const_iterator ai;
00278     for (ai = args.begin(); ai != args.end(); ++ai) {
00279       nout << (*ai) << " ";
00280     }
00281     nout << "\r";
00282     return false;
00283   }
00284 
00285   if (!_got_path_directory && _got_output_filename) {
00286     // Put in the name of the output directory.
00287     _path_replace->_path_directory = _output_filename.get_dirname();
00288   }
00289 
00290   return true;
00291 }
00292 
00293 ////////////////////////////////////////////////////////////////////
00294 //     Function: EggWriter::post_command_line
00295 //       Access: Protected, Virtual
00296 //  Description:
00297 ////////////////////////////////////////////////////////////////////
00298 bool EggWriter::
00299 post_command_line() {
00300   if (!_allow_stdout && !_got_output_filename) {
00301     nout << "You must specify the filename to write with -o.\n";
00302     return false;
00303   }
00304 
00305   append_command_comment(_data);
00306 
00307   return EggBase::post_command_line();
00308 }
00309 
00310 ////////////////////////////////////////////////////////////////////
00311 //     Function: EggWriter::dispatch_normals
00312 //       Access: Protected, Static
00313 //  Description: Accepts one of -no, -np, etc. and sets _normals_mode
00314 //               as indicated.  The void * argument is a pointer to a
00315 //               NormalsMode variable that indicates which switch was
00316 //               passed.
00317 ////////////////////////////////////////////////////////////////////
00318 bool EggWriter::
00319 dispatch_normals(ProgramBase *self, const string &opt, const string &arg, void *mode) {
00320   EggBase *base = (EggBase *)self;
00321   EggWriter *me = base->as_writer();
00322   return me->ns_dispatch_normals(opt, arg, mode);
00323 }
00324 
00325 ////////////////////////////////////////////////////////////////////
00326 //     Function: EggWriter::ns_dispatch_normals
00327 //       Access: Protected
00328 //  Description: Accepts one of -no, -np, etc. and sets _normals_mode
00329 //               as indicated.  The void * argument is a pointer to a
00330 //               NormalsMode variable that indicates which switch was
00331 //               passed.
00332 ////////////////////////////////////////////////////////////////////
00333 bool EggWriter::
00334 ns_dispatch_normals(const string &opt, const string &arg, void *mode) {
00335   _normals_mode = *(NormalsMode *)mode;
00336 
00337   if (_normals_mode == NM_vertex) {
00338     if (!string_to_double(arg, _normals_threshold)) {
00339       nout << "Invalid numeric parameter for -" << opt << ": "
00340            << arg << "\n";
00341       return false;
00342     }
00343   }
00344 
00345   return true;
00346 }
00347 
00348 ////////////////////////////////////////////////////////////////////
00349 //     Function: EggWriter::dispatch_scale
00350 //       Access: Protected, Static
00351 //  Description: Handles -TS, which specifies a scale transform.  Var
00352 //               is an LMatrix4d.
00353 ////////////////////////////////////////////////////////////////////
00354 bool EggWriter::
00355 dispatch_scale(const string &opt, const string &arg, void *var) {
00356   LMatrix4d *transform = (LMatrix4d *)var;
00357 
00358   vector_string words;
00359   tokenize(arg, words, ",");
00360 
00361   double sx, sy, sz;
00362 
00363   bool okflag = false;
00364   if (words.size() == 3) {
00365     okflag =
00366       string_to_double(words[0], sx) &&
00367       string_to_double(words[1], sy) &&
00368       string_to_double(words[2], sz);
00369 
00370   } else if (words.size() == 1) {
00371     okflag =
00372       string_to_double(words[0], sx);
00373     sy = sz = sx;
00374   }
00375 
00376   if (!okflag) {
00377     nout << "-" << opt
00378          << " requires one or three numbers separated by commas.\n";
00379     return false;
00380   }
00381 
00382   *transform = (*transform) * LMatrix4d::scale_mat(sx, sy, sz);
00383 
00384   return true;
00385 }
00386 
00387 ////////////////////////////////////////////////////////////////////
00388 //     Function: EggWriter::dispatch_rotate_xyz
00389 //       Access: Protected, Static
00390 //  Description: Handles -TR, which specifies a rotate transform about
00391 //               the three cardinal axes.  Var is an LMatrix4d.
00392 ////////////////////////////////////////////////////////////////////
00393 bool EggWriter::
00394 dispatch_rotate_xyz(ProgramBase *self, const string &opt, const string &arg, void *var) {
00395   EggBase *base = (EggBase *)self;
00396   EggWriter *me = base->as_writer();
00397   return me->ns_dispatch_rotate_xyz(opt, arg, var);
00398 }
00399 
00400 ////////////////////////////////////////////////////////////////////
00401 //     Function: EggWriter::ns_dispatch_rotate_xyz
00402 //       Access: Protected
00403 //  Description: Handles -TR, which specifies a rotate transform about
00404 //               the three cardinal axes.  Var is an LMatrix4d.
00405 ////////////////////////////////////////////////////////////////////
00406 bool EggWriter::
00407 ns_dispatch_rotate_xyz(const string &opt, const string &arg, void *var) {
00408   LMatrix4d *transform = (LMatrix4d *)var;
00409 
00410   vector_string words;
00411   tokenize(arg, words, ",");
00412 
00413   LVecBase3d xyz;
00414 
00415   bool okflag = false;
00416   if (words.size() == 3) {
00417     okflag =
00418       string_to_double(words[0], xyz[0]) &&
00419       string_to_double(words[1], xyz[1]) &&
00420       string_to_double(words[2], xyz[2]);
00421   }
00422 
00423   if (!okflag) {
00424     nout << "-" << opt
00425          << " requires three numbers separated by commas.\n";
00426     return false;
00427   }
00428 
00429   LMatrix4d mat =
00430     LMatrix4d::rotate_mat(xyz[0], LVector3d(1.0, 0.0, 0.0), _coordinate_system) *
00431     LMatrix4d::rotate_mat(xyz[1], LVector3d(0.0, 1.0, 0.0), _coordinate_system) *
00432     LMatrix4d::rotate_mat(xyz[2], LVector3d(0.0, 0.0, 1.0), _coordinate_system);
00433 
00434   *transform = (*transform) * mat;
00435 
00436   return true;
00437 }
00438 
00439 ////////////////////////////////////////////////////////////////////
00440 //     Function: EggWriter::dispatch_rotate_axis
00441 //       Access: Protected, Static
00442 //  Description: Handles -TA, which specifies a rotate transform about
00443 //               an arbitrary axis.  Var is an LMatrix4d.
00444 ////////////////////////////////////////////////////////////////////
00445 bool EggWriter::
00446 dispatch_rotate_axis(ProgramBase *self, const string &opt, const string &arg, void *var) {
00447   EggBase *base = (EggBase *)self;
00448   EggWriter *me = base->as_writer();
00449   return me->ns_dispatch_rotate_axis(opt, arg, var);
00450 }
00451 
00452 ////////////////////////////////////////////////////////////////////
00453 //     Function: EggWriter::ns_dispatch_rotate_axis
00454 //       Access: Protected
00455 //  Description: Handles -TA, which specifies a rotate transform about
00456 //               an arbitrary axis.  Var is an LMatrix4d.
00457 ////////////////////////////////////////////////////////////////////
00458 bool EggWriter::
00459 ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var) {
00460   LMatrix4d *transform = (LMatrix4d *)var;
00461 
00462   vector_string words;
00463   tokenize(arg, words, ",");
00464 
00465   double angle;
00466   LVecBase3d axis;
00467 
00468   bool okflag = false;
00469   if (words.size() == 4) {
00470     okflag =
00471       string_to_double(words[0], angle) &&
00472       string_to_double(words[1], axis[0]) &&
00473       string_to_double(words[2], axis[1]) &&
00474       string_to_double(words[3], axis[2]);
00475   }
00476 
00477   if (!okflag) {
00478     nout << "-" << opt
00479          << " requires four numbers separated by commas.\n";
00480     return false;
00481   }
00482 
00483   *transform = (*transform) * LMatrix4d::rotate_mat(angle, axis, _coordinate_system);
00484 
00485   return true;
00486 }
00487 
00488 ////////////////////////////////////////////////////////////////////
00489 //     Function: EggWriter::dispatch_translate
00490 //       Access: Protected, Static
00491 //  Description: Handles -TT, which specifies a translate transform.
00492 //               Var is an LMatrix4d.
00493 ////////////////////////////////////////////////////////////////////
00494 bool EggWriter::
00495 dispatch_translate(const string &opt, const string &arg, void *var) {
00496   LMatrix4d *transform = (LMatrix4d *)var;
00497 
00498   vector_string words;
00499   tokenize(arg, words, ",");
00500 
00501   LVector3d trans;
00502 
00503   bool okflag = false;
00504   if (words.size() == 3) {
00505     okflag =
00506       string_to_double(words[0], trans[0]) &&
00507       string_to_double(words[1], trans[1]) &&
00508       string_to_double(words[2], trans[2]);
00509   }
00510 
00511   if (!okflag) {
00512     nout << "-" << opt
00513          << " requires three numbers separated by commas.\n";
00514     return false;
00515   }
00516 
00517   *transform = (*transform) * LMatrix4d::translate_mat(trans);
00518 
00519   return true;
00520 }

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