25 set_program_brief(
"tesselate NURBS surfaces in .egg files");
26 set_program_description
27 (
"egg-qtess reads an egg file, tessellates all of its NURBS surfaces "
28 "using a simple uniform tessellation, and outputs a polygonal "
31 "Characters are supported, soft-skinned and otherwise; joint "
32 "ownership is computed correctly for each new polygon vertex. "
33 "Primitives other than NURBS surfaces appearing in the egg file "
38 "Read the indicated parameter file. Type egg-qtess -H "
39 "to print a description of the parameter file format.",
40 &EggQtess::dispatch_filename,
nullptr, &_qtess_filename);
44 "Specify a uniform subdivision per patch (isoparam). Each NURBS "
45 "surface is made up of N x M patches, each of which is divided "
46 "into subdiv x subdiv quads. A fractional number is allowed.",
47 &EggQtess::dispatch_double,
nullptr, &_uniform_per_isoparam);
51 "Specify a uniform subdivision per surface. Each NURBS "
52 "surface is subdivided into subdiv x subdiv quads, regardless "
53 "of the number of isoparams it has. A fractional number is "
55 &EggQtess::dispatch_int,
nullptr, &_uniform_per_surface);
59 "Specify an approximate number of triangles to produce. This "
60 "is the total number of triangles for the entire egg file, "
61 "including those surfaces that have already been given an "
62 "explicit tessellation by a parameter file.",
63 &EggQtess::dispatch_int,
nullptr, &_total_tris);
67 "Attempt to automatically place tessellation lines where they'll "
68 "do the most good on each surface (once the number of polygons "
69 "for the surface has already been determined).",
70 &EggQtess::dispatch_none, &QtessGlobals::_auto_place);
74 "Attempt to automatically distribute polygons among the surfaces "
75 "where they are most needed according to curvature and size, "
76 "instead of according to the number of isoparams. This only has "
77 "meaning when used in conjunction with -t.",
78 &EggQtess::dispatch_none, &QtessGlobals::_auto_distribute);
82 "Specify the ratio of dominance of size to curvature for -ap and "
83 "-ad. A value of 0 forces placement by curvature only; a very "
84 "large value (like 1000) forces placement by size only. The "
86 &EggQtess::dispatch_double,
nullptr, &QtessGlobals::_curvature_ratio);
90 "Respect subdivision parameters given in the egg file. If this "
91 "is specified, the egg file may define the effective number of "
92 "patches of each NURBS entry. This can be used alone or in "
93 "conjunction with -u or -t to fine-tune the uniform tessellation "
94 "on a per-surface basis. (This is ignored if -ad is in effect.)",
95 &EggQtess::dispatch_none, &QtessGlobals::_respect_egg);
99 "Instead of writing an egg file, generate a parameter file "
101 &EggQtess::dispatch_none, &_qtess_output);
105 "Describe the format of the parameter file specified with -f.",
106 &EggQtess::dispatch_none, &_describe_qtess);
108 _uniform_per_isoparam = 0.0;
109 _uniform_per_surface = 0;
120 if (_describe_qtess) {
121 describe_qtess_format();
125 return EggFilter::handle_args(args);
133 bool read_qtess =
false;
134 if (!_qtess_filename.empty()) {
135 if (!_qtess_file.
read(_qtess_filename)) {
141 find_surfaces(_data);
144 if (!read_qtess || default_entry.get_num_surfaces() == 0) {
145 nout << _surfaces.size() <<
" NURBS surfaces found.\n";
148 nout << _surfaces.size() <<
" NURBS surfaces found; "
149 << default_entry.get_num_surfaces()
150 <<
" unaccounted for by input file.\n";
155 if (_total_tris != 0) {
158 int extra_tris = std::max(0, _total_tris - num_tris);
159 if (read_qtess && default_entry.get_num_surfaces() != 0) {
160 std::cerr << extra_tris <<
" triangles unaccounted for.\n";
163 default_entry.set_num_tris(extra_tris);
165 }
else if (_uniform_per_isoparam!=0.0) {
166 default_entry.set_per_isoparam(_uniform_per_isoparam);
168 }
else if (_uniform_per_surface!=0.0) {
169 default_entry.set_uv(_uniform_per_surface, _uniform_per_surface);
172 default_entry.set_per_isoparam(1.0);
184 Surfaces::const_iterator si;
185 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
186 tris += (*si)->write_qtess_parameter(out);
189 std::cerr << tris <<
" tris generated.\n";
195 Surfaces::const_iterator si;
196 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
197 tris += (*si)->tesselate();
200 std::cerr << tris <<
" tris generated.\n";
206 _data->remove_unused_vertices(
true);
215 describe_qtess_format() {
217 "An egg-qtess parameter file consists of lines of the form:\n\n"
219 "name [name...] : parameters\n\n"
221 "Where name is a string (possibly including wildcard characters "
222 "such as * and ?) that matches one or more surface "
223 "names, and parameters is a tesselation specification, described below. "
224 "The colon must be followed by at least one space to differentiate it "
225 "from a colon character in the name(s). Multiple names "
226 "may be combined on one line.\n\n\n"
229 "The parameters may be any of the following. Lowercase letters are "
230 "literal. NUM is any number.\n\n";
233 "Remove the surface from the output.\n\n");
236 "Try to achieve the indicated number of triangles over all the "
237 "surfaces matched by this line.\n\n");
239 show_text(
" NUM NUM [[!]u# [!]u# ...] [[!]v# [!]v# ...]", 10,
240 "Tesselate to NUM x NUM quads. If u# or v# appear, they indicate "
241 "additional isoparams to insert (or remove if preceded by an "
242 "exclamation point). The range is [0, 1].\n\n");
245 "Subdivision amount per isoparam. Equivalent to the command-line "
246 "option -u NUM.\n\n");
249 "This is a special parameter. This does not request any specific "
250 "tesselation for the named surfaces, but instead gives a relative "
251 "importance for them when they appear with other surfaces in a "
252 "later entry (or are tesselated via -t on the command line). In "
253 "general, a surface with a weight of 25% will be given a quarter "
254 "of the share of the polygons it otherwise would have received; "
255 "a weight of 150% will give the surface 50% more than its fair "
259 "This is a special parameter that indicates that two or more "
260 "surfaces share a common edge, and must be tesselated the "
262 "along that edge. Specifically, matchvu means that the V "
263 "tesselation of the first named surface will be applied to the U "
264 "tesselation of the second (and later) named surface(s). Similar "
265 "definitions exist for matchuv, matchuu, and matchvv.\n\n");
268 "This is another special parameter that specifies a "
269 "minimum tesselation for all these surfaces in "
270 "the U direction. This is "
271 "the number of quads across the dimension the surface will be "
272 "broken into. The default is 1 for an open surface, and 3 for "
273 "a closed surface.\n\n");
276 "Similar to minv, in the V direction.\n\n");
279 "In addition, the following optional parameters may appear. If they appear, "
280 "they override similar parameters given on the command line; if they do not "
281 "appear, the defaults are taken from the command line:\n\n";
284 "Automatically place tesselation lines on each surface where they "
285 "seem to be needed most.\n\n");
288 "Do not move lines automatically; use a strict uniform "
292 "Automatically distribute polygons to the surfaces that seem to "
293 "need them the most.\n\n");
296 "Do not automatically distribute polygons; distribute "
297 "them according to the number of isoparams of each surface.\n\n");
300 "Specify the ratio of dominance of size to curvature.\n\n");
303 "The hash symbol '#' begins a comment if it is preceded by whitespace or at the "
304 "beginning of a line. The backslash character at the end of a line can be used "
305 "to indicate a continuation.\n\n";
312 find_surfaces(
EggNode *egg_node) {
313 if (egg_node->
is_of_type(EggNurbsSurface::get_class_type())) {
316 if (surface->is_valid()) {
317 _surfaces.push_back(surface);
318 QtessInputEntry::Type match_type = _qtess_file.
match(surface);
319 nassertv(match_type != QtessInputEntry::T_undefined);
323 if (egg_node->
is_of_type(EggGroupNode::get_class_type())) {
325 EggGroupNode::const_iterator ci;
326 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
332 int main(
int argc,
char *argv[]) {
void add_normals_options()
Adds -no, -np, etc.
A base class for nodes in the hierarchy that are not leaf nodes.
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...
void write_egg_file()
Writes out the egg file as the normal result of the program.
void show_text(const std::string &text)
Formats the indicated text to stderr with the known _terminal_width.
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_...
Stores one entry in the qtess input file.
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...
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
std::ostream & get_output()
Returns an output stream that corresponds to the user's intended egg file output–either stdout,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.