Panda3D
|
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 }