Panda3D
eggBase.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 eggBase.cxx
10  * @author drose
11  * @date 2000-02-14
12  */
13 
14 #include "eggBase.h"
15 
16 #include "eggGroupNode.h"
17 #include "eggTexture.h"
18 #include "eggFilenameNode.h"
19 #include "eggComment.h"
20 #include "dcast.h"
21 #include "string_utils.h"
22 
23 using std::string;
24 
25 /**
26  *
27  */
28 EggBase::
29 EggBase() {
30  add_option
31  ("cs", "coordinate-system", 80,
32  "Specify the coordinate system to operate in. This may be one of "
33  "'y-up', 'z-up', 'y-up-left', or 'z-up-left'.",
34  &EggBase::dispatch_coordinate_system,
35  &_got_coordinate_system, &_coordinate_system);
36 
37  _normals_mode = NM_preserve;
38  _normals_threshold = 0.0;
39 
40  _got_tbnall = false;
41  _got_tbnauto = false;
42  _make_points = false;
43 
44  _got_transform = false;
45  _transform = LMatrix4d::ident_mat();
46 
47  _got_coordinate_system = false;
48  _coordinate_system = CS_yup_right;
49 
50  _noabs = false;
51 }
52 
53 /**
54  * Adds -no, -np, etc. as valid options for this program. If the user
55  * specifies one of the options on the command line, the normals will be
56  * adjusted when the egg file is written out.
57  */
58 void EggBase::
60  static NormalsMode strip = NM_strip;
61  static NormalsMode polygon = NM_polygon;
62  static NormalsMode vertex = NM_vertex;
63  static NormalsMode preserve = NM_preserve;
64 
65  add_option
66  ("no", "", 48,
67  "Strip all normals.",
68  &EggBase::dispatch_normals, nullptr, &strip);
69 
70  add_option
71  ("np", "", 48,
72  "Strip existing normals and redefine polygon normals.",
73  &EggBase::dispatch_normals, nullptr, &polygon);
74 
75  add_option
76  ("nv", "threshold", 48,
77  "Strip existing normals and redefine vertex normals. Consider an edge "
78  "between adjacent polygons to be smooth if the angle between them "
79  "is less than threshold degrees.",
80  &EggBase::dispatch_normals, nullptr, &vertex);
81 
82  add_option
83  ("nn", "", 48,
84  "Preserve normals exactly as they are. This is the default.",
85  &EggBase::dispatch_normals, nullptr, &preserve);
86 
87  add_option
88  ("tbn", "name", 48,
89  "Compute tangent and binormal for the named texture coordinate "
90  "set(s). The name may include wildcard characters such as * and ?. "
91  "The normal must already exist or have been computed via one of the "
92  "above options. The tangent and binormal are used to implement "
93  "bump mapping and related texture-based lighting effects. This option "
94  "may be repeated as necessary to name multiple texture coordinate sets.",
95  &EggBase::dispatch_vector_string, nullptr, &_tbn_names);
96 
97  add_option
98  ("tbnall", "", 48,
99  "Compute tangent and binormal for all texture coordinate "
100  "sets. This is equivalent to -tbn \"*\".",
101  &EggBase::dispatch_none, &_got_tbnall);
102 
103  add_option
104  ("tbnauto", "", 48,
105  "Compute tangent and binormal for all normal maps. ",
106  &EggBase::dispatch_none, &_got_tbnauto);
107 }
108 
109 /**
110  * Adds -points as a valid option for this program.
111  */
112 void EggBase::
114  add_option
115  ("points", "", 46,
116  "Construct <PointLight> entries for any unreferenced vertices, to make them visible.",
117  &EggBase::dispatch_none, &_make_points);
118 }
119 
120 /**
121  * Adds -TS, -TT, etc. as valid options for this program. If the user
122  * specifies one of the options on the command line, the data will be
123  * transformed when the egg file is written out.
124  */
125 void EggBase::
127  add_option
128  ("TS", "sx[,sy,sz]", 49,
129  "Scale the model uniformly by the given factor (if only one number "
130  "is given) or in each axis by sx, sy, sz (if three numbers are given).",
131  &EggBase::dispatch_scale, &_got_transform, &_transform);
132 
133  add_option
134  ("TR", "x,y,z", 49,
135  "Rotate the model x degrees about the x axis, then y degrees about the "
136  "y axis, and then z degrees about the z axis.",
137  &EggBase::dispatch_rotate_xyz, &_got_transform, &_transform);
138 
139  add_option
140  ("TA", "angle,x,y,z", 49,
141  "Rotate the model angle degrees counterclockwise about the given "
142  "axis.",
143  &EggBase::dispatch_rotate_axis, &_got_transform, &_transform);
144 
145  add_option
146  ("TT", "x,y,z", 49,
147  "Translate the model by the indicated amount.\n\n"
148  "All transformation options (-TS, -TR, -TA, -TT) are cumulative and are "
149  "applied in the order they are encountered on the command line.",
150  &EggBase::dispatch_translate, &_got_transform, &_transform);
151 }
152 
153 /**
154  * Recursively walks the egg hierarchy. Any filenames encountered are
155  * replaced according to the indicated PathReplace.
156  */
157 void EggBase::
158 convert_paths(EggNode *node, PathReplace *path_replace,
159  const DSearchPath &additional_path) {
160  if (node->is_of_type(EggTexture::get_class_type())) {
161  EggTexture *egg_tex = DCAST(EggTexture, node);
162  Filename fullpath, outpath;
163  path_replace->full_convert_path(egg_tex->get_filename(), additional_path,
164  fullpath, outpath);
165  egg_tex->set_filename(outpath);
166  egg_tex->set_fullpath(fullpath);
167 
168  if (egg_tex->has_alpha_filename()) {
169  Filename alpha_fullpath, alpha_outpath;
170  path_replace->full_convert_path(egg_tex->get_alpha_filename(), additional_path,
171  alpha_fullpath, alpha_outpath);
172  egg_tex->set_alpha_filename(alpha_outpath);
173  egg_tex->set_alpha_fullpath(alpha_fullpath);
174  }
175 
176  } else if (node->is_of_type(EggFilenameNode::get_class_type())) {
177  EggFilenameNode *egg_fnode = DCAST(EggFilenameNode, node);
178 
179  Filename fullpath, outpath;
180  path_replace->full_convert_path(egg_fnode->get_filename(), additional_path,
181  fullpath, outpath);
182  egg_fnode->set_filename(outpath);
183  egg_fnode->set_fullpath(fullpath);
184 
185  } else if (node->is_of_type(EggGroupNode::get_class_type())) {
186  EggGroupNode *egg_group = DCAST(EggGroupNode, node);
187  EggGroupNode::const_iterator ci;
188  for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
189  convert_paths(*ci, path_replace, additional_path);
190  }
191  }
192 }
193 
194 /**
195  * Inserts a comment into the beginning of the indicated egg file
196  * corresponding to the command line that invoked this program.
197  *
198  * Normally this function is called automatically when appropriate by
199  * EggWriter, and it's not necessary to call it explicitly.
200  */
201 void EggBase::
202 append_command_comment(EggData *data) {
203  append_command_comment(data, get_exec_command());
204 }
205 
206 /**
207  * Inserts a comment into the beginning of the indicated egg file
208  * corresponding to the command line that invoked this program.
209  *
210  * Normally this function is called automatically when appropriate by
211  * EggWriter, and it's not necessary to call it explicitly.
212  */
213 void EggBase::
214 append_command_comment(EggData *data, const string &comment) {
215  data->insert(data->begin(), new EggComment("", comment));
216 }
217 
218 /**
219  * Accepts one of -no, -np, etc. and sets _normals_mode as indicated. The
220  * void * argument is a pointer to a NormalsMode variable that indicates which
221  * switch was passed.
222  */
223 bool EggBase::
224 dispatch_normals(ProgramBase *self, const string &opt, const string &arg, void *mode) {
225  EggBase *base = (EggBase *)self;
226  return base->ns_dispatch_normals(opt, arg, mode);
227 }
228 
229 /**
230  * Accepts one of -no, -np, etc. and sets _normals_mode as indicated. The
231  * void * argument is a pointer to a NormalsMode variable that indicates which
232  * switch was passed.
233  */
234 bool EggBase::
235 ns_dispatch_normals(const string &opt, const string &arg, void *mode) {
236  _normals_mode = *(NormalsMode *)mode;
237 
238  if (_normals_mode == NM_vertex) {
239  if (!string_to_double(arg, _normals_threshold)) {
240  nout << "Invalid numeric parameter for -" << opt << ": "
241  << arg << "\n";
242  return false;
243  }
244  }
245 
246  return true;
247 }
248 
249 /**
250  * Handles -TS, which specifies a scale transform. Var is an LMatrix4d.
251  */
252 bool EggBase::
253 dispatch_scale(const string &opt, const string &arg, void *var) {
254  LMatrix4d *transform = (LMatrix4d *)var;
255 
256  vector_string words;
257  tokenize(arg, words, ",");
258 
259  double sx, sy, sz;
260 
261  bool okflag = false;
262  if (words.size() == 3) {
263  okflag =
264  string_to_double(words[0], sx) &&
265  string_to_double(words[1], sy) &&
266  string_to_double(words[2], sz);
267 
268  } else if (words.size() == 1) {
269  okflag =
270  string_to_double(words[0], sx);
271  sy = sz = sx;
272  }
273 
274  if (!okflag) {
275  nout << "-" << opt
276  << " requires one or three numbers separated by commas.\n";
277  return false;
278  }
279 
280  *transform = (*transform) * LMatrix4d::scale_mat(sx, sy, sz);
281 
282  return true;
283 }
284 
285 /**
286  * Handles -TR, which specifies a rotate transform about the three cardinal
287  * axes. Var is an LMatrix4d.
288  */
289 bool EggBase::
290 dispatch_rotate_xyz(ProgramBase *self, const string &opt, const string &arg, void *var) {
291  EggBase *base = (EggBase *)self;
292  return base->ns_dispatch_rotate_xyz(opt, arg, var);
293 }
294 
295 /**
296  * Handles -TR, which specifies a rotate transform about the three cardinal
297  * axes. Var is an LMatrix4d.
298  */
299 bool EggBase::
300 ns_dispatch_rotate_xyz(const string &opt, const string &arg, void *var) {
301  LMatrix4d *transform = (LMatrix4d *)var;
302 
303  vector_string words;
304  tokenize(arg, words, ",");
305 
306  LVecBase3d xyz;
307 
308  bool okflag = false;
309  if (words.size() == 3) {
310  okflag =
311  string_to_double(words[0], xyz[0]) &&
312  string_to_double(words[1], xyz[1]) &&
313  string_to_double(words[2], xyz[2]);
314  }
315 
316  if (!okflag) {
317  nout << "-" << opt
318  << " requires three numbers separated by commas.\n";
319  return false;
320  }
321 
322  LMatrix4d mat =
323  LMatrix4d::rotate_mat(xyz[0], LVector3d(1.0, 0.0, 0.0), _coordinate_system) *
324  LMatrix4d::rotate_mat(xyz[1], LVector3d(0.0, 1.0, 0.0), _coordinate_system) *
325  LMatrix4d::rotate_mat(xyz[2], LVector3d(0.0, 0.0, 1.0), _coordinate_system);
326 
327  *transform = (*transform) * mat;
328 
329  return true;
330 }
331 
332 /**
333  * Handles -TA, which specifies a rotate transform about an arbitrary axis.
334  * Var is an LMatrix4d.
335  */
336 bool EggBase::
337 dispatch_rotate_axis(ProgramBase *self, const string &opt, const string &arg, void *var) {
338  EggBase *base = (EggBase *)self;
339  return base->ns_dispatch_rotate_axis(opt, arg, var);
340 }
341 
342 /**
343  * Handles -TA, which specifies a rotate transform about an arbitrary axis.
344  * Var is an LMatrix4d.
345  */
346 bool EggBase::
347 ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var) {
348  LMatrix4d *transform = (LMatrix4d *)var;
349 
350  vector_string words;
351  tokenize(arg, words, ",");
352 
353  double angle;
354  LVecBase3d axis;
355 
356  bool okflag = false;
357  if (words.size() == 4) {
358  okflag =
359  string_to_double(words[0], angle) &&
360  string_to_double(words[1], axis[0]) &&
361  string_to_double(words[2], axis[1]) &&
362  string_to_double(words[3], axis[2]);
363  }
364 
365  if (!okflag) {
366  nout << "-" << opt
367  << " requires four numbers separated by commas.\n";
368  return false;
369  }
370 
371  *transform = (*transform) * LMatrix4d::rotate_mat(angle, axis, _coordinate_system);
372 
373  return true;
374 }
375 
376 /**
377  * Handles -TT, which specifies a translate transform. Var is an LMatrix4d.
378  */
379 bool EggBase::
380 dispatch_translate(const string &opt, const string &arg, void *var) {
381  LMatrix4d *transform = (LMatrix4d *)var;
382 
383  vector_string words;
384  tokenize(arg, words, ",");
385 
386  LVector3d trans;
387 
388  bool okflag = false;
389  if (words.size() == 3) {
390  okflag =
391  string_to_double(words[0], trans[0]) &&
392  string_to_double(words[1], trans[1]) &&
393  string_to_double(words[2], trans[2]);
394  }
395 
396  if (!okflag) {
397  nout << "-" << opt
398  << " requires three numbers separated by commas.\n";
399  return false;
400  }
401 
402  *transform = (*transform) * LMatrix4d::translate_mat(trans);
403 
404  return true;
405 }
void set_fullpath(const Filename &fullpath)
Records the full pathname to the file, for the benefit of get_fullpath().
This is intended to be the base class for most general-purpose utility programs in the PANDATOOL tree...
Definition: programBase.h:34
const Filename & get_filename() const
Returns a nonmodifiable reference to the filename.
double string_to_double(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
This is an egg node that contains a filename.
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
A comment that appears in an egg file within a <Comment> entry.
Definition: eggComment.h:24
has_alpha_filename
Returns true if a separate file for the alpha component has been applied, false otherwise.
Definition: eggTexture.h:343
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
set_alpha_fullpath
Records the full pathname to the file, for the benefit of get_alpha_fullpath().
Definition: eggTexture.h:344
void add_normals_options()
Adds -no, -np, etc.
Definition: eggBase.cxx:59
void full_convert_path(const Filename &orig_filename, const DSearchPath &additional_path, Filename &resolved_path, Filename &output_path)
Converts the input path into two different forms: A resolved path, and an output path.
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void convert_paths(EggNode *node, PathReplace *path_replace, const DSearchPath &additional_path)
Recursively walks the egg hierarchy.
Definition: eggBase.cxx:158
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
std::string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
void tokenize(const string &str, vector_string &words, const string &delimiters, bool discard_repeated_delimiters)
Chops the source string up into pieces delimited by any of the characters specified in delimiters.
get_alpha_filename
Returns the separate file assigned for the alpha channel.
Definition: eggTexture.h:343
This encapsulates the user's command-line request to replace existing, incorrect pathnames to models ...
Definition: pathReplace.h:36
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
set_alpha_filename
Specifies a separate file that will be loaded in with the 1- or 3-component texture and applied as th...
Definition: eggTexture.h:343
void add_transform_options()
Adds -TS, -TT, etc.
Definition: eggBase.cxx:126
This is a base class for both EggSingleBase and EggMultiBase.
Definition: eggBase.h:29
void add_points_options()
Adds -points as a valid option for this program.
Definition: eggBase.cxx:113
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition: dSearchPath.h:28
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.