Panda3D

eggBase.cxx

00001 // Filename: eggBase.cxx
00002 // Created by:  drose (14Feb00)
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 "eggBase.h"
00016 
00017 #include "eggGroupNode.h"
00018 #include "eggTexture.h"
00019 #include "eggFilenameNode.h"
00020 #include "eggComment.h"
00021 #include "dcast.h"
00022 #include "string_utils.h"
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: EggBase::Constructor
00026 //       Access: Public
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 EggBase::
00030 EggBase() {
00031   add_option
00032     ("cs", "coordinate-system", 80,
00033      "Specify the coordinate system to operate in.  This may be one of "
00034      "'y-up', 'z-up', 'y-up-left', or 'z-up-left'.",
00035      &EggBase::dispatch_coordinate_system,
00036      &_got_coordinate_system, &_coordinate_system);
00037 
00038   _normals_mode = NM_preserve;
00039   _normals_threshold = 0.0;
00040 
00041   _got_tbnall = false;
00042   _got_tbnauto = false;
00043   _make_points = false;
00044 
00045   _got_transform = false;
00046   _transform = LMatrix4d::ident_mat();
00047 
00048   _got_coordinate_system = false;
00049   _coordinate_system = CS_yup_right;
00050 
00051   _noabs = false;
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: EggBase::add_normals_options
00056 //       Access: Public
00057 //  Description: Adds -no, -np, etc. as valid options for this
00058 //               program.  If the user specifies one of the options on
00059 //               the command line, the normals will be adjusted when
00060 //               the egg file is written out.
00061 ////////////////////////////////////////////////////////////////////
00062 void EggBase::
00063 add_normals_options() {
00064   static NormalsMode strip = NM_strip;
00065   static NormalsMode polygon = NM_polygon;
00066   static NormalsMode vertex = NM_vertex;
00067   static NormalsMode preserve = NM_preserve;
00068 
00069   add_option
00070     ("no", "", 48,
00071      "Strip all normals.",
00072      &EggBase::dispatch_normals, NULL, &strip);
00073 
00074   add_option
00075     ("np", "", 48,
00076      "Strip existing normals and redefine polygon normals.",
00077      &EggBase::dispatch_normals, NULL, &polygon);
00078 
00079   add_option
00080     ("nv", "threshold", 48,
00081      "Strip existing normals and redefine vertex normals.  Consider an edge "
00082      "between adjacent polygons to be smooth if the angle between them "
00083      "is less than threshold degrees.",
00084      &EggBase::dispatch_normals, NULL, &vertex);
00085 
00086   add_option
00087     ("nn", "", 48,
00088      "Preserve normals exactly as they are.  This is the default.",
00089      &EggBase::dispatch_normals, NULL, &preserve);
00090 
00091   add_option
00092     ("tbn", "name", 48,
00093      "Compute tangent and binormal for the named texture coordinate "
00094      "set(s).  The name may include wildcard characters such as * and ?.  "
00095      "The normal must already exist or have been computed via one of the "
00096      "above options.  The tangent and binormal are used to implement "
00097      "bump mapping and related texture-based lighting effects.  This option "
00098      "may be repeated as necessary to name multiple texture coordinate sets.",
00099      &EggBase::dispatch_vector_string, NULL, &_tbn_names);
00100 
00101   add_option
00102     ("tbnall", "", 48,
00103      "Compute tangent and binormal for all texture coordinate "
00104      "sets.  This is equivalent to -tbn \"*\".",
00105      &EggBase::dispatch_none, &_got_tbnall);
00106 
00107   add_option
00108     ("tbnauto", "", 48,
00109      "Compute tangent and binormal for all normal maps. ",
00110      &EggBase::dispatch_none, &_got_tbnauto);
00111 }
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: EggBase::add_points_options
00115 //       Access: Public
00116 //  Description: Adds -points as a valid option for this program.
00117 ////////////////////////////////////////////////////////////////////
00118 void EggBase::
00119 add_points_options() {
00120   add_option
00121     ("points", "", 46,
00122      "Construct <PointLight> entries for any unreferenced vertices, to make them visible.",
00123      &EggBase::dispatch_none, &_make_points);
00124 }
00125 
00126 ////////////////////////////////////////////////////////////////////
00127 //     Function: EggBase::add_transform_options
00128 //       Access: Public
00129 //  Description: Adds -TS, -TT, etc. as valid options for this
00130 //               program.  If the user specifies one of the options on
00131 //               the command line, the data will be transformed when
00132 //               the egg file is written out.
00133 ////////////////////////////////////////////////////////////////////
00134 void EggBase::
00135 add_transform_options() {
00136   add_option
00137     ("TS", "sx[,sy,sz]", 49,
00138      "Scale the model uniformly by the given factor (if only one number "
00139      "is given) or in each axis by sx, sy, sz (if three numbers are given).",
00140      &EggBase::dispatch_scale, &_got_transform, &_transform);
00141 
00142   add_option
00143     ("TR", "x,y,z", 49,
00144      "Rotate the model x degrees about the x axis, then y degrees about the "
00145      "y axis, and then z degrees about the z axis.",
00146      &EggBase::dispatch_rotate_xyz, &_got_transform, &_transform);
00147 
00148   add_option
00149     ("TA", "angle,x,y,z", 49,
00150      "Rotate the model angle degrees counterclockwise about the given "
00151      "axis.",
00152      &EggBase::dispatch_rotate_axis, &_got_transform, &_transform);
00153 
00154   add_option
00155     ("TT", "x,y,z", 49,
00156      "Translate the model by the indicated amount.\n\n"
00157      "All transformation options (-TS, -TR, -TA, -TT) are cumulative and are "
00158      "applied in the order they are encountered on the command line.",
00159      &EggBase::dispatch_translate, &_got_transform, &_transform);
00160 }
00161 
00162 ////////////////////////////////////////////////////////////////////
00163 //     Function: EggBase::convert_paths
00164 //       Access: Public, Static
00165 //  Description: Recursively walks the egg hierarchy.  Any filenames
00166 //               encountered are replaced according to the indicated
00167 //               PathReplace.
00168 ////////////////////////////////////////////////////////////////////
00169 void EggBase::
00170 convert_paths(EggNode *node, PathReplace *path_replace,
00171               const DSearchPath &additional_path) {
00172   if (node->is_of_type(EggTexture::get_class_type())) {
00173     EggTexture *egg_tex = DCAST(EggTexture, node);
00174     Filename fullpath, outpath;
00175     path_replace->full_convert_path(egg_tex->get_filename(), additional_path,
00176                                     fullpath, outpath);
00177     egg_tex->set_filename(outpath);
00178     egg_tex->set_fullpath(fullpath);
00179 
00180     if (egg_tex->has_alpha_filename()) {
00181       Filename alpha_fullpath, alpha_outpath;
00182       path_replace->full_convert_path(egg_tex->get_alpha_filename(), additional_path,
00183                                       alpha_fullpath, alpha_outpath);
00184       egg_tex->set_alpha_filename(alpha_outpath);
00185       egg_tex->set_alpha_fullpath(alpha_fullpath);
00186     }
00187 
00188   } else if (node->is_of_type(EggFilenameNode::get_class_type())) {
00189     EggFilenameNode *egg_fnode = DCAST(EggFilenameNode, node);
00190 
00191     Filename fullpath, outpath;
00192     path_replace->full_convert_path(egg_fnode->get_filename(), additional_path,
00193                                     fullpath, outpath);
00194     egg_fnode->set_filename(outpath);
00195     egg_fnode->set_fullpath(fullpath);
00196 
00197   } else if (node->is_of_type(EggGroupNode::get_class_type())) {
00198     EggGroupNode *egg_group = DCAST(EggGroupNode, node);
00199     EggGroupNode::const_iterator ci;
00200     for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
00201       convert_paths(*ci, path_replace, additional_path);
00202     }
00203   }
00204 }
00205 
00206 ////////////////////////////////////////////////////////////////////
00207 //     Function: EggBase::append_command_comment
00208 //       Access: Protected
00209 //  Description: Inserts a comment into the beginning of the indicated
00210 //               egg file corresponding to the command line that
00211 //               invoked this program.
00212 //
00213 //               Normally this function is called automatically when
00214 //               appropriate by EggWriter, and it's not necessary to
00215 //               call it explicitly.
00216 ////////////////////////////////////////////////////////////////////
00217 void EggBase::
00218 append_command_comment(EggData *data) {
00219   append_command_comment(data, get_exec_command());
00220 }
00221 
00222 ////////////////////////////////////////////////////////////////////
00223 //     Function: EggBase::append_command_comment
00224 //       Access: Protected, Static
00225 //  Description: Inserts a comment into the beginning of the indicated
00226 //               egg file corresponding to the command line that
00227 //               invoked this program.
00228 //
00229 //               Normally this function is called automatically when
00230 //               appropriate by EggWriter, and it's not necessary to
00231 //               call it explicitly.
00232 ////////////////////////////////////////////////////////////////////
00233 void EggBase::
00234 append_command_comment(EggData *data, const string &comment) {
00235   data->insert(data->begin(), new EggComment("", comment));
00236 }
00237 
00238 ////////////////////////////////////////////////////////////////////
00239 //     Function: EggBase::dispatch_normals
00240 //       Access: Protected, Static
00241 //  Description: Accepts one of -no, -np, etc. and sets _normals_mode
00242 //               as indicated.  The void * argument is a pointer to a
00243 //               NormalsMode variable that indicates which switch was
00244 //               passed.
00245 ////////////////////////////////////////////////////////////////////
00246 bool EggBase::
00247 dispatch_normals(ProgramBase *self, const string &opt, const string &arg, void *mode) {
00248   EggBase *base = (EggBase *)self;
00249   return base->ns_dispatch_normals(opt, arg, mode);
00250 }
00251 
00252 ////////////////////////////////////////////////////////////////////
00253 //     Function: EggBase::ns_dispatch_normals
00254 //       Access: Protected
00255 //  Description: Accepts one of -no, -np, etc. and sets _normals_mode
00256 //               as indicated.  The void * argument is a pointer to a
00257 //               NormalsMode variable that indicates which switch was
00258 //               passed.
00259 ////////////////////////////////////////////////////////////////////
00260 bool EggBase::
00261 ns_dispatch_normals(const string &opt, const string &arg, void *mode) {
00262   _normals_mode = *(NormalsMode *)mode;
00263 
00264   if (_normals_mode == NM_vertex) {
00265     if (!string_to_double(arg, _normals_threshold)) {
00266       nout << "Invalid numeric parameter for -" << opt << ": "
00267            << arg << "\n";
00268       return false;
00269     }
00270   }
00271 
00272   return true;
00273 }
00274 
00275 ////////////////////////////////////////////////////////////////////
00276 //     Function: EggBase::dispatch_scale
00277 //       Access: Protected, Static
00278 //  Description: Handles -TS, which specifies a scale transform.  Var
00279 //               is an LMatrix4d.
00280 ////////////////////////////////////////////////////////////////////
00281 bool EggBase::
00282 dispatch_scale(const string &opt, const string &arg, void *var) {
00283   LMatrix4d *transform = (LMatrix4d *)var;
00284 
00285   vector_string words;
00286   tokenize(arg, words, ",");
00287 
00288   double sx, sy, sz;
00289 
00290   bool okflag = false;
00291   if (words.size() == 3) {
00292     okflag =
00293       string_to_double(words[0], sx) &&
00294       string_to_double(words[1], sy) &&
00295       string_to_double(words[2], sz);
00296 
00297   } else if (words.size() == 1) {
00298     okflag =
00299       string_to_double(words[0], sx);
00300     sy = sz = sx;
00301   }
00302 
00303   if (!okflag) {
00304     nout << "-" << opt
00305          << " requires one or three numbers separated by commas.\n";
00306     return false;
00307   }
00308 
00309   *transform = (*transform) * LMatrix4d::scale_mat(sx, sy, sz);
00310 
00311   return true;
00312 }
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: EggBase::dispatch_rotate_xyz
00316 //       Access: Protected, Static
00317 //  Description: Handles -TR, which specifies a rotate transform about
00318 //               the three cardinal axes.  Var is an LMatrix4d.
00319 ////////////////////////////////////////////////////////////////////
00320 bool EggBase::
00321 dispatch_rotate_xyz(ProgramBase *self, const string &opt, const string &arg, void *var) {
00322   EggBase *base = (EggBase *)self;
00323   return base->ns_dispatch_rotate_xyz(opt, arg, var);
00324 }
00325 
00326 ////////////////////////////////////////////////////////////////////
00327 //     Function: EggBase::ns_dispatch_rotate_xyz
00328 //       Access: Protected
00329 //  Description: Handles -TR, which specifies a rotate transform about
00330 //               the three cardinal axes.  Var is an LMatrix4d.
00331 ////////////////////////////////////////////////////////////////////
00332 bool EggBase::
00333 ns_dispatch_rotate_xyz(const string &opt, const string &arg, void *var) {
00334   LMatrix4d *transform = (LMatrix4d *)var;
00335 
00336   vector_string words;
00337   tokenize(arg, words, ",");
00338 
00339   LVecBase3d xyz;
00340 
00341   bool okflag = false;
00342   if (words.size() == 3) {
00343     okflag =
00344       string_to_double(words[0], xyz[0]) &&
00345       string_to_double(words[1], xyz[1]) &&
00346       string_to_double(words[2], xyz[2]);
00347   }
00348 
00349   if (!okflag) {
00350     nout << "-" << opt
00351          << " requires three numbers separated by commas.\n";
00352     return false;
00353   }
00354 
00355   LMatrix4d mat =
00356     LMatrix4d::rotate_mat(xyz[0], LVector3d(1.0, 0.0, 0.0), _coordinate_system) *
00357     LMatrix4d::rotate_mat(xyz[1], LVector3d(0.0, 1.0, 0.0), _coordinate_system) *
00358     LMatrix4d::rotate_mat(xyz[2], LVector3d(0.0, 0.0, 1.0), _coordinate_system);
00359 
00360   *transform = (*transform) * mat;
00361 
00362   return true;
00363 }
00364 
00365 ////////////////////////////////////////////////////////////////////
00366 //     Function: EggBase::dispatch_rotate_axis
00367 //       Access: Protected, Static
00368 //  Description: Handles -TA, which specifies a rotate transform about
00369 //               an arbitrary axis.  Var is an LMatrix4d.
00370 ////////////////////////////////////////////////////////////////////
00371 bool EggBase::
00372 dispatch_rotate_axis(ProgramBase *self, const string &opt, const string &arg, void *var) {
00373   EggBase *base = (EggBase *)self;
00374   return base->ns_dispatch_rotate_axis(opt, arg, var);
00375 }
00376 
00377 ////////////////////////////////////////////////////////////////////
00378 //     Function: EggBase::ns_dispatch_rotate_axis
00379 //       Access: Protected
00380 //  Description: Handles -TA, which specifies a rotate transform about
00381 //               an arbitrary axis.  Var is an LMatrix4d.
00382 ////////////////////////////////////////////////////////////////////
00383 bool EggBase::
00384 ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var) {
00385   LMatrix4d *transform = (LMatrix4d *)var;
00386 
00387   vector_string words;
00388   tokenize(arg, words, ",");
00389 
00390   double angle;
00391   LVecBase3d axis;
00392 
00393   bool okflag = false;
00394   if (words.size() == 4) {
00395     okflag =
00396       string_to_double(words[0], angle) &&
00397       string_to_double(words[1], axis[0]) &&
00398       string_to_double(words[2], axis[1]) &&
00399       string_to_double(words[3], axis[2]);
00400   }
00401 
00402   if (!okflag) {
00403     nout << "-" << opt
00404          << " requires four numbers separated by commas.\n";
00405     return false;
00406   }
00407 
00408   *transform = (*transform) * LMatrix4d::rotate_mat(angle, axis, _coordinate_system);
00409 
00410   return true;
00411 }
00412 
00413 ////////////////////////////////////////////////////////////////////
00414 //     Function: EggBase::dispatch_translate
00415 //       Access: Protected, Static
00416 //  Description: Handles -TT, which specifies a translate transform.
00417 //               Var is an LMatrix4d.
00418 ////////////////////////////////////////////////////////////////////
00419 bool EggBase::
00420 dispatch_translate(const string &opt, const string &arg, void *var) {
00421   LMatrix4d *transform = (LMatrix4d *)var;
00422 
00423   vector_string words;
00424   tokenize(arg, words, ",");
00425 
00426   LVector3d trans;
00427 
00428   bool okflag = false;
00429   if (words.size() == 3) {
00430     okflag =
00431       string_to_double(words[0], trans[0]) &&
00432       string_to_double(words[1], trans[1]) &&
00433       string_to_double(words[2], trans[2]);
00434   }
00435 
00436   if (!okflag) {
00437     nout << "-" << opt
00438          << " requires three numbers separated by commas.\n";
00439     return false;
00440   }
00441 
00442   *transform = (*transform) * LMatrix4d::translate_mat(trans);
00443 
00444   return true;
00445 }
 All Classes Functions Variables Enumerations