16 #include "qtessGlobals.h"
29 set_program_brief(
"tesselate NURBS surfaces in .egg files");
30 set_program_description
31 (
"egg-qtess reads an egg file, tessellates all of its NURBS surfaces "
32 "using a simple uniform tessellation, and outputs a polygonal "
35 "Characters are supported, soft-skinned and otherwise; joint "
36 "ownership is computed correctly for each new polygon vertex. "
37 "Primitives other than NURBS surfaces appearing in the egg file "
42 "Read the indicated parameter file. Type egg-qtess -H "
43 "to print a description of the parameter file format.",
44 &EggQtess::dispatch_filename, NULL, &_qtess_filename);
48 "Specify a uniform subdivision per patch (isoparam). Each NURBS "
49 "surface is made up of N x M patches, each of which is divided "
50 "into subdiv x subdiv quads. A fractional number is allowed.",
51 &EggQtess::dispatch_double, NULL, &_uniform_per_isoparam);
55 "Specify a uniform subdivision per surface. Each NURBS "
56 "surface is subdivided into subdiv x subdiv quads, regardless "
57 "of the number of isoparams it has. A fractional number is "
59 &EggQtess::dispatch_int, NULL, &_uniform_per_surface);
63 "Specify an approximate number of triangles to produce. This "
64 "is the total number of triangles for the entire egg file, "
65 "including those surfaces that have already been given an "
66 "explicit tessellation by a parameter file.",
67 &EggQtess::dispatch_int, NULL, &_total_tris);
71 "Attempt to automatically place tessellation lines where they'll "
72 "do the most good on each surface (once the number of polygons "
73 "for the surface has already been determined).",
74 &EggQtess::dispatch_none, &QtessGlobals::_auto_place);
78 "Attempt to automatically distribute polygons among the surfaces "
79 "where they are most needed according to curvature and size, "
80 "instead of according to the number of isoparams. This only has "
81 "meaning when used in conjunction with -t.",
82 &EggQtess::dispatch_none, &QtessGlobals::_auto_distribute);
86 "Specify the ratio of dominance of size to curvature for -ap and "
87 "-ad. A value of 0 forces placement by curvature only; a very "
88 "large value (like 1000) forces placement by size only. The "
90 &EggQtess::dispatch_double, NULL, &QtessGlobals::_curvature_ratio);
94 "Respect subdivision parameters given in the egg file. If this "
95 "is specified, the egg file may define the effective number of "
96 "patches of each NURBS entry. This can be used alone or in "
97 "conjunction with -u or -t to fine-tune the uniform tessellation "
98 "on a per-surface basis. (This is ignored if -ad is in effect.)",
99 &EggQtess::dispatch_none, &QtessGlobals::_respect_egg);
103 "Instead of writing an egg file, generate a parameter file "
105 &EggQtess::dispatch_none, &_qtess_output);
109 "Describe the format of the parameter file specified with -f.",
110 &EggQtess::dispatch_none, &_describe_qtess);
112 _uniform_per_isoparam = 0.0;
113 _uniform_per_surface = 0;
127 if (_describe_qtess) {
128 describe_qtess_format();
132 return EggFilter::handle_args(args);
142 bool read_qtess =
false;
143 if (!_qtess_filename.empty()) {
144 if (!_qtess_file.
read(_qtess_filename)) {
150 find_surfaces(_data);
153 if (!read_qtess || default_entry.get_num_surfaces() == 0) {
154 nout << _surfaces.size() <<
" NURBS surfaces found.\n";
157 nout << _surfaces.size() <<
" NURBS surfaces found; "
158 << default_entry.get_num_surfaces()
159 <<
" unaccounted for by input file.\n";
164 if (_total_tris != 0) {
167 int extra_tris = max(0, _total_tris - num_tris);
168 if (read_qtess && default_entry.get_num_surfaces() != 0) {
169 cerr << extra_tris <<
" triangles unaccounted for.\n";
172 default_entry.set_num_tris(extra_tris);
174 }
else if (_uniform_per_isoparam!=0.0) {
175 default_entry.set_per_isoparam(_uniform_per_isoparam);
177 }
else if (_uniform_per_surface!=0.0) {
178 default_entry.set_uv(_uniform_per_surface, _uniform_per_surface);
181 default_entry.set_per_isoparam(1.0);
193 Surfaces::const_iterator si;
194 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
195 tris += (*si)->write_qtess_parameter(out);
198 cerr << tris <<
" tris generated.\n";
204 Surfaces::const_iterator si;
205 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
206 tris += (*si)->tesselate();
209 cerr << tris <<
" tris generated.\n";
216 _data->remove_unused_vertices(
true);
227 describe_qtess_format() {
229 "An egg-qtess parameter file consists of lines of the form:\n\n"
231 "name [name...] : parameters\n\n"
233 "Where name is a string (possibly including wildcard characters "
234 "such as * and ?) that matches one or more surface "
235 "names, and parameters is a tesselation specification, described below. "
236 "The colon must be followed by at least one space to differentiate it "
237 "from a colon character in the name(s). Multiple names "
238 "may be combined on one line.\n\n\n"
241 "The parameters may be any of the following. Lowercase letters are "
242 "literal. NUM is any number.\n\n";
245 "Remove the surface from the output.\n\n");
248 "Try to achieve the indicated number of triangles over all the "
249 "surfaces matched by this line.\n\n");
251 show_text(
" NUM NUM [[!]u# [!]u# ...] [[!]v# [!]v# ...]", 10,
252 "Tesselate to NUM x NUM quads. If u# or v# appear, they indicate "
253 "additional isoparams to insert (or remove if preceded by an "
254 "exclamation point). The range is [0, 1].\n\n");
257 "Subdivision amount per isoparam. Equivalent to the command-line "
258 "option -u NUM.\n\n");
261 "This is a special parameter. This does not request any specific "
262 "tesselation for the named surfaces, but instead gives a relative "
263 "importance for them when they appear with other surfaces in a "
264 "later entry (or are tesselated via -t on the command line). In "
265 "general, a surface with a weight of 25% will be given a quarter "
266 "of the share of the polygons it otherwise would have received; "
267 "a weight of 150% will give the surface 50% more than its fair "
271 "This is a special parameter that indicates that two or more "
272 "surfaces share a common edge, and must be tesselated the "
274 "along that edge. Specifically, matchvu means that the V "
275 "tesselation of the first named surface will be applied to the U "
276 "tesselation of the second (and later) named surface(s). Similar "
277 "definitions exist for matchuv, matchuu, and matchvv.\n\n");
280 "This is another special parameter that specifies a "
281 "minimum tesselation for all these surfaces in "
282 "the U direction. This is "
283 "the number of quads across the dimension the surface will be "
284 "broken into. The default is 1 for an open surface, and 3 for "
285 "a closed surface.\n\n");
288 "Similar to minv, in the V direction.\n\n");
291 "In addition, the following optional parameters may appear. If they appear, "
292 "they override similar parameters given on the command line; if they do not "
293 "appear, the defaults are taken from the command line:\n\n";
296 "Automatically place tesselation lines on each surface where they "
297 "seem to be needed most.\n\n");
300 "Do not move lines automatically; use a strict uniform "
304 "Automatically distribute polygons to the surfaces that seem to "
305 "need them the most.\n\n");
308 "Do not automatically distribute polygons; distribute "
309 "them according to the number of isoparams of each surface.\n\n");
312 "Specify the ratio of dominance of size to curvature.\n\n");
315 "The hash symbol '#' begins a comment if it is preceded by whitespace or at the "
316 "beginning of a line. The backslash character at the end of a line can be used "
317 "to indicate a continuation.\n\n";
327 find_surfaces(
EggNode *egg_node) {
328 if (egg_node->
is_of_type(EggNurbsSurface::get_class_type())) {
331 if (surface->is_valid()) {
332 _surfaces.push_back(surface);
333 QtessInputEntry::Type match_type = _qtess_file.
match(surface);
334 nassertv(match_type != QtessInputEntry::T_undefined);
338 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
340 EggGroupNode::const_iterator ci;
341 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
347 int main(
int argc,
char *argv[]) {
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
A base class for nodes in the hierarchy that are not leaf nodes.
int count_tris(double tri_factor=1.0, int attempts=0)
Determines the tesselation u,v amounts of each attached surface, and stores this information in the s...
void add_normals_options()
Adds -no, -np, etc.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
void show_text(const string &text)
Formats the indicated text to stderr with the known _terminal_width.
Stores one entry in the qtess input file.
void write_egg_file()
Writes out the egg file as the normal result of the program.
ostream & get_output()
Returns an output stream that corresponds to the user's intended egg file output–either stdout...
A base class for things that may be directly added into the egg hierarchy.
A parametric NURBS surface.
A program to tesselate NURBS surfaces appearing within an egg file into polygons, using variations on...