diff --git a/panda/src/egg/eggVertex.I b/panda/src/egg/eggVertex.I index cbe2d90530..27ffb45a5f 100644 --- a/panda/src/egg/eggVertex.I +++ b/panda/src/egg/eggVertex.I @@ -21,13 +21,32 @@ //////////////////////////////////////////////////////////////////// // Function: EggVertex::get_pool // Access: Public -// Description: +// Description: Returns the vertex pool this vertex belongs in. This +// may be NULL if the vertex has not been added to a +// pool. //////////////////////////////////////////////////////////////////// INLINE EggVertexPool *EggVertex:: get_pool() const { return _pool; } +//////////////////////////////////////////////////////////////////// +// Function: EggVertex::is_forward_reference +// Access: Public +// Description: Returns true if the vertex is a forward reference to +// some vertex that hasn't been defined yet. In this +// case, the vertex may not have any properties filled +// in yet. +// +// This can only happen if you implicitly create a +// vertex via EggVertexPool::get_forward_vertex(). +// Presumably, when the vertex pool is later filled in, +// this vertex will be replaced with real data. +//////////////////////////////////////////////////////////////////// +INLINE bool EggVertex:: +is_forward_reference() const { + return _forward_reference; +} //////////////////////////////////////////////////////////////////// // Function: EggVertex::set_pos diff --git a/panda/src/egg/eggVertex.cxx b/panda/src/egg/eggVertex.cxx index 524cc912af..95345f926d 100644 --- a/panda/src/egg/eggVertex.cxx +++ b/panda/src/egg/eggVertex.cxx @@ -42,6 +42,7 @@ TypeHandle EggVertex::_type_handle; EggVertex:: EggVertex() { _pool = NULL; + _forward_reference = false; _index = -1; _external_index = -1; set_pos(LPoint3d(0.0, 0.0, 0.0)); @@ -64,6 +65,7 @@ EggVertex(const EggVertex ©) _num_dimensions(copy._num_dimensions) { _pool = NULL; + _forward_reference = false; _index = -1; test_pref_integrity(); test_gref_integrity(); diff --git a/panda/src/egg/eggVertex.h b/panda/src/egg/eggVertex.h index dfd69a6730..1e0b785b32 100644 --- a/panda/src/egg/eggVertex.h +++ b/panda/src/egg/eggVertex.h @@ -52,6 +52,8 @@ PUBLISHED: INLINE EggVertexPool *get_pool() const; + INLINE bool is_forward_reference() const; + // The pos might have 1, 2, 3, or 4 dimensions. That complicates // things a bit. INLINE void set_pos(double pos); @@ -116,6 +118,7 @@ PUBLISHED: private: EggVertexPool *_pool; + bool _forward_reference; int _index; int _external_index; LPoint4d _pos; diff --git a/panda/src/egg/eggVertexPool.I b/panda/src/egg/eggVertexPool.I index c9926eb626..5c30298747 100644 --- a/panda/src/egg/eggVertexPool.I +++ b/panda/src/egg/eggVertexPool.I @@ -17,6 +17,18 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: EggVertexPool::has_vertex +// Access: Public +// Description: Returns true if the indicated vertex has been defined +// in the vertex pool, false otherwise. This does not +// include forward references. +//////////////////////////////////////////////////////////////////// +INLINE bool EggVertexPool:: +has_vertex(int index) const { + return get_vertex(index) != (EggVertex *)NULL; +} + //////////////////////////////////////////////////////////////////// // Function: EggVertexPool::indexing operator // Access: Public @@ -39,8 +51,7 @@ operator [](int index) const { INLINE EggVertex *EggVertexPool:: make_new_vertex() { PT(EggVertex) vertex = new EggVertex; - add_vertex(vertex); - return vertex; + return add_vertex(vertex); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/egg/eggVertexPool.cxx b/panda/src/egg/eggVertexPool.cxx index 5d73721c30..26f85a6c63 100644 --- a/panda/src/egg/eggVertexPool.cxx +++ b/panda/src/egg/eggVertexPool.cxx @@ -20,7 +20,7 @@ #include "eggPrimitive.h" #include "eggUtilities.h" -#include +#include "indent.h" TypeHandle EggVertexPool::_type_handle; @@ -31,6 +31,7 @@ TypeHandle EggVertexPool::_type_handle; //////////////////////////////////////////////////////////////////// EggVertexPool:: EggVertexPool(const string &name) : EggNode(name) { + _highest_index = 0; } //////////////////////////////////////////////////////////////////// @@ -62,20 +63,62 @@ EggVertexPool:: // Sanity check. nassertv(_index_vertices.size() == _unique_vertices.size()); - iterator i; - for (i = begin(); i != end(); ++i) { - // Sanity checks on our internal data structures. - nassertv((*i)->_pool == this); - nassertv(get_vertex((*i)->_index) == (*i)); + IndexVertices::iterator ivi; + for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { + int index = (*ivi).first; + EggVertex *vertex = (*ivi).second; - (*i)->_pool = NULL; - (*i)->_index = -1; + // Sanity checks on our internal data structures. + nassertv(vertex->_pool == this); + nassertv(vertex->get_index() == index); + + vertex->_pool = NULL; + vertex->_index = -1; } - _index_vertices.erase(_index_vertices.begin(), _index_vertices.end()); - _unique_vertices.erase(_unique_vertices.begin(), _unique_vertices.end()); + _index_vertices.clear(); + _unique_vertices.clear(); } +//////////////////////////////////////////////////////////////////// +// Function: EggVertexPool::has_forward_vertices +// Access: Published +// Description: Returns true if any vertices in the pool are +// undefined forward-reference vertices, false if all +// vertices are defined. +//////////////////////////////////////////////////////////////////// +bool EggVertexPool:: +has_forward_vertices() const { + IndexVertices::const_iterator ivi; + for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { + EggVertex *vertex = (*ivi).second; + if (vertex->is_forward_reference()) { + return true; + } + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggVertexPool::has_defined_vertices +// Access: Published +// Description: Returns true if any vertices in the pool are +// fully defined vertices, false if all vertices are +// forward references. +//////////////////////////////////////////////////////////////////// +bool EggVertexPool:: +has_defined_vertices() const { + IndexVertices::const_iterator ivi; + for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { + EggVertex *vertex = (*ivi).second; + if (!vertex->is_forward_reference()) { + return true; + } + } + + return false; +} //////////////////////////////////////////////////////////////////// // Function: EggVertexPool::get_vertex @@ -90,6 +133,35 @@ get_vertex(int index) const { if (ivi == _index_vertices.end()) { return NULL; + } else { + EggVertex *vertex = (*ivi).second; + if (vertex->is_forward_reference()) { + return NULL; + } + return vertex; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: EggVertexPool::get_forward_vertex +// Access: Public +// Description: Returns the vertex in the pool with the indicated +// index number. If there is not a vertex in the pool +// with the indicated index number, creates a special +// forward-reference EggVertex that has no data, on the +// assumption that the vertex pool has not yet been +// fully read and more data will be available later. +//////////////////////////////////////////////////////////////////// +EggVertex *EggVertexPool:: +get_forward_vertex(int index) { + nassertr(index >= 0, NULL); + + IndexVertices::const_iterator ivi = _index_vertices.find(index); + + if (ivi == _index_vertices.end()) { + PT(EggVertex) forward = new EggVertex; + forward->_forward_reference = true; + return add_vertex(forward, index); } else { return (*ivi).second; } @@ -99,16 +171,11 @@ get_vertex(int index) const { // Function: EggVertexPool::get_highest_index // Access: Public // Description: Returns the highest index number used by any vertex -// in the pool. +// in the pool (except forward references). //////////////////////////////////////////////////////////////////// int EggVertexPool:: get_highest_index() const { - if (_index_vertices.empty()) { - return 0; - } - IndexVertices::const_reverse_iterator ivi = _index_vertices.rbegin(); - nassertr((*ivi).first == (*ivi).second->get_index(), 0); - return (*ivi).first; + return _highest_index; } //////////////////////////////////////////////////////////////////// @@ -166,26 +233,59 @@ size() const { // the vertex pool. If the index number is supplied, // tries to assign that index number; it is an error if // the index number is already in use. +// +// It is possible that a forward reference to this +// vertex was requested in the past; if so, the data +// from the supplied vertex is copied onto the forward +// reference, which becomes the actual vertex. In this +// case, a different pointer is saved (and returned) +// than the one actually passed in. In the usual case, +// however, the vertex pointer passed in is the one that +// is saved in the vertex pool and returned from this +// method. //////////////////////////////////////////////////////////////////// -void EggVertexPool:: +EggVertex *EggVertexPool:: add_vertex(EggVertex *vertex, int index) { + // Save a pointer to the vertex. + PT(EggVertex) vertex_keep = vertex; + // Don't try to add a vertex while it still belongs to another pool. - nassertv(vertex->_pool == NULL); + nassertr(vertex->_pool == NULL, NULL); if (index == -1) { index = get_highest_index() + 1; } // Always supply an index number >= 0. - nassertv(index >= 0); + nassertr(index >= 0, NULL); - // Don't try to duplicate index numbers within a vertex pool. - nassertv(_index_vertices.find(index) == _index_vertices.end()); + // Check for a forward reference. + IndexVertices::const_iterator ivi = _index_vertices.find(index); + if (ivi != _index_vertices.end()) { + EggVertex *orig_vertex = (*ivi).second; + if (orig_vertex->is_forward_reference() && + !vertex->is_forward_reference()) { + (*orig_vertex) = (*vertex); + orig_vertex->_forward_reference = false; + _highest_index = max(_highest_index, index); + return orig_vertex; + } + + // Oops, you duplicated a vertex index. + nassertr(false, NULL); + } + _unique_vertices.insert(vertex); _index_vertices[index] = vertex; + if (!vertex->is_forward_reference()) { + _highest_index = max(_highest_index, index); + } + vertex->_pool = this; vertex->_index = index; + + return vertex; } @@ -208,9 +308,7 @@ create_unique_vertex(const EggVertex ©) { } // Create a new vertex. - EggVertex *vtx = new EggVertex(copy); - add_vertex(vtx); - return vtx; + return add_vertex(new EggVertex(copy)); } @@ -231,6 +329,24 @@ remove_vertex(EggVertex *vertex) { // Removing the vertex from the indexed list is simple. _index_vertices.erase(vertex->_index); + if (_highest_index == vertex->_index) { + // Find the new highest vertex index. + if (_index_vertices.empty()) { + _highest_index = 0; + } else { + IndexVertices::reverse_iterator ivi = _index_vertices.rbegin(); + while (ivi != _index_vertices.rend() && + (*ivi).second->is_forward_reference()) { + ++ivi; + } + if (ivi != _index_vertices.rend()) { + _highest_index = (*ivi).first; + } else { + _highest_index = 0; + } + } + } + // Removing the vertex from the unique list is a bit trickier--there // might be several other vertices that are considered identical to // this one, and so we have to walk through all the identical @@ -289,6 +405,7 @@ remove_unused_vertices() { // All done. Lose the old lists. _unique_vertices.swap(new_unique_vertices); _index_vertices.swap(new_index_vertices); + _highest_index = _index_vertices.size() - 1; nassertr(_index_vertices.size() == _unique_vertices.size(), num_removed); diff --git a/panda/src/egg/eggVertexPool.h b/panda/src/egg/eggVertexPool.h index 6f3fbe2e8c..021829ecde 100644 --- a/panda/src/egg/eggVertexPool.h +++ b/panda/src/egg/eggVertexPool.h @@ -77,10 +77,18 @@ PUBLISHED: EggVertexPool(const EggVertexPool ©); ~EggVertexPool(); + INLINE bool has_vertex(int index) const; + + bool has_forward_vertices() const; + bool has_defined_vertices() const; + // Returns NULL if there is no such vertex. EggVertex *get_vertex(int index) const; INLINE EggVertex *operator [](int index) const; + // Returns a forward reference if there is no such vertex. + EggVertex *get_forward_vertex(int index); + // Returns 0 if the pool is empty. int get_highest_index() const; @@ -94,7 +102,7 @@ public: PUBLISHED: // add_vertex() adds a freshly-allocated vertex. It is up to the // user to allocate the vertex. - void add_vertex(EggVertex *vertex, int index = -1); + EggVertex *add_vertex(EggVertex *vertex, int index = -1); // make_new_vertex() allocates and returns a new vertex from the // pool. @@ -124,6 +132,7 @@ protected: private: UniqueVertices _unique_vertices; IndexVertices _index_vertices; + int _highest_index; public: diff --git a/panda/src/egg/parser.yxx b/panda/src/egg/parser.yxx index 66d9354f57..3256c58fbf 100644 --- a/panda/src/egg/parser.yxx +++ b/panda/src/egg/parser.yxx @@ -5,7 +5,8 @@ %{ -#include +#include "pandabase.h" +#include "config_egg.h" #include "parserDefs.h" #include "lexerDefs.h" #include "eggObject.h" @@ -101,6 +102,32 @@ egg_init_parser(istream &in, const string &filename, void egg_cleanup_parser() { + // Check for undefined vertex pools. + VertexPools::const_iterator vpi; + for (vpi = vertex_pools.begin(); vpi != vertex_pools.end(); ++vpi) { + EggVertexPool *pool = (*vpi).second; + if (pool->has_forward_vertices()) { + if (!pool->has_defined_vertices()) { + eggyyerror("Undefined vertex pool " + pool->get_name()); + } else { + eggyyerror("Undefined vertices in pool " + pool->get_name()); + + egg_cat.error(false) + << "Undefined vertex index numbers:"; + EggVertexPool::const_iterator vi; + for (vi = pool->begin(); vi != pool->end(); ++vi) { + EggVertex *vertex = (*vi); + if (vertex->is_forward_reference()) { + egg_cat.error(false) + << " " << vertex->get_index(); + } + } + egg_cat.error(false) + << "\n"; + } + } + } + // Clean these out after we're done, so we don't keep big memory // structures around needlessly. egg_stack.clear(); @@ -580,12 +607,20 @@ vertex_pool: VERTEXPOOL required_name { string name = $2; - EggVertexPool *pool = new EggVertexPool(name); + EggVertexPool *pool = NULL; - if (vertex_pools.find(name) != vertex_pools.end()) { - eggyywarning("Duplicate vertex pool name " + name); + VertexPools::const_iterator vpi = vertex_pools.find(name); + if (vpi != vertex_pools.end()) { + pool = (*vpi).second; + if (pool->has_defined_vertices()) { + eggyywarning("Duplicate vertex pool name " + name); + pool = new EggVertexPool(name); + vertex_pools[name] = pool; + } + } else { + pool = new EggVertexPool(name); + vertex_pools[name] = pool; } - vertex_pools[name] = pool; egg_stack.push_back(pool); } @@ -640,7 +675,7 @@ vertex: eggyywarning(errmsg); vertex_index = -1; - } else if (pool->get_vertex(vertex_index) != NULL) { + } else if (pool->has_vertex(vertex_index)) { ostringstream errmsg; errmsg << "Ignoring duplicate vertex index " << vertex_index << " in vertex pool " << pool->get_name() << ends; @@ -1271,7 +1306,7 @@ group_vertex_ref: for (int i = 0; i < (int)nums.size(); i++) { int index = (int)nums[i]; - EggVertex *vertex = pool->get_vertex(index); + EggVertex *vertex = pool->get_forward_vertex(index); if (vertex == NULL) { ostringstream errmsg; errmsg << "No vertex " << index << " in pool " << pool->get_name() @@ -1840,7 +1875,7 @@ primitive_vertex_ref: for (int i = 0; i < (int)nums.size(); i++) { int index = (int)nums[i]; - EggVertex *vertex = pool->get_vertex(index); + EggVertex *vertex = pool->get_forward_vertex(index); if (vertex == NULL) { ostringstream errmsg; errmsg << "No vertex " << index << " in pool " << pool->get_name() @@ -2310,8 +2345,10 @@ vertex_pool_name: string name = $1; VertexPools::iterator vpi = vertex_pools.find(name); if (vpi == vertex_pools.end()) { - eggyyerror("Unknown vertex pool " + name); - $$ = PT(EggObject)(); + // This will become a forward reference. + EggVertexPool *pool = new EggVertexPool(name); + vertex_pools[name] = pool; + $$ = pool; } else { $$ = (*vpi).second; }