Panda3D
 All Classes Functions Variables Enumerations
eggQtess.cxx
1 // Filename: eggQtess.cxx
2 // Created by: drose (13Oct03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "eggQtess.h"
16 #include "qtessGlobals.h"
17 #include "dcast.h"
18 #include "pystub.h"
19 
20 ////////////////////////////////////////////////////////////////////
21 // Function: EggQtess::Constructor
22 // Access: Public
23 // Description:
24 ////////////////////////////////////////////////////////////////////
25 EggQtess::
26 EggQtess() {
28 
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 "
33  "egg file.\n\n"
34 
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 "
38  "are unaffected.");
39 
40  add_option
41  ("f", "filename", 0,
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);
45 
46  add_option
47  ("up", "subdiv", 0,
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);
52 
53  add_option
54  ("us", "subdiv", 0,
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 "
58  "meaningless.",
59  &EggQtess::dispatch_int, NULL, &_uniform_per_surface);
60 
61  add_option
62  ("t", "tris", 0,
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);
68 
69  add_option
70  ("ap", "", 0,
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);
75 
76  add_option
77  ("ad", "", 0,
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);
83 
84  add_option
85  ("ar", "ratio", 0,
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 "
89  "default is 5.0.",
90  &EggQtess::dispatch_double, NULL, &QtessGlobals::_curvature_ratio);
91 
92  add_option
93  ("e", "", 0,
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);
100 
101  add_option
102  ("q", "", 0,
103  "Instead of writing an egg file, generate a parameter file "
104  "for output.",
105  &EggQtess::dispatch_none, &_qtess_output);
106 
107  add_option
108  ("H", "", 0,
109  "Describe the format of the parameter file specified with -f.",
110  &EggQtess::dispatch_none, &_describe_qtess);
111 
112  _uniform_per_isoparam = 0.0;
113  _uniform_per_surface = 0;
114  _total_tris = 0;
115 }
116 
117 ////////////////////////////////////////////////////////////////////
118 // Function: EggQtess::handle_args
119 // Access: Protected, Virtual
120 // Description: Does something with the additional arguments on the
121 // command line (after all the -options have been
122 // parsed). Returns true if the arguments are good,
123 // false otherwise.
124 ////////////////////////////////////////////////////////////////////
125 bool EggQtess::
126 handle_args(ProgramBase::Args &args) {
127  if (_describe_qtess) {
128  describe_qtess_format();
129  exit(0);
130  }
131 
132  return EggFilter::handle_args(args);
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: EggQtess::run
137 // Access: Public
138 // Description:
139 ////////////////////////////////////////////////////////////////////
140 void EggQtess::
141 run() {
142  bool read_qtess = false;
143  if (!_qtess_filename.empty()) {
144  if (!_qtess_file.read(_qtess_filename)) {
145  exit(1);
146  }
147  read_qtess = true;
148  }
149 
150  find_surfaces(_data);
151 
152  QtessInputEntry &default_entry = _qtess_file.get_default_entry();
153  if (!read_qtess || default_entry.get_num_surfaces() == 0) {
154  nout << _surfaces.size() << " NURBS surfaces found.\n";
155 
156  } else {
157  nout << _surfaces.size() << " NURBS surfaces found; "
158  << default_entry.get_num_surfaces()
159  << " unaccounted for by input file.\n";
160  }
161 
162  int num_tris = _qtess_file.count_tris();
163 
164  if (_total_tris != 0) {
165  // Whatever number of triangles we have unaccounted for, assign to
166  // the default bucket.
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";
170  }
171 
172  default_entry.set_num_tris(extra_tris);
173 
174  } else if (_uniform_per_isoparam!=0.0) {
175  default_entry.set_per_isoparam(_uniform_per_isoparam);
176 
177  } else if (_uniform_per_surface!=0.0) {
178  default_entry.set_uv(_uniform_per_surface, _uniform_per_surface);
179 
180  } else {
181  default_entry.set_per_isoparam(1.0);
182  }
183 
184  default_entry.count_tris();
185 
186  if (_qtess_output) {
187  // Sort the names into alphabetical order for aesthetics.
188  //sort(_surfaces.begin(), _surfaces.end(), compare_surfaces());
189 
190  int tris = 0;
191 
192  ostream &out = get_output();
193  Surfaces::const_iterator si;
194  for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
195  tris += (*si)->write_qtess_parameter(out);
196  }
197 
198  cerr << tris << " tris generated.\n";
199 
200  } else {
201 
202  int tris = 0;
203 
204  Surfaces::const_iterator si;
205  for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
206  tris += (*si)->tesselate();
207  }
208 
209  cerr << tris << " tris generated.\n";
210 
211  // Clear out the surfaces list before removing the vertices, since
212  // each surface is holding reference counts to the previously-used
213  // vertices.
214  _surfaces.clear();
215 
216  _data->remove_unused_vertices(true);
217  write_egg_file();
218  }
219 }
220 
221 ////////////////////////////////////////////////////////////////////
222 // Function: EggQtess::describe_qtess_format
223 // Access: Private
224 // Description:
225 ////////////////////////////////////////////////////////////////////
226 void EggQtess::
227 describe_qtess_format() {
228  nout <<
229  "An egg-qtess parameter file consists of lines of the form:\n\n"
230 
231  "name [name...] : parameters\n\n"
232 
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"
239 
240 
241  "The parameters may be any of the following. Lowercase letters are "
242  "literal. NUM is any number.\n\n";
243 
244  show_text(" omit", 10,
245  "Remove the surface from the output.\n\n");
246 
247  show_text(" NUM", 10,
248  "Try to achieve the indicated number of triangles over all the "
249  "surfaces matched by this line.\n\n");
250 
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");
255 
256  show_text(" iNUM", 10,
257  "Subdivision amount per isoparam. Equivalent to the command-line "
258  "option -u NUM.\n\n");
259 
260  show_text(" NUM%", 10,
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 "
268  "share.\n\n");
269 
270  show_text(" matchvu", 10,
271  "This is a special parameter that indicates that two or more "
272  "surfaces share a common edge, and must be tesselated the "
273  "same way "
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");
278 
279  show_text(" minu NUM", 10,
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");
286 
287  show_text(" minv NUM", 10,
288  "Similar to minv, in the V direction.\n\n");
289 
290  nout <<
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";
294 
295  show_text(" ap", 10,
296  "Automatically place tesselation lines on each surface where they "
297  "seem to be needed most.\n\n");
298 
299  show_text(" !ap", 10,
300  "Do not move lines automatically; use a strict uniform "
301  "tesselation.\n\n");
302 
303  show_text(" ad", 10,
304  "Automatically distribute polygons to the surfaces that seem to "
305  "need them the most.\n\n");
306 
307  show_text(" !ad", 10,
308  "Do not automatically distribute polygons; distribute "
309  "them according to the number of isoparams of each surface.\n\n");
310 
311  show_text(" arNUM", 10,
312  "Specify the ratio of dominance of size to curvature.\n\n");
313 
314  nout <<
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";
318 }
319 
320 ////////////////////////////////////////////////////////////////////
321 // Function: EggQtess::find_surfaces
322 // Access: Private
323 // Description: Recursively walks the egg graph, collecting all the
324 // NURBS surfaces found.
325 ////////////////////////////////////////////////////////////////////
326 void EggQtess::
327 find_surfaces(EggNode *egg_node) {
328  if (egg_node->is_of_type(EggNurbsSurface::get_class_type())) {
329  PT(QtessSurface) surface =
330  new QtessSurface(DCAST(EggNurbsSurface, egg_node));
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);
335  }
336  }
337 
338  if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
339  EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
340  EggGroupNode::const_iterator ci;
341  for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
342  find_surfaces(*ci);
343  }
344  }
345 }
346 
347 int main(int argc, char *argv[]) {
348  // A call to pystub() to force libpystub.so to be linked in.
349  pystub();
350 
351  EggQtess prog;
352  prog.parse_command_line(argc, argv);
353  prog.run();
354  return 0;
355 }
356 
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
Definition: qtessSurface.h:34
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.
Definition: eggGroupNode.h:51
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.
Definition: eggBase.cxx:63
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
QtessInputEntry::Type match(QtessSurface *surface)
Attempts to find a match for the given surface in the user input entries.
int count_tris()
Determines the tesselation u,v amounts of each attached surface, and stores this information in the s...
void show_text(const string &text)
Formats the indicated text to stderr with the known _terminal_width.
Definition: programBase.I:23
QtessInputEntry & get_default_entry()
Returns a reference to the last entry on the list, which is the &quot;default&quot; entry that will match any s...
Stores one entry in the qtess input file.
void write_egg_file()
Writes out the egg file as the normal result of the program.
Definition: eggWriter.cxx:193
ostream & get_output()
Returns an output stream that corresponds to the user&#39;s intended egg file output–either stdout...
bool read(const Filename &filename)
reads the input file.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
A parametric NURBS surface.
A program to tesselate NURBS surfaces appearing within an egg file into polygons, using variations on...
Definition: eggQtess.h:31