Panda3D
 All Classes Functions Variables Enumerations
eggQtess.cxx
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 
 All Classes Functions Variables Enumerations