Panda3D
Loading...
Searching...
No Matches
eggReader.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 eggReader.cxx
10 * @author drose
11 * @date 2000-02-14
12 */
13
14#include "eggReader.h"
15
16#include "pnmImage.h"
17#include "config_putil.h"
19#include "eggGroup.h"
20#include "eggGroupNode.h"
21#include "eggSwitchCondition.h"
22#include "string_utils.h"
23#include "dcast.h"
24
25/**
26 *
27 */
28EggReader::
29EggReader() {
30 clear_runlines();
31 add_runline("[opts] input.egg");
32
33 redescribe_option
34 ("cs",
35 "Specify the coordinate system to operate in. This may be "
36 " one of 'y-up', 'z-up', 'y-up-left', or 'z-up-left'. The default "
37 "is the coordinate system of the input egg file.");
38
39 add_option
40 ("f", "", 80,
41 "Force complete loading: load up the egg file along with all of its "
42 "external references.",
43 &EggReader::dispatch_none, &_force_complete);
44
45 add_option
46 ("noabs", "", 0,
47 "Don't allow the input egg file to have absolute pathnames. "
48 "If it does, abort with an error. This option is designed to help "
49 "detect errors when populating or building a standalone model tree, "
50 "which should be self-contained and include only relative pathnames.",
51 &EggReader::dispatch_none, &_noabs);
52
53 _tex_type = nullptr;
54 _delod = -1.0;
55
56 _got_tex_dirname = false;
57 _got_tex_extension = false;
58}
59
60/**
61 * Adds -td, -te, etc. as valid options for this program. If the user
62 * specifies one of the options on the command line, the textures will be
63 * copied and converted as each egg file is read.
64 *
65 * Note that if you call this function to add these options, you must call
66 * do_reader_options() at the appropriate point before or during processing to
67 * execute the options if the user specified them.
68 */
71 add_option
72 ("td", "dirname", 40,
73 "Copy textures to the indicated directory. The copy is performed "
74 "only if the destination file does not exist or is older than the "
75 "source file.",
76 &EggReader::dispatch_filename, &_got_tex_dirname, &_tex_dirname);
77
78 add_option
79 ("te", "ext", 40,
80 "Rename textures to have the indicated extension. This also "
81 "automatically copies them to the new filename (possibly in a "
82 "different directory if -td is also specified), and may implicitly "
83 "convert to a different image format according to the extension.",
84 &EggReader::dispatch_string, &_got_tex_extension, &_tex_extension);
85
86 add_option
87 ("tt", "type", 40,
88 "Explicitly specifies the image format to convert textures to "
89 "when copying them via -td or -te. Normally, this is unnecessary as "
90 "the image format can be determined by the extension, but sometimes "
91 "the extension is insufficient to unambiguously specify an image "
92 "type.",
93 &EggReader::dispatch_image_type, nullptr, &_tex_type);
94}
95
96/**
97 * Adds -delod as a valid option for this program.
98 *
99 * Note that if you call this function to add these options, you must call
100 * do_reader_options() at the appropriate point before or during processing to
101 * execute the options if the user specified them.
102 */
104add_delod_options(double default_delod) {
105 _delod = default_delod;
106
107 if (default_delod < 0) {
108 add_option
109 ("delod", "dist", 40,
110 "Eliminate LOD's by choosing the level that would be appropriate for "
111 "a camera at the indicated fixed distance from each LOD. "
112 "Use -delod -1 to keep all the LOD's as they are, which is "
113 "the default.\n",
114 &EggReader::dispatch_double, nullptr, &_delod);
115
116 } else {
117 add_option
118 ("delod", "dist", 40,
119 "Eliminate LOD's by choosing the level that would be appropriate for "
120 "a camera at the indicated fixed distance from each LOD. "
121 "Use -delod -1 to keep all the LOD's as they are. The default value "
122 "is " + format_string(default_delod) + ".",
123 &EggReader::dispatch_double, nullptr, &_delod);
124 }
125}
126
127/**
128 * Returns this object as an EggReader pointer, if it is in fact an EggReader,
129 * or NULL if it is not.
130 *
131 * This is intended to work around the C++ limitation that prevents downcasts
132 * past virtual inheritance. Since both EggReader and EggWriter inherit
133 * virtually from EggSingleBase, we need functions like this to downcast to
134 * the appropriate pointer.
135 */
137as_reader() {
138 return this;
139}
140
141/**
142 * Performs any processing of the egg file that is appropriate after reading
143 * it in.
144 *
145 * Normally, you should not need to call this function directly; it is called
146 * automatically at startup.
147 */
151
152/**
153 *
154 */
155bool EggReader::
156handle_args(ProgramBase::Args &args) {
157 if (args.empty()) {
158 nout << "You must specify the egg file(s) to read on the command line.\n";
159 return false;
160 }
161
162 // Any separate egg files that are listed on the command line will get
163 // implicitly loaded up into one big egg file.
164
165 if (!args.empty()) {
166 _data->set_egg_filename(Filename::from_os_specific(args[0]));
167 }
168 Args::const_iterator ai;
169 for (ai = args.begin(); ai != args.end(); ++ai) {
170 Filename filename = Filename::from_os_specific(*ai);
171
172 EggData file_data;
173 if (filename != "-") {
174 if (!file_data.read(filename)) {
175 // Rather than returning false, we simply exit here, so the ProgramBase
176 // won't try to tell the user how to run the program just because we got
177 // a bad egg file.
178 exit(1);
179 }
180 } else {
181 if (!file_data.read(std::cin)) {
182 exit(1);
183 }
184 }
185
186 if (_noabs && file_data.original_had_absolute_pathnames()) {
187 nout << filename.get_basename()
188 << " includes absolute pathnames!\n";
189 exit(1);
190 }
191
192 DSearchPath file_path;
193 file_path.append_directory(filename.get_dirname());
194
195 if (_force_complete) {
196 if (!file_data.load_externals(file_path)) {
197 exit(1);
198 }
199 }
200
201 // Now resolve the filenames again according to the user's specified
202 // _path_replace.
203 convert_paths(&file_data, _path_replace, file_path);
204
205 _data->merge(file_data);
206 }
207
209
210 return true;
211}
212
213/**
214 * This is called after the command line has been completely processed, and it
215 * gives the program a chance to do some last-minute processing and validation
216 * of the options and arguments. It should return true if everything is fine,
217 * false if there is an error.
218 */
219bool EggReader::
220post_command_line() {
221 return EggSingleBase::post_command_line();
222}
223
224/**
225 * Postprocesses the egg file as the user requested according to whatever
226 * command-line options are in effect. Returns true if everything is done
227 * correctly, false if there was some problem.
228 */
229bool EggReader::
230do_reader_options() {
231 bool okflag = true;
232
233 if (_got_tex_dirname || _got_tex_extension) {
234 if (!copy_textures()) {
235 okflag = false;
236 }
237 }
238
239 if (_delod >= 0.0) {
240 do_delod(_data);
241 }
242
243 return okflag;
244}
245
246/**
247 * Renames and copies the textures referenced in the egg file, if so specified
248 * by the -td and -te options. Returns true if all textures are copied
249 * successfully, false if any one of them failed.
250 */
251bool EggReader::
252copy_textures() {
253 bool success = true;
254 EggTextureCollection textures;
255 textures.find_used_textures(_data);
256
257 EggTextureCollection::const_iterator ti;
258 for (ti = textures.begin(); ti != textures.end(); ++ti) {
259 EggTexture *tex = (*ti);
260 Filename orig_filename = tex->get_filename();
261 if (!orig_filename.exists()) {
262 bool found = orig_filename.resolve_filename(get_model_path());
263 if (!found) {
264 nout << "Cannot find " << orig_filename << "\n";
265 success = false;
266 continue;
267 }
268 }
269
270 Filename new_filename = orig_filename;
271 if (_got_tex_dirname) {
272 new_filename.set_dirname(_tex_dirname);
273 }
274 if (_got_tex_extension) {
275 new_filename.set_extension(_tex_extension);
276 }
277
278 if (orig_filename != new_filename) {
279 tex->set_filename(new_filename);
280
281 // The new filename is different; does it need copying?
282 int compare =
283 orig_filename.compare_timestamps(new_filename, true, true);
284 if (compare > 0) {
285 // Yes, it does. Copy it!
286 nout << "Reading " << orig_filename << "\n";
287 PNMImage image;
288 if (!image.read(orig_filename)) {
289 nout << " unable to read!\n";
290 success = false;
291 } else {
292 nout << "Writing " << new_filename << "\n";
293 if (!image.write(new_filename, _tex_type)) {
294 nout << " unable to write!\n";
295 success = false;
296 }
297 }
298 }
299 }
300 }
301
302 return success;
303}
304
305/**
306 * Removes all the LOD's in the egg file by treating the camera as being
307 * _delod distance from each LOD. Returns true if this particular group should
308 * be preserved, false if it should be removed.
309 */
310bool EggReader::
311do_delod(EggNode *node) {
312 if (node->is_of_type(EggGroup::get_class_type())) {
313 EggGroup *group = DCAST(EggGroup, node);
314 if (group->has_lod()) {
315 const EggSwitchCondition &cond = group->get_lod();
316 if (cond.is_of_type(EggSwitchConditionDistance::get_class_type())) {
317 const EggSwitchConditionDistance *dist =
318 DCAST(EggSwitchConditionDistance, &cond);
319 if (_delod >= dist->_switch_out && _delod < dist->_switch_in) {
320 // Preserve this group node, but not the LOD information itself.
321 nout << "Preserving LOD " << node->get_name()
322 << " (" << dist->_switch_out << " to " << dist->_switch_in
323 << ")\n";
324 group->clear_lod();
325 } else {
326 // Remove this group node.
327 nout << "Eliminating LOD " << node->get_name()
328 << " (" << dist->_switch_out << " to " << dist->_switch_in
329 << ")\n";
330 return false;
331 }
332 }
333 }
334 }
335
336 // Now process all the children.
337 if (node->is_of_type(EggGroupNode::get_class_type())) {
338 EggGroupNode *group = DCAST(EggGroupNode, node);
339 EggGroupNode::iterator ci;
340 ci = group->begin();
341 while (ci != group->end()) {
342 EggNode *child = *ci;
343 ++ci;
344
345 if (!do_delod(child)) {
346 group->remove_child(child);
347 }
348 }
349 }
350
351 return true;
352}
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition dSearchPath.h:28
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
static void convert_paths(EggNode *node, PathReplace *path_replace, const DSearchPath &additional_path)
Recursively walks the egg hierarchy.
Definition eggBase.cxx:158
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
bool original_had_absolute_pathnames() const
Returns true if the data processed in the last call to read() contained absolute pathnames,...
Definition eggData.I:82
bool load_externals(const DSearchPath &searchpath=DSearchPath())
Loads up all the egg files referenced by <File> entries within the egg structure, and inserts their c...
Definition eggData.cxx:162
bool read(Filename filename, std::string display_name=std::string())
Opens the indicated filename and reads the egg data contents from it.
Definition eggData.cxx:65
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.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition eggGroup.h:34
A base class for things that may be directly added into the egg hierarchy.
Definition eggNode.h:36
This is the base class for a program that reads egg files, but doesn't write an egg file.
Definition eggReader.h:28
virtual void pre_process_egg_file()
Performs any processing of the egg file that is appropriate after reading it in.
void add_texture_options()
Adds -td, -te, etc.
Definition eggReader.cxx:70
virtual EggReader * as_reader()
Returns this object as an EggReader pointer, if it is in fact an EggReader, or NULL if it is not.
void add_delod_options(double default_delod=-1.0)
Adds -delod as a valid option for this program.
A SwitchCondition that switches the levels-of-detail based on distance from the camera's eyepoint.
This corresponds to a <SwitchCondition> entry within a group.
This is a collection of textures by TRef name.
int find_used_textures(EggNode *node)
Walks the egg hierarchy beginning at the indicated node, looking for textures that are referenced by ...
Defines a texture map that may be applied to geometry.
Definition eggTexture.h:30
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
int compare_timestamps(const Filename &other, bool this_missing_is_old=true, bool other_missing_is_old=true) const
Returns a number less than zero if the file named by this object is older than the given file,...
std::string get_basename() const
Returns the basename part of the filename.
Definition filename.I:367
bool resolve_filename(const DSearchPath &searchpath, const std::string &default_extension=std::string())
Searches the given search path for the filename.
void set_dirname(const std::string &s)
Replaces the directory part of the filename.
Definition filename.cxx:704
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
Definition filename.cxx:328
void set_extension(const std::string &s)
Replaces the file extension.
Definition filename.cxx:804
std::string get_dirname() const
Returns the directory part of the filename.
Definition filename.I:358
bool exists() const
Returns true if the filename exists on the physical disk, false otherwise.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition pnmImage.h:58
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
Definition pnmImage.cxx:278
bool write(const Filename &filename, PNMFileType *type=nullptr) const
Writes the image to the indicated filename.
Definition pnmImage.cxx:385
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.