Panda3D
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"
16 #include "eggTextureCollection.h"
17 #include "eggMaterialCollection.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 
29 using std::istream;
30 using std::ostream;
31 
32 extern int eggyyparse();
33 #include "parserDefs.h"
34 #include "lexerDefs.h"
35 
36 TypeHandle 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  */
44 resolve_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  */
65 read(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  */
107 read(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  */
139 merge(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  */
162 load_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  */
175 load_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  */
212 write_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  */
231 write_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  */
252 void EggData::
253 set_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  */
277 void EggData::
278 write(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  */
290 void EggData::
291 post_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());
321  resolve_filenames(dir);
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  */
330 void EggData::
331 pre_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 }
Filename::set_text
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
eggData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggGroupNode::has_absolute_pathnames
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...
Definition: eggGroupNode.cxx:313
EggTextureCollection::extract_textures
int extract_textures(EggGroupNode *node)
Walks the egg hierarchy beginning at the indicated node, and removes any EggTextures encountered in t...
Definition: eggTextureCollection.cxx:74
EggData::read
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
config_putil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggMaterialCollection::extract_materials
int extract_materials(EggGroupNode *node)
Walks the egg hierarchy beginning at the indicated node, and removes any EggMaterials encountered in ...
Definition: eggMaterialCollection.cxx:73
BamCacheRecord
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
Definition: bamCacheRecord.h:36
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggMaterialCollection
This is a collection of materials by MRef name.
Definition: eggMaterialCollection.h:30
EggMaterialCollection::sort_by_mref
void sort_by_mref()
Sorts all the materials into alphabetical order by MRef name.
Definition: eggMaterialCollection.cxx:300
EggMaterialCollection::collapse_equivalent_materials
int collapse_equivalent_materials(int eq, EggGroupNode *node)
Walks through the collection and collapses together any separate materials that are equivalent accord...
Definition: eggMaterialCollection.cxx:185
VirtualFileSystem::get_file
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
Definition: virtualFileSystem.cxx:515
EggData::merge
void merge(EggData &other)
Appends the other egg structure to the end of this one.
Definition: eggData.cxx:139
EggData::load_externals
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
EggGroupNode::write
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.
Definition: eggGroupNode.cxx:84
EggTextureCollection::remove_unused_textures
void remove_unused_textures(EggNode *node)
Removes any textures from the collection that aren't referenced by any primitives in the indicated eg...
Definition: eggTextureCollection.cxx:217
EggData::write_egg
bool write_egg(Filename filename)
The main interface for writing complete egg files.
Definition: eggData.cxx:212
EggTextureCollection::find_used_textures
int find_used_textures(EggNode *node)
Walks the egg hierarchy beginning at the indicated node, looking for textures that are referenced by ...
Definition: eggTextureCollection.cxx:159
EggData::get_coordinate_system
get_coordinate_system
Returns the coordinate system in which the egg file is defined.
Definition: eggData.h:73
VirtualFileSystem::exists
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
Definition: virtualFileSystem.I:18
EggData::set_egg_filename
set_egg_filename
Sets the filename–especially the directory part–in which the egg file is considered to reside.
Definition: eggData.h:74
EggData::resolve_egg_filename
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
EggData::get_egg_filename
get_egg_filename
Returns the directory in which the egg file is considered to reside.
Definition: eggData.h:74
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
EggGroupNode::steal_children
void steal_children(EggGroupNode &other)
Moves all the children from the other node to this one.
Definition: eggGroupNode.cxx:278
eggTextureCollection.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
VirtualFileSystem::close_write_file
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
Definition: virtualFileSystem.cxx:929
EggMaterialCollection::remove_unused_materials
void remove_unused_materials(EggNode *node)
Removes any materials from the collection that aren't referenced by any primitives in the indicated e...
Definition: eggMaterialCollection.cxx:167
EggData
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
EggTextureCollection::sort_by_tref
void sort_by_tref()
Sorts all the textures into alphabetical order by TRef name.
Definition: eggTextureCollection.cxx:357
eggCoordinateSystem.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
VirtualFileSystem::open_write_file
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,...
Definition: virtualFileSystem.cxx:890
DSearchPath::append_directory
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
Definition: dSearchPath.cxx:147
EggTextureCollection::collapse_equivalent_textures
int collapse_equivalent_textures(int eq, EggGroupNode *node)
Walks through the collection and collapses together any separate textures that are equivalent accordi...
Definition: eggTextureCollection.cxx:235
lightMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DSearchPath
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition: dSearchPath.h:28
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition: virtualFileSystem.h:40
EggNameUniquifier::uniquify
void uniquify(EggNode *node)
Begins the traversal from the indicated node.
Definition: eggNameUniquifier.cxx:55
parserDefs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggData::set_coordinate_system
set_coordinate_system
Changes the coordinate system of the EggData.
Definition: eggData.h:73
eggComment.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggTextureCollection::insert_textures
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...
Definition: eggTextureCollection.cxx:113
EggCoordinateSystem
The <CoordinateSystem> entry at the top of an egg file.
Definition: eggCoordinateSystem.h:29
EggMaterialCollection::find_used_materials
int find_used_materials(EggNode *node)
Walks the egg hierarchy beginning at the indicated node, looking for materials that are referenced by...
Definition: eggMaterialCollection.cxx:126
VirtualFileSystem::delete_file
bool delete_file(const Filename &filename)
Attempts to delete the indicated file or directory.
Definition: virtualFileSystem.cxx:575
VirtualFileSystem::get_global_ptr
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Definition: virtualFileSystem.cxx:741
virtualFileSystem.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggGroupNode::resolve_filenames
void resolve_filenames(const DSearchPath &searchpath)
Walks the tree and attempts to resolve any filenames encountered.
Definition: eggGroupNode.cxx:368
VirtualFile
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
zStream.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggTextureCollection::uniquify_trefs
void uniquify_trefs()
Guarantees that each texture in the collection has a unique TRef name.
Definition: eggTextureCollection.cxx:339
EggData::set_egg_timestamp
set_egg_timestamp
Sets the timestamp of the egg file on disk, at the time it was opened for reading.
Definition: eggData.h:75
EggPoolUniquifier
This is a specialization of EggNameUniquifier to generate unique names for textures,...
Definition: eggPoolUniquifier.h:26
EggData::get_auto_resolve_externals
get_auto_resolve_externals
Indicates whether the EggData object will automatically resolve any external references when read() i...
Definition: eggData.h:72
VirtualFileSystem::resolve_filename
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
Definition: virtualFileSystem.cxx:640
dSearchPath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggData::collapse_equivalent_materials
int collapse_equivalent_materials()
Removes duplicate references to the same material with the same properties.
Definition: eggData.cxx:201
EggMaterialCollection::insert_materials
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...
Definition: eggMaterialCollection.cxx:85
config_egg.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_express.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggMaterialCollection.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lexerDefs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggTextureCollection
This is a collection of textures by TRef name.
Definition: eggTextureCollection.h:30
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
EggMaterialCollection::uniquify_mrefs
void uniquify_mrefs()
Guarantees that each material in the collection has a unique MRef name.
Definition: eggMaterialCollection.cxx:282
EggData::collapse_equivalent_textures
int collapse_equivalent_textures()
Removes duplicate references to the same texture image with the same properties.
Definition: eggData.cxx:187
Filename::is_fully_qualified
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
Definition: filename.I:562
eggPoolUniquifier.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.