Panda3D
Loading...
Searching...
No Matches
eggQtess.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file eggQtess.cxx
10 * @author drose
11 * @date 2003-10-13
12 */
13
14#include "eggQtess.h"
15#include "qtessGlobals.h"
16#include "dcast.h"
17
18/**
19 *
20 */
21EggQtess::
22EggQtess() {
24
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 "
29 "egg file.\n\n"
30
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 "
34 "are unaffected.");
35
36 add_option
37 ("f", "filename", 0,
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);
41
42 add_option
43 ("up", "subdiv", 0,
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);
48
49 add_option
50 ("us", "subdiv", 0,
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 "
54 "meaningless.",
55 &EggQtess::dispatch_int, nullptr, &_uniform_per_surface);
56
57 add_option
58 ("t", "tris", 0,
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);
64
65 add_option
66 ("ap", "", 0,
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);
71
72 add_option
73 ("ad", "", 0,
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);
79
80 add_option
81 ("ar", "ratio", 0,
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 "
85 "default is 5.0.",
86 &EggQtess::dispatch_double, nullptr, &QtessGlobals::_curvature_ratio);
87
88 add_option
89 ("e", "", 0,
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);
96
97 add_option
98 ("q", "", 0,
99 "Instead of writing an egg file, generate a parameter file "
100 "for output.",
101 &EggQtess::dispatch_none, &_qtess_output);
102
103 add_option
104 ("H", "", 0,
105 "Describe the format of the parameter file specified with -f.",
106 &EggQtess::dispatch_none, &_describe_qtess);
107
108 _uniform_per_isoparam = 0.0;
109 _uniform_per_surface = 0;
110 _total_tris = 0;
111}
112
113/**
114 * Does something with the additional arguments on the command line (after all
115 * the -options have been parsed). Returns true if the arguments are good,
116 * false otherwise.
117 */
118bool EggQtess::
119handle_args(ProgramBase::Args &args) {
120 if (_describe_qtess) {
121 describe_qtess_format();
122 exit(0);
123 }
124
125 return EggFilter::handle_args(args);
126}
127
128/**
129 *
130 */
131void EggQtess::
132run() {
133 bool read_qtess = false;
134 if (!_qtess_filename.empty()) {
135 if (!_qtess_file.read(_qtess_filename)) {
136 exit(1);
137 }
138 read_qtess = true;
139 }
140
141 find_surfaces(_data);
142
143 QtessInputEntry &default_entry = _qtess_file.get_default_entry();
144 if (!read_qtess || default_entry.get_num_surfaces() == 0) {
145 nout << _surfaces.size() << " NURBS surfaces found.\n";
146
147 } else {
148 nout << _surfaces.size() << " NURBS surfaces found; "
149 << default_entry.get_num_surfaces()
150 << " unaccounted for by input file.\n";
151 }
152
153 int num_tris = _qtess_file.count_tris();
154
155 if (_total_tris != 0) {
156 // Whatever number of triangles we have unaccounted for, assign to the
157 // default bucket.
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";
161 }
162
163 default_entry.set_num_tris(extra_tris);
164
165 } else if (_uniform_per_isoparam!=0.0) {
166 default_entry.set_per_isoparam(_uniform_per_isoparam);
167
168 } else if (_uniform_per_surface!=0.0) {
169 default_entry.set_uv(_uniform_per_surface, _uniform_per_surface);
170
171 } else {
172 default_entry.set_per_isoparam(1.0);
173 }
174
175 default_entry.count_tris();
176
177 if (_qtess_output) {
178 // Sort the names into alphabetical order for aesthetics.
179 // sort(_surfaces.begin(), _surfaces.end(), compare_surfaces());
180
181 int tris = 0;
182
183 std::ostream &out = get_output();
184 Surfaces::const_iterator si;
185 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
186 tris += (*si)->write_qtess_parameter(out);
187 }
188
189 std::cerr << tris << " tris generated.\n";
190
191 } else {
192
193 int tris = 0;
194
195 Surfaces::const_iterator si;
196 for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
197 tris += (*si)->tesselate();
198 }
199
200 std::cerr << tris << " tris generated.\n";
201
202 // Clear out the surfaces list before removing the vertices, since each
203 // surface is holding reference counts to the previously-used vertices.
204 _surfaces.clear();
205
206 _data->remove_unused_vertices(true);
208 }
209}
210
211/**
212 *
213 */
214void EggQtess::
215describe_qtess_format() {
216 nout <<
217 "An egg-qtess parameter file consists of lines of the form:\n\n"
218
219 "name [name...] : parameters\n\n"
220
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"
227
228
229 "The parameters may be any of the following. Lowercase letters are "
230 "literal. NUM is any number.\n\n";
231
232 show_text(" omit", 10,
233 "Remove the surface from the output.\n\n");
234
235 show_text(" NUM", 10,
236 "Try to achieve the indicated number of triangles over all the "
237 "surfaces matched by this line.\n\n");
238
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");
243
244 show_text(" iNUM", 10,
245 "Subdivision amount per isoparam. Equivalent to the command-line "
246 "option -u NUM.\n\n");
247
248 show_text(" NUM%", 10,
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 "
256 "share.\n\n");
257
258 show_text(" matchvu", 10,
259 "This is a special parameter that indicates that two or more "
260 "surfaces share a common edge, and must be tesselated the "
261 "same way "
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");
266
267 show_text(" minu NUM", 10,
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");
274
275 show_text(" minv NUM", 10,
276 "Similar to minv, in the V direction.\n\n");
277
278 nout <<
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";
282
283 show_text(" ap", 10,
284 "Automatically place tesselation lines on each surface where they "
285 "seem to be needed most.\n\n");
286
287 show_text(" !ap", 10,
288 "Do not move lines automatically; use a strict uniform "
289 "tesselation.\n\n");
290
291 show_text(" ad", 10,
292 "Automatically distribute polygons to the surfaces that seem to "
293 "need them the most.\n\n");
294
295 show_text(" !ad", 10,
296 "Do not automatically distribute polygons; distribute "
297 "them according to the number of isoparams of each surface.\n\n");
298
299 show_text(" arNUM", 10,
300 "Specify the ratio of dominance of size to curvature.\n\n");
301
302 nout <<
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";
306}
307
308/**
309 * Recursively walks the egg graph, collecting all the NURBS surfaces found.
310 */
311void EggQtess::
312find_surfaces(EggNode *egg_node) {
313 if (egg_node->is_of_type(EggNurbsSurface::get_class_type())) {
314 PT(QtessSurface) surface =
315 new QtessSurface(DCAST(EggNurbsSurface, egg_node));
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);
320 }
321 }
322
323 if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
324 EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
325 EggGroupNode::const_iterator ci;
326 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
327 find_surfaces(*ci);
328 }
329 }
330}
331
332int main(int argc, char *argv[]) {
333 EggQtess prog;
334 prog.parse_command_line(argc, argv);
335 prog.run();
336 return 0;
337}
void add_normals_options()
Adds -no, -np, etc.
Definition eggBase.cxx:59
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.
Definition eggNode.h:36
A parametric NURBS surface.
A program to tesselate NURBS surfaces appearing within an egg file into polygons, using variations on...
Definition eggQtess.h:28
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.
Definition programBase.I:18
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...
QtessInputEntry & get_default_entry()
Returns a reference to the last entry on the list, which is the "default" entry that will match any s...
int count_tris()
Determines the tesselation u,v amounts of each attached surface, and stores this information in the s...
QtessInputEntry::Type match(QtessSurface *surface)
Attempts to find a match for the given surface in the user input entries.
bool read(const Filename &filename)
reads the input file.
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.
Definition typedObject.I:28
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.