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  */
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  */
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  */
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  */
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 }
EggFilenameNode
This is an egg node that contains a filename.
Definition: eggFilenameNode.h:27
EggComment
A comment that appears in an egg file within a <Comment> entry.
Definition: eggComment.h:24
EggTexture::get_alpha_filename
get_alpha_filename
Returns the separate file assigned for the alpha channel.
Definition: eggTexture.h:347
EggBase::add_normals_options
void add_normals_options()
Adds -no, -np, etc.
Definition: eggBase.cxx:59
tokenize
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.
Definition: string_utils.cxx:170
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcast.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggGroupNode
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
eggTexture.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggFilenameNode::get_filename
const Filename & get_filename() const
Returns a nonmodifiable reference to the filename.
Definition: eggFilenameNode.I:58
ProgramBase
This is intended to be the base class for most general-purpose utility programs in the PANDATOOL tree...
Definition: programBase.h:34
EggFilenameNode::set_fullpath
void set_fullpath(const Filename &fullpath)
Records the full pathname to the file, for the benefit of get_fullpath().
Definition: eggFilenameNode.I:90
PathReplace::full_convert_path
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.
Definition: pathReplace.cxx:198
EggBase::convert_paths
static void convert_paths(EggNode *node, PathReplace *path_replace, const DSearchPath &additional_path)
Recursively walks the egg hierarchy.
Definition: eggBase.cxx:158
EggTexture::set_alpha_filename
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:347
ProgramBase::get_exec_command
std::string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
Definition: programBase.cxx:455
EggData
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
DSearchPath
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition: dSearchPath.h:28
EggBase::add_transform_options
void add_transform_options()
Adds -TS, -TT, etc.
Definition: eggBase.cxx:126
eggFilenameNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggComment.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PathReplace
This encapsulates the user's command-line request to replace existing, incorrect pathnames to models ...
Definition: pathReplace.h:36
EggTexture::has_alpha_filename
has_alpha_filename
Returns true if a separate file for the alpha component has been applied, false otherwise.
Definition: eggTexture.h:347
string_to_double
double string_to_double(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
Definition: string_utils.cxx:354
eggGroupNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggBase
This is a base class for both EggSingleBase and EggMultiBase.
Definition: eggBase.h:29
EggTexture
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
EggTexture::set_alpha_fullpath
set_alpha_fullpath
Records the full pathname to the file, for the benefit of get_alpha_fullpath().
Definition: eggTexture.h:348
EggNode
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
EggBase::add_points_options
void add_points_options()
Adds -points as a valid option for this program.
Definition: eggBase.cxx:113