Sfoglia il codice sorgente

support forward-referenced vertex pools

David Rose 22 anni fa
parent
commit
29cfd81978

+ 20 - 1
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

+ 2 - 0
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 &copy)
     _num_dimensions(copy._num_dimensions)
 {
   _pool = NULL;
+  _forward_reference = false;
   _index = -1;
   test_pref_integrity();
   test_gref_integrity();

+ 3 - 0
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;

+ 13 - 2
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);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 141 - 24
panda/src/egg/eggVertexPool.cxx

@@ -20,7 +20,7 @@
 #include "eggPrimitive.h"
 #include "eggUtilities.h"
 
-#include <indent.h>
+#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) {
+  IndexVertices::iterator ivi;
+  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
+    int index = (*ivi).first;
+    EggVertex *vertex = (*ivi).second;
+
     // Sanity checks on our internal data structures.
-    nassertv((*i)->_pool == this);
-    nassertv(get_vertex((*i)->_index) == (*i));
+    nassertv(vertex->_pool == this);
+    nassertv(vertex->get_index() == index);
+
+    vertex->_pool = NULL;
+    vertex->_index = -1;
+  }
 
-    (*i)->_pool = NULL;
-    (*i)->_index = -1;
+  _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;
+    }
   }
 
-  _index_vertices.erase(_index_vertices.begin(), _index_vertices.end());
-  _unique_vertices.erase(_unique_vertices.begin(), _unique_vertices.end());
+  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);
+
+  // Check for a forward reference.
+  IndexVertices::const_iterator ivi = _index_vertices.find(index);
 
-  // Don't try to duplicate index numbers within a vertex pool.
-  nassertv(_index_vertices.find(index) == _index_vertices.end());
+  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 &copy) {
   }
 
   // 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);
 

+ 10 - 1
panda/src/egg/eggVertexPool.h

@@ -77,10 +77,18 @@ PUBLISHED:
   EggVertexPool(const EggVertexPool &copy);
   ~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:

+ 48 - 11
panda/src/egg/parser.yxx

@@ -5,7 +5,8 @@
 
 %{
 
-#include <pandabase.h>
+#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);
-
-  if (vertex_pools.find(name) != vertex_pools.end()) {
-    eggyywarning("Duplicate vertex pool name " + name);
+  EggVertexPool *pool = NULL;
+
+  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;
   }