Panda3D
Loading...
Searching...
No Matches
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
23using std::string;
24
25/**
26 *
27 */
28EggBase::
29EggBase() {
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 */
158convert_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 */
201void EggBase::
202append_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 */
213void EggBase::
214append_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 */
223bool EggBase::
224dispatch_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 */
234bool EggBase::
235ns_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 */
252bool EggBase::
253dispatch_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 */
289bool EggBase::
290dispatch_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 */
299bool EggBase::
300ns_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 */
336bool EggBase::
337dispatch_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 */
346bool EggBase::
347ns_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 */
379bool EggBase::
380dispatch_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}
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition dSearchPath.h:28
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
void add_normals_options()
Adds -no, -np, etc.
Definition eggBase.cxx:59
static void convert_paths(EggNode *node, PathReplace *path_replace, const DSearchPath &additional_path)
Recursively walks the egg hierarchy.
Definition eggBase.cxx:158
void add_transform_options()
Adds -TS, -TT, etc.
Definition eggBase.cxx:126
A comment that appears in an egg file within a <Comment> entry.
Definition eggComment.h:24
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
This is an egg node that contains a filename.
void set_fullpath(const Filename &fullpath)
Records the full pathname to the file, for the benefit of get_fullpath().
const Filename & get_filename() const
Returns a nonmodifiable reference to the filename.
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
Defines a texture map that may be applied to geometry.
Definition eggTexture.h:30
get_alpha_filename
Returns the separate file assigned for the alpha channel.
Definition eggTexture.h:347
set_alpha_fullpath
Records the full pathname to the file, for the benefit of get_alpha_fullpath().
Definition eggTexture.h:348
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
has_alpha_filename
Returns true if a separate file for the alpha component has been applied, false otherwise.
Definition eggTexture.h:347
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
This encapsulates the user's command-line request to replace existing, incorrect pathnames to models ...
Definition pathReplace.h:36
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 intended to be the base class for most general-purpose utility programs in the PANDATOOL tree...
Definition programBase.h:34
std::string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double string_to_double(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.