Panda3D
|
00001 // Filename: eggQtess.cxx 00002 // Created by: drose (13Oct03) 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 "eggQtess.h" 00016 #include "qtessGlobals.h" 00017 #include "dcast.h" 00018 #include "pystub.h" 00019 00020 //////////////////////////////////////////////////////////////////// 00021 // Function: EggQtess::Constructor 00022 // Access: Public 00023 // Description: 00024 //////////////////////////////////////////////////////////////////// 00025 EggQtess:: 00026 EggQtess() { 00027 add_normals_options(); 00028 00029 set_program_description 00030 ("egg-qtess reads an egg file, tesselates all of its NURBS surfaces " 00031 "using a simple uniform tesselation, and outputs a polygonal " 00032 "egg file.\n\n" 00033 00034 "Characters are supported, soft-skinned and otherwise; joint " 00035 "ownership is computed correctly for each new polygon vertex. " 00036 "Primitives other than NURBS surfaces appearing in the egg file " 00037 "are unaffected."); 00038 00039 add_option 00040 ("f", "filename", 0, 00041 "Read the indicated parameter file. Type egg-qtess -H " 00042 "to print a description of the parameter file format.", 00043 &EggQtess::dispatch_filename, NULL, &_qtess_filename); 00044 00045 add_option 00046 ("up", "subdiv", 0, 00047 "Specify a uniform subdivision per patch (isoparam). Each NURBS " 00048 "surface is made up of N x M patches, each of which is divided " 00049 "into subdiv x subdiv quads. A fractional number is allowed.", 00050 &EggQtess::dispatch_double, NULL, &_uniform_per_isoparam); 00051 00052 add_option 00053 ("us", "subdiv", 0, 00054 "Specify a uniform subdivision per surface. Each NURBS " 00055 "surface is subdivided into subdiv x subdiv quads, regardless " 00056 "of the number of isoparams it has. A fractional number is " 00057 "meaningless.", 00058 &EggQtess::dispatch_int, NULL, &_uniform_per_surface); 00059 00060 add_option 00061 ("t", "tris", 0, 00062 "Specify an approximate number of triangles to produce. This " 00063 "is the total number of triangles for the entire egg file, " 00064 "including those surfaces that have already been given an " 00065 "explicit tesselation by a parameter file.", 00066 &EggQtess::dispatch_int, NULL, &_total_tris); 00067 00068 add_option 00069 ("ap", "", 0, 00070 "Attempt to automatically place tesselation lines where they'll " 00071 "do the most good on each surface (once the number of polygons " 00072 "for the surface has already been determined).", 00073 &EggQtess::dispatch_none, &QtessGlobals::_auto_place); 00074 00075 add_option 00076 ("ad", "", 0, 00077 "Attempt to automatically distribute polygons among the surfaces " 00078 "where they are most needed according to curvature and size, " 00079 "instead of according to the number of isoparams. This only has " 00080 "meaning when used in conjunction with -t.", 00081 &EggQtess::dispatch_none, &QtessGlobals::_auto_distribute); 00082 00083 add_option 00084 ("ar", "ratio", 0, 00085 "Specify the ratio of dominance of size to curvature for -ap and " 00086 "-ad. A value of 0 forces placement by curvature only; a very " 00087 "large value (like 1000) forces placement by size only. The " 00088 "default is 5.0.", 00089 &EggQtess::dispatch_double, NULL, &QtessGlobals::_curvature_ratio); 00090 00091 add_option 00092 ("e", "", 0, 00093 "Respect subdivision parameters given in the egg file. If this " 00094 "is specified, the egg file may define the effective number of " 00095 "patches of each NURBS entry. This can be used alone or in " 00096 "conjunction with -u or -t to fine-tune the uniform tesselation " 00097 "on a per-surface basis. (This is ignored if -ad is in effect.)", 00098 &EggQtess::dispatch_none, &QtessGlobals::_respect_egg); 00099 00100 add_option 00101 ("q", "", 0, 00102 "Instead of writing an egg file, generate a parameter file " 00103 "for output.", 00104 &EggQtess::dispatch_none, &_qtess_output); 00105 00106 add_option 00107 ("H", "", 0, 00108 "Describe the format of the parameter file specified with -f.", 00109 &EggQtess::dispatch_none, &_describe_qtess); 00110 00111 _uniform_per_isoparam = 0.0; 00112 _uniform_per_surface = 0; 00113 _total_tris = 0; 00114 } 00115 00116 //////////////////////////////////////////////////////////////////// 00117 // Function: EggQtess::handle_args 00118 // Access: Protected, Virtual 00119 // Description: Does something with the additional arguments on the 00120 // command line (after all the -options have been 00121 // parsed). Returns true if the arguments are good, 00122 // false otherwise. 00123 //////////////////////////////////////////////////////////////////// 00124 bool EggQtess:: 00125 handle_args(ProgramBase::Args &args) { 00126 if (_describe_qtess) { 00127 describe_qtess_format(); 00128 exit(0); 00129 } 00130 00131 return EggFilter::handle_args(args); 00132 } 00133 00134 //////////////////////////////////////////////////////////////////// 00135 // Function: EggQtess::run 00136 // Access: Public 00137 // Description: 00138 //////////////////////////////////////////////////////////////////// 00139 void EggQtess:: 00140 run() { 00141 bool read_qtess = false; 00142 if (!_qtess_filename.empty()) { 00143 if (!_qtess_file.read(_qtess_filename)) { 00144 exit(1); 00145 } 00146 read_qtess = true; 00147 } 00148 00149 find_surfaces(_data); 00150 00151 QtessInputEntry &default_entry = _qtess_file.get_default_entry(); 00152 if (!read_qtess || default_entry.get_num_surfaces() == 0) { 00153 nout << _surfaces.size() << " NURBS surfaces found.\n"; 00154 00155 } else { 00156 nout << _surfaces.size() << " NURBS surfaces found; " 00157 << default_entry.get_num_surfaces() 00158 << " unaccounted for by input file.\n"; 00159 } 00160 00161 int num_tris = _qtess_file.count_tris(); 00162 00163 if (_total_tris != 0) { 00164 // Whatever number of triangles we have unaccounted for, assign to 00165 // the default bucket. 00166 int extra_tris = max(0, _total_tris - num_tris); 00167 if (read_qtess && default_entry.get_num_surfaces() != 0) { 00168 cerr << extra_tris << " triangles unaccounted for.\n"; 00169 } 00170 00171 default_entry.set_num_tris(extra_tris); 00172 00173 } else if (_uniform_per_isoparam!=0.0) { 00174 default_entry.set_per_isoparam(_uniform_per_isoparam); 00175 00176 } else if (_uniform_per_surface!=0.0) { 00177 default_entry.set_uv(_uniform_per_surface, _uniform_per_surface); 00178 00179 } else { 00180 default_entry.set_per_isoparam(1.0); 00181 } 00182 00183 default_entry.count_tris(); 00184 00185 if (_qtess_output) { 00186 // Sort the names into alphabetical order for aesthetics. 00187 //sort(_surfaces.begin(), _surfaces.end(), compare_surfaces()); 00188 00189 int tris = 0; 00190 00191 ostream &out = get_output(); 00192 Surfaces::const_iterator si; 00193 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) { 00194 tris += (*si)->write_qtess_parameter(out); 00195 } 00196 00197 cerr << tris << " tris generated.\n"; 00198 00199 } else { 00200 00201 int tris = 0; 00202 00203 Surfaces::const_iterator si; 00204 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) { 00205 tris += (*si)->tesselate(); 00206 } 00207 00208 cerr << tris << " tris generated.\n"; 00209 00210 // Clear out the surfaces list before removing the vertices, since 00211 // each surface is holding reference counts to the previously-used 00212 // vertices. 00213 _surfaces.clear(); 00214 00215 _data->remove_unused_vertices(true); 00216 write_egg_file(); 00217 } 00218 } 00219 00220 //////////////////////////////////////////////////////////////////// 00221 // Function: EggQtess::describe_qtess_format 00222 // Access: Private 00223 // Description: 00224 //////////////////////////////////////////////////////////////////// 00225 void EggQtess:: 00226 describe_qtess_format() { 00227 nout << 00228 "An egg-qtess parameter file consists of lines of the form:\n\n" 00229 00230 "name [name...] : parameters\n\n" 00231 00232 "Where name is a string (possibly including wildcard characters " 00233 "such as * and ?) that matches one or more surface " 00234 "names, and parameters is a tesselation specification, described below. " 00235 "The colon must be followed by at least one space to differentiate it " 00236 "from a colon character in the name(s). Multiple names " 00237 "may be combined on one line.\n\n\n" 00238 00239 00240 "The parameters may be any of the following. Lowercase letters are " 00241 "literal. NUM is any number.\n\n"; 00242 00243 show_text(" omit", 10, 00244 "Remove the surface from the output.\n\n"); 00245 00246 show_text(" NUM", 10, 00247 "Try to achieve the indicated number of triangles over all the " 00248 "surfaces matched by this line.\n\n"); 00249 00250 show_text(" NUM NUM [[!]u# [!]u# ...] [[!]v# [!]v# ...]", 10, 00251 "Tesselate to NUM x NUM quads. If u# or v# appear, they indicate " 00252 "additional isoparams to insert (or remove if preceded by an " 00253 "exclamation point). The range is [0, 1].\n\n"); 00254 00255 show_text(" iNUM", 10, 00256 "Subdivision amount per isoparam. Equivalent to the command-line " 00257 "option -u NUM.\n\n"); 00258 00259 show_text(" NUM%", 10, 00260 "This is a special parameter. This does not request any specific " 00261 "tesselation for the named surfaces, but instead gives a relative " 00262 "importance for them when they appear with other surfaces in a " 00263 "later entry (or are tesselated via -t on the command line). In " 00264 "general, a surface with a weight of 25% will be given a quarter " 00265 "of the share of the polygons it otherwise would have received; " 00266 "a weight of 150% will give the surface 50% more than its fair " 00267 "share.\n\n"); 00268 00269 show_text(" matchvu", 10, 00270 "This is a special parameter that indicates that two or more " 00271 "surfaces share a common edge, and must be tesselated the " 00272 "same way " 00273 "along that edge. Specifically, matchvu means that the V " 00274 "tesselation of the first named surface will be applied to the U " 00275 "tesselation of the second (and later) named surface(s). Similar " 00276 "definitions exist for matchuv, matchuu, and matchvv.\n\n"); 00277 00278 show_text(" minu NUM", 10, 00279 "This is another special parameter that specifies a " 00280 "minimum tesselation for all these surfaces in " 00281 "the U direction. This is " 00282 "the number of quads across the dimension the surface will be " 00283 "broken into. The default is 1 for an open surface, and 3 for " 00284 "a closed surface.\n\n"); 00285 00286 show_text(" minv NUM", 10, 00287 "Similar to minv, in the V direction.\n\n"); 00288 00289 nout << 00290 "In addition, the following optional parameters may appear. If they appear, " 00291 "they override similar parameters given on the command line; if they do not " 00292 "appear, the defaults are taken from the command line:\n\n"; 00293 00294 show_text(" ap", 10, 00295 "Automatically place tesselation lines on each surface where they " 00296 "seem to be needed most.\n\n"); 00297 00298 show_text(" !ap", 10, 00299 "Do not move lines automatically; use a strict uniform " 00300 "tesselation.\n\n"); 00301 00302 show_text(" ad", 10, 00303 "Automatically distribute polygons to the surfaces that seem to " 00304 "need them the most.\n\n"); 00305 00306 show_text(" !ad", 10, 00307 "Do not automatically distribute polygons; distribute " 00308 "them according to the number of isoparams of each surface.\n\n"); 00309 00310 show_text(" arNUM", 10, 00311 "Specify the ratio of dominance of size to curvature.\n\n"); 00312 00313 nout << 00314 "The hash symbol '#' begins a comment if it is preceded by whitespace or at the " 00315 "beginning of a line. The backslash character at the end of a line can be used " 00316 "to indicate a continuation.\n\n"; 00317 } 00318 00319 //////////////////////////////////////////////////////////////////// 00320 // Function: EggQtess::find_surfaces 00321 // Access: Private 00322 // Description: Recursively walks the egg graph, collecting all the 00323 // NURBS surfaces found. 00324 //////////////////////////////////////////////////////////////////// 00325 void EggQtess:: 00326 find_surfaces(EggNode *egg_node) { 00327 if (egg_node->is_of_type(EggNurbsSurface::get_class_type())) { 00328 PT(QtessSurface) surface = 00329 new QtessSurface(DCAST(EggNurbsSurface, egg_node)); 00330 if (surface->is_valid()) { 00331 _surfaces.push_back(surface); 00332 QtessInputEntry::Type match_type = _qtess_file.match(surface); 00333 nassertv(match_type != QtessInputEntry::T_undefined); 00334 } 00335 } 00336 00337 if (egg_node->is_of_type(EggGroupNode::get_class_type())) { 00338 EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node); 00339 EggGroupNode::const_iterator ci; 00340 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) { 00341 find_surfaces(*ci); 00342 } 00343 } 00344 } 00345 00346 int main(int argc, char *argv[]) { 00347 // A call to pystub() to force libpystub.so to be linked in. 00348 pystub(); 00349 00350 EggQtess prog; 00351 prog.parse_command_line(argc, argv); 00352 prog.run(); 00353 return 0; 00354 } 00355