00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 #include "eggWriter.h"
00020 
00021 #include "string_utils.h"
00022 #include "compose_matrix.h"
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 EggWriter::
00044 EggWriter(bool allow_last_param, bool allow_stdout) :
00045   WithOutputFile(allow_last_param, allow_stdout, false)
00046 {
00047   
00048   
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 
00106 
00107 
00108 
00109 
00110 
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 
00144 
00145 
00146 
00147 
00148 
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 
00180 
00181 
00182 
00183 
00184 
00185 
00186 
00187 
00188 
00189 
00190 EggWriter *EggWriter::
00191 as_writer() {
00192   return this;
00193 }
00194 
00195 
00196 
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
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     
00242     break;
00243   }
00244 }
00245 
00246 
00247 
00248 
00249 
00250 
00251 
00252 
00253 
00254 
00255 void EggWriter::
00256 write_egg_file() {
00257   post_process_egg_file();
00258   _data.write_egg(get_output());
00259 }
00260 
00261 
00262 
00263 
00264 
00265 
00266 
00267 
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     
00287     _path_replace->_path_directory = _output_filename.get_dirname();
00288   }
00289 
00290   return true;
00291 }
00292 
00293 
00294 
00295 
00296 
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 
00312 
00313 
00314 
00315 
00316 
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 
00327 
00328 
00329 
00330 
00331 
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 
00350 
00351 
00352 
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 
00389 
00390 
00391 
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 
00402 
00403 
00404 
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 
00441 
00442 
00443 
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 
00454 
00455 
00456 
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 
00490 
00491 
00492 
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 }