00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "eggQtess.h"
00016 #include "qtessGlobals.h"
00017 #include "dcast.h"
00018 #include "pystub.h"
00019
00020
00021
00022
00023
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
00118
00119
00120
00121
00122
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
00136
00137
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
00165
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
00187
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
00211
00212
00213 _surfaces.clear();
00214
00215 _data->remove_unused_vertices(true);
00216 write_egg_file();
00217 }
00218 }
00219
00220
00221
00222
00223
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
00321
00322
00323
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
00348 pystub();
00349
00350 EggQtess prog;
00351 prog.parse_command_line(argc, argv);
00352 prog.run();
00353 return 0;
00354 }
00355