Panda3D
Loading...
Searching...
No Matches
eggData.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 eggData.cxx
10 * @author drose
11 * @date 1999-01-20
12 */
13
14#include "eggData.h"
15#include "eggCoordinateSystem.h"
18#include "eggComment.h"
19#include "eggPoolUniquifier.h"
20#include "config_egg.h"
21#include "config_putil.h"
22#include "config_express.h"
23#include "string_utils.h"
24#include "dSearchPath.h"
25#include "virtualFileSystem.h"
26#include "lightMutexHolder.h"
27#include "zStream.h"
28
29using std::istream;
30using std::ostream;
31
32extern int eggyyparse();
33#include "parserDefs.h"
34#include "lexerDefs.h"
35
36TypeHandle EggData::_type_handle;
37
38/**
39 * Looks for the indicated filename, first along the indicated searchpath, and
40 * then along the model_path. If found, updates the filename to the full path
41 * and returns true; otherwise, returns false.
42 */
44resolve_egg_filename(Filename &egg_filename, const DSearchPath &searchpath) {
46
47 if (egg_filename.is_fully_qualified() && vfs->exists(egg_filename)) {
48 return true;
49 }
50
51 vfs->resolve_filename(egg_filename, searchpath, "egg") ||
52 vfs->resolve_filename(egg_filename, get_model_path(), "egg");
53
54 return vfs->exists(egg_filename);
55}
56
57/**
58 * Opens the indicated filename and reads the egg data contents from it.
59 * Returns true if the file was successfully opened and read, false if there
60 * were some errors, in which case the data may be partially read.
61 *
62 * error is the output stream to which to write error messages.
63 */
65read(Filename filename, std::string display_name) {
66 filename.set_text();
67 set_egg_filename(filename);
68
69 if (display_name.empty()) {
70 display_name = filename;
71 }
72
74
75 PT(VirtualFile) vfile = vfs->get_file(filename);
76 if (vfile == nullptr) {
77 egg_cat.error() << "Could not find " << display_name << "\n";
78 return false;
79 }
80 set_egg_timestamp(vfile->get_timestamp());
81
82 istream *file = vfile->open_read_file(true);
83 if (file == nullptr) {
84 egg_cat.error() << "Unable to open " << display_name << "\n";
85 return false;
86 }
87
88 egg_cat.info()
89 << "Reading " << display_name << "\n";
90
91 bool read_ok = read(*file);
92 vfile->close_read_file(file);
93 return read_ok;
94}
95
96
97/**
98 * Parses the egg syntax contained in the indicated input stream. Returns
99 * true if the stream was a completely valid egg file, false if there were
100 * some errors, in which case the data may be partially read.
101 *
102 * Before you call this routine, you should probably call set_egg_filename()
103 * to set the name of the egg file we're processing, if at all possible. If
104 * there is no such filename, you may set it to the empty string.
105 */
107read(istream &in) {
108 // First, dispense with any children we had previously. We will replace
109 // them with the new data.
110 clear();
111
112 // Create a temporary EggData structure to read into. We initialize it with
113 // a copy of ourselves, so that it will get our _coordsys value, if the user
114 // set it.
115 PT(EggData) data = new EggData(*this);
116
117 int error_count;
118 {
119 LightMutexHolder holder(egg_lock);
120 egg_init_parser(in, get_egg_filename(), data, data);
121 eggyyparse();
122 egg_cleanup_parser();
123 error_count = egg_error_count();
124 }
125
126 data->post_read();
127
128 steal_children(*data);
129 (*this) = *data;
130
131 return (error_count == 0);
132}
133
134/**
135 * Appends the other egg structure to the end of this one. The other egg
136 * structure is invalidated.
137 */
139merge(EggData &other) {
140 if (get_coordinate_system() == CS_default) {
141 // If we haven't specified a coordinate system yet, we inherit the other
142 // one's.
144
145 } else {
146 // Otherwise, the other one is forced into our coordinate system before we
147 // merge.
149 }
150 steal_children(other);
151}
152
153
154/**
155 * Loads up all the egg files referenced by <File> entries within the egg
156 * structure, and inserts their contents in place of the <File> entries.
157 * Searches for files in the searchpath, if not found directly, and writes
158 * error messages to the indicated output stream. Returns true if all
159 * externals were loaded successfully, false otherwise.
160 */
162load_externals(const DSearchPath &searchpath) {
163 return
164 r_load_externals(searchpath, get_coordinate_system(), nullptr);
165}
166
167/**
168 * Loads up all the egg files referenced by <File> entries within the egg
169 * structure, and inserts their contents in place of the <File> entries.
170 * Searches for files in the searchpath, if not found directly, and writes
171 * error messages to the indicated output stream. Returns true if all
172 * externals were loaded successfully, false otherwise.
173 */
175load_externals(const DSearchPath &searchpath, BamCacheRecord *record) {
176 return
177 r_load_externals(searchpath, get_coordinate_system(), record);
178}
179
180/**
181 * Removes duplicate references to the same texture image with the same
182 * properties. Considers two texture references with identical properties,
183 * but different tref names, to be equivalent, and collapses them, choosing
184 * one tref name to keep arbitrarily. Returns the number of textures removed.
185 */
188 EggTextureCollection textures;
189 textures.find_used_textures(this);
190 return
191 textures.collapse_equivalent_textures(~EggTexture::E_tref_name, this);
192}
193
194/**
195 * Removes duplicate references to the same material with the same properties.
196 * Considers two material references with identical properties, but different
197 * mref names, to be equivalent, and collapses them, choosing one mref name to
198 * keep arbitrarily. Returns the number of materials removed.
199 */
202 EggMaterialCollection materials;
203 materials.find_used_materials(this);
204 return
205 materials.collapse_equivalent_materials(~EggMaterial::E_mref_name, this);
206}
207
208/**
209 * The main interface for writing complete egg files.
210 */
212write_egg(Filename filename) {
214 filename.set_text();
215 vfs->delete_file(filename);
216 ostream *file = vfs->open_write_file(filename, true, true);
217 if (file == nullptr) {
218 egg_cat.error() << "Unable to open " << filename << " for writing.\n";
219 return false;
220 }
221
222 bool wrote_ok = write_egg(*file);
223 vfs->close_write_file(file);
224 return wrote_ok;
225}
226
227/**
228 * The main interface for writing complete egg files.
229 */
231write_egg(ostream &out) {
232 pre_write();
233
234 if (egg_precision > 0) {
235 // Change the egg precision as requested.
236 std::streamsize orig_precision = out.precision();
237 out.precision((std::streamsize)egg_precision);
238 write(out, 0);
239 out.precision(orig_precision);
240 } else {
241 // Use the stream default precision.
242 write(out, 0);
243 }
244 return true;
245}
246
247
248/**
249 * Changes the coordinate system of the EggData. If the coordinate system was
250 * previously different, this may result in a conversion of the data.
251 */
252void EggData::
253set_coordinate_system(CoordinateSystem new_coordsys) {
254 if (new_coordsys == CS_default) {
255 new_coordsys = get_default_coordinate_system();
256 }
257 if (new_coordsys != _coordsys &&
258 (_coordsys != CS_default && _coordsys != CS_invalid)) {
259 // Time to convert the data.
260 LMatrix4d mat = LMatrix4d::convert_mat(_coordsys, new_coordsys);
261 LMatrix4d inv = LMatrix4d::convert_mat(new_coordsys, _coordsys);
262
263 r_transform(mat, inv, new_coordsys);
264 r_transform_vertices(mat);
265
266 // Now we have to update the under_flags to ensure that all the cached
267 // relative matrices are correct.
268 update_under(0);
269 }
270
271 _coordsys = new_coordsys;
272}
273
274/**
275 * Writes the egg data out to the indicated output stream.
276 */
277void EggData::
278write(ostream &out, int indent_level) const {
279 PT(EggCoordinateSystem) ecs = new EggCoordinateSystem(_coordsys);
280 ecs->write(out, indent_level);
281 EggGroupNode::write(out, indent_level);
282 out << std::flush;
283}
284
285
286/**
287 * Does whatever processing is appropriate after reading the data in from an
288 * egg file.
289 */
290void EggData::
291post_read() {
292 CoordinateSystem old_coordsys = _coordsys;
293 _coordsys = find_coordsys_entry();
294
295 if (_coordsys == CS_default) {
296 // If the egg file didn't contain a <CoordinateSystem> entry, assume it's
297 // Y-up, by convention.
298 _coordsys = CS_yup_right;
299
300 } else if (_coordsys == CS_invalid) {
301 egg_cat.warning()
302 << "Contradictory <CoordinateSystem> entries encountered.\n";
303 _coordsys = CS_yup_right;
304 }
305
306 r_mark_coordsys(_coordsys);
307
308 if (old_coordsys != CS_default) {
309 // Now if we had a previous definition, enforce it. This might convert
310 // the data to the given coordinate system.
311 set_coordinate_system(old_coordsys);
312 }
313
314 // Fill this in before we automatically resolve pathnames.
315 _had_absolute_pathnames = has_absolute_pathnames();
316
318 // Resolve filenames that are relative to the egg file.
319 DSearchPath dir;
320 dir.append_directory(get_egg_filename().get_dirname());
322 }
323}
324
325/**
326 * Does whatever processing is appropriate just before writing the data out to
327 * an egg file. This includes verifying that vertex pool names are unique,
328 * etc.
329 */
330void EggData::
331pre_write() {
332 // Pull out all of the texture definitions in the file and massage them a
333 // bit.
334 EggTextureCollection textures;
335 textures.extract_textures(this);
336
337 // Remove any textures that aren't being used.
338 textures.remove_unused_textures(this);
339
340 // Collapse out any textures that are completely equivalent. For this
341 // purpose, we consider two textures with identical properties but different
342 // tref names to be different.
343 textures.collapse_equivalent_textures(~0, this);
344
345 // Make sure all of the textures have unique TRef names.
346 textures.uniquify_trefs();
347 textures.sort_by_tref();
348
349 // Do the same thing with the materials.
350 EggMaterialCollection materials;
351 materials.extract_materials(this);
352 materials.remove_unused_materials(this);
353 materials.collapse_equivalent_materials(~0, this);
354 materials.uniquify_mrefs();
355 materials.sort_by_mref();
356
357 // Now put them all back at the head of the file, after any initial comment
358 // records.
359 iterator ci = begin();
360 while (ci != end() && (*ci)->is_of_type(EggComment::get_class_type())) {
361 ++ci;
362 }
363 textures.insert_textures(this, ci);
364 materials.insert_materials(this, ci);
365
366 // Also make sure that the vertex pools are uniquely named. This also
367 // checks textures and materials, which is kind of redundant since we just
368 // did that, but we don't mind.
370 pu.uniquify(this);
371}
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
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.
The <CoordinateSystem> entry at the top of an egg file.
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
bool write_egg(Filename filename)
The main interface for writing complete egg files.
Definition eggData.cxx:212
get_auto_resolve_externals
Indicates whether the EggData object will automatically resolve any external references when read() i...
Definition eggData.h:72
static bool resolve_egg_filename(Filename &egg_filename, const DSearchPath &searchpath=DSearchPath())
Looks for the indicated filename, first along the indicated searchpath, and then along the model_path...
Definition eggData.cxx:44
set_egg_timestamp
Sets the timestamp of the egg file on disk, at the time it was opened for reading.
Definition eggData.h:75
get_coordinate_system
Returns the coordinate system in which the egg file is defined.
Definition eggData.h:73
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
set_coordinate_system
Changes the coordinate system of the EggData.
Definition eggData.h:73
int collapse_equivalent_materials()
Removes duplicate references to the same material with the same properties.
Definition eggData.cxx:201
int collapse_equivalent_textures()
Removes duplicate references to the same texture image with the same properties.
Definition eggData.cxx:187
set_egg_filename
Sets the filename–especially the directory part–in which the egg file is considered to reside.
Definition eggData.h:74
void merge(EggData &other)
Appends the other egg structure to the end of this one.
Definition eggData.cxx:139
get_egg_filename
Returns the directory in which the egg file is considered to reside.
Definition eggData.h:74
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
virtual void write(std::ostream &out, int indent_level) const
Writes the group and all of its children to the indicated output stream in Egg format.
void resolve_filenames(const DSearchPath &searchpath)
Walks the tree and attempts to resolve any filenames encountered.
bool has_absolute_pathnames() const
Returns true if any nodes at this level and below include a reference to a file via an absolute pathn...
void steal_children(EggGroupNode &other)
Moves all the children from the other node to this one.
This is a collection of materials by MRef name.
void uniquify_mrefs()
Guarantees that each material in the collection has a unique MRef name.
int find_used_materials(EggNode *node)
Walks the egg hierarchy beginning at the indicated node, looking for materials that are referenced by...
int collapse_equivalent_materials(int eq, EggGroupNode *node)
Walks through the collection and collapses together any separate materials that are equivalent accord...
int extract_materials(EggGroupNode *node)
Walks the egg hierarchy beginning at the indicated node, and removes any EggMaterials encountered in ...
EggGroupNode::iterator insert_materials(EggGroupNode *node)
Adds a series of EggMaterial nodes to the beginning of the indicated node to reflect each of the mate...
void sort_by_mref()
Sorts all the materials into alphabetical order by MRef name.
void remove_unused_materials(EggNode *node)
Removes any materials from the collection that aren't referenced by any primitives in the indicated e...
void uniquify(EggNode *node)
Begins the traversal from the indicated node.
This is a specialization of EggNameUniquifier to generate unique names for textures,...
This is a collection of textures by TRef name.
void sort_by_tref()
Sorts all the textures into alphabetical order 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 ...
int collapse_equivalent_textures(int eq, EggGroupNode *node)
Walks through the collection and collapses together any separate textures that are equivalent accordi...
int extract_textures(EggGroupNode *node)
Walks the egg hierarchy beginning at the indicated node, and removes any EggTextures encountered in t...
void uniquify_trefs()
Guarantees that each texture in the collection has a unique TRef name.
EggGroupNode::iterator insert_textures(EggGroupNode *node)
Adds a series of EggTexture nodes to the beginning of the indicated node to reflect each of the textu...
void remove_unused_textures(EggNode *node)
Removes any textures from the collection that aren't referenced by any primitives in the indicated eg...
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
Definition filename.I:562
void set_text()
Indicates that the filename represents a text file.
Definition filename.I:424
Similar to MutexHolder, but for a light mutex.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
A hierarchy of directories and files that appears to be one continuous file system,...
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists in the virtual file system hierarchy.
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
std::ostream * open_write_file(const Filename &filename, bool auto_wrap, bool truncate)
Convenience function; returns a newly allocated ostream if the file exists and can be written,...
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
bool delete_file(const Filename &filename)
Attempts to delete the indicated file or directory.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition virtualFile.h:35
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.
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.