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