support forward-referenced vertex pools

This commit is contained in:
David Rose 2003-11-21 23:02:52 +00:00
parent 3110e8c5ef
commit 29cfd81978
7 changed files with 237 additions and 39 deletions

View File

@ -21,13 +21,32 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: EggVertex::get_pool // Function: EggVertex::get_pool
// Access: Public // 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:: INLINE EggVertexPool *EggVertex::
get_pool() const { get_pool() const {
return _pool; 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 // Function: EggVertex::set_pos

View File

@ -42,6 +42,7 @@ TypeHandle EggVertex::_type_handle;
EggVertex:: EggVertex::
EggVertex() { EggVertex() {
_pool = NULL; _pool = NULL;
_forward_reference = false;
_index = -1; _index = -1;
_external_index = -1; _external_index = -1;
set_pos(LPoint3d(0.0, 0.0, 0.0)); set_pos(LPoint3d(0.0, 0.0, 0.0));
@ -64,6 +65,7 @@ EggVertex(const EggVertex &copy)
_num_dimensions(copy._num_dimensions) _num_dimensions(copy._num_dimensions)
{ {
_pool = NULL; _pool = NULL;
_forward_reference = false;
_index = -1; _index = -1;
test_pref_integrity(); test_pref_integrity();
test_gref_integrity(); test_gref_integrity();

View File

@ -52,6 +52,8 @@ PUBLISHED:
INLINE EggVertexPool *get_pool() const; INLINE EggVertexPool *get_pool() const;
INLINE bool is_forward_reference() const;
// The pos might have 1, 2, 3, or 4 dimensions. That complicates // The pos might have 1, 2, 3, or 4 dimensions. That complicates
// things a bit. // things a bit.
INLINE void set_pos(double pos); INLINE void set_pos(double pos);
@ -116,6 +118,7 @@ PUBLISHED:
private: private:
EggVertexPool *_pool; EggVertexPool *_pool;
bool _forward_reference;
int _index; int _index;
int _external_index; int _external_index;
LPoint4d _pos; LPoint4d _pos;

View File

@ -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 // Function: EggVertexPool::indexing operator
// Access: Public // Access: Public
@ -39,8 +51,7 @@ operator [](int index) const {
INLINE EggVertex *EggVertexPool:: INLINE EggVertex *EggVertexPool::
make_new_vertex() { make_new_vertex() {
PT(EggVertex) vertex = new EggVertex; PT(EggVertex) vertex = new EggVertex;
add_vertex(vertex); return add_vertex(vertex);
return vertex;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -20,7 +20,7 @@
#include "eggPrimitive.h" #include "eggPrimitive.h"
#include "eggUtilities.h" #include "eggUtilities.h"
#include <indent.h> #include "indent.h"
TypeHandle EggVertexPool::_type_handle; TypeHandle EggVertexPool::_type_handle;
@ -31,6 +31,7 @@ TypeHandle EggVertexPool::_type_handle;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
EggVertexPool:: EggVertexPool::
EggVertexPool(const string &name) : EggNode(name) { EggVertexPool(const string &name) : EggNode(name) {
_highest_index = 0;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -62,20 +63,62 @@ EggVertexPool::
// Sanity check. // Sanity check.
nassertv(_index_vertices.size() == _unique_vertices.size()); nassertv(_index_vertices.size() == _unique_vertices.size());
iterator i; IndexVertices::iterator ivi;
for (i = begin(); i != end(); ++i) { for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
// Sanity checks on our internal data structures. int index = (*ivi).first;
nassertv((*i)->_pool == this); EggVertex *vertex = (*ivi).second;
nassertv(get_vertex((*i)->_index) == (*i));
(*i)->_pool = NULL; // Sanity checks on our internal data structures.
(*i)->_index = -1; nassertv(vertex->_pool == this);
nassertv(vertex->get_index() == index);
vertex->_pool = NULL;
vertex->_index = -1;
} }
_index_vertices.erase(_index_vertices.begin(), _index_vertices.end()); _index_vertices.clear();
_unique_vertices.erase(_unique_vertices.begin(), _unique_vertices.end()); _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 // Function: EggVertexPool::get_vertex
@ -90,6 +133,35 @@ get_vertex(int index) const {
if (ivi == _index_vertices.end()) { if (ivi == _index_vertices.end()) {
return NULL; 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 { } else {
return (*ivi).second; return (*ivi).second;
} }
@ -99,16 +171,11 @@ get_vertex(int index) const {
// Function: EggVertexPool::get_highest_index // Function: EggVertexPool::get_highest_index
// Access: Public // Access: Public
// Description: Returns the highest index number used by any vertex // Description: Returns the highest index number used by any vertex
// in the pool. // in the pool (except forward references).
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
int EggVertexPool:: int EggVertexPool::
get_highest_index() const { get_highest_index() const {
if (_index_vertices.empty()) { return _highest_index;
return 0;
}
IndexVertices::const_reverse_iterator ivi = _index_vertices.rbegin();
nassertr((*ivi).first == (*ivi).second->get_index(), 0);
return (*ivi).first;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -166,26 +233,59 @@ size() const {
// the vertex pool. If the index number is supplied, // the vertex pool. If the index number is supplied,
// tries to assign that index number; it is an error if // tries to assign that index number; it is an error if
// the index number is already in use. // 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) { 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. // 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) { if (index == -1) {
index = get_highest_index() + 1; index = get_highest_index() + 1;
} }
// Always supply an index number >= 0. // Always supply an index number >= 0.
nassertv(index >= 0); nassertr(index >= 0, NULL);
// Don't try to duplicate index numbers within a vertex pool. // Check for a forward reference.
nassertv(_index_vertices.find(index) == _index_vertices.end()); 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); _unique_vertices.insert(vertex);
_index_vertices[index] = vertex; _index_vertices[index] = vertex;
if (!vertex->is_forward_reference()) {
_highest_index = max(_highest_index, index);
}
vertex->_pool = this; vertex->_pool = this;
vertex->_index = index; vertex->_index = index;
return vertex;
} }
@ -208,9 +308,7 @@ create_unique_vertex(const EggVertex &copy) {
} }
// Create a new vertex. // Create a new vertex.
EggVertex *vtx = new EggVertex(copy); return add_vertex(new EggVertex(copy));
add_vertex(vtx);
return vtx;
} }
@ -231,6 +329,24 @@ remove_vertex(EggVertex *vertex) {
// Removing the vertex from the indexed list is simple. // Removing the vertex from the indexed list is simple.
_index_vertices.erase(vertex->_index); _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 // Removing the vertex from the unique list is a bit trickier--there
// might be several other vertices that are considered identical to // might be several other vertices that are considered identical to
// this one, and so we have to walk through all the identical // 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. // All done. Lose the old lists.
_unique_vertices.swap(new_unique_vertices); _unique_vertices.swap(new_unique_vertices);
_index_vertices.swap(new_index_vertices); _index_vertices.swap(new_index_vertices);
_highest_index = _index_vertices.size() - 1;
nassertr(_index_vertices.size() == _unique_vertices.size(), num_removed); nassertr(_index_vertices.size() == _unique_vertices.size(), num_removed);

View File

@ -77,10 +77,18 @@ PUBLISHED:
EggVertexPool(const EggVertexPool &copy); EggVertexPool(const EggVertexPool &copy);
~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. // Returns NULL if there is no such vertex.
EggVertex *get_vertex(int index) const; EggVertex *get_vertex(int index) const;
INLINE EggVertex *operator [](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. // Returns 0 if the pool is empty.
int get_highest_index() const; int get_highest_index() const;
@ -94,7 +102,7 @@ public:
PUBLISHED: PUBLISHED:
// add_vertex() adds a freshly-allocated vertex. It is up to the // add_vertex() adds a freshly-allocated vertex. It is up to the
// user to allocate the vertex. // 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 // make_new_vertex() allocates and returns a new vertex from the
// pool. // pool.
@ -124,6 +132,7 @@ protected:
private: private:
UniqueVertices _unique_vertices; UniqueVertices _unique_vertices;
IndexVertices _index_vertices; IndexVertices _index_vertices;
int _highest_index;
public: public:

View File

@ -5,7 +5,8 @@
%{ %{
#include <pandabase.h> #include "pandabase.h"
#include "config_egg.h"
#include "parserDefs.h" #include "parserDefs.h"
#include "lexerDefs.h" #include "lexerDefs.h"
#include "eggObject.h" #include "eggObject.h"
@ -101,6 +102,32 @@ egg_init_parser(istream &in, const string &filename,
void void
egg_cleanup_parser() { 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 // Clean these out after we're done, so we don't keep big memory
// structures around needlessly. // structures around needlessly.
egg_stack.clear(); egg_stack.clear();
@ -580,12 +607,20 @@ vertex_pool:
VERTEXPOOL required_name VERTEXPOOL required_name
{ {
string name = $2; string name = $2;
EggVertexPool *pool = new EggVertexPool(name); EggVertexPool *pool = NULL;
if (vertex_pools.find(name) != vertex_pools.end()) { VertexPools::const_iterator vpi = vertex_pools.find(name);
eggyywarning("Duplicate vertex pool name " + 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); egg_stack.push_back(pool);
} }
@ -640,7 +675,7 @@ vertex:
eggyywarning(errmsg); eggyywarning(errmsg);
vertex_index = -1; vertex_index = -1;
} else if (pool->get_vertex(vertex_index) != NULL) { } else if (pool->has_vertex(vertex_index)) {
ostringstream errmsg; ostringstream errmsg;
errmsg << "Ignoring duplicate vertex index " << vertex_index errmsg << "Ignoring duplicate vertex index " << vertex_index
<< " in vertex pool " << pool->get_name() << ends; << " in vertex pool " << pool->get_name() << ends;
@ -1271,7 +1306,7 @@ group_vertex_ref:
for (int i = 0; i < (int)nums.size(); i++) { for (int i = 0; i < (int)nums.size(); i++) {
int index = (int)nums[i]; int index = (int)nums[i];
EggVertex *vertex = pool->get_vertex(index); EggVertex *vertex = pool->get_forward_vertex(index);
if (vertex == NULL) { if (vertex == NULL) {
ostringstream errmsg; ostringstream errmsg;
errmsg << "No vertex " << index << " in pool " << pool->get_name() 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++) { for (int i = 0; i < (int)nums.size(); i++) {
int index = (int)nums[i]; int index = (int)nums[i];
EggVertex *vertex = pool->get_vertex(index); EggVertex *vertex = pool->get_forward_vertex(index);
if (vertex == NULL) { if (vertex == NULL) {
ostringstream errmsg; ostringstream errmsg;
errmsg << "No vertex " << index << " in pool " << pool->get_name() errmsg << "No vertex " << index << " in pool " << pool->get_name()
@ -2310,8 +2345,10 @@ vertex_pool_name:
string name = $1; string name = $1;
VertexPools::iterator vpi = vertex_pools.find(name); VertexPools::iterator vpi = vertex_pools.find(name);
if (vpi == vertex_pools.end()) { if (vpi == vertex_pools.end()) {
eggyyerror("Unknown vertex pool " + name); // This will become a forward reference.
$$ = PT(EggObject)(); EggVertexPool *pool = new EggVertexPool(name);
vertex_pools[name] = pool;
$$ = pool;
} else { } else {
$$ = (*vpi).second; $$ = (*vpi).second;
} }