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