Przeglądaj źródła

per-primitive minmax

David Rose 21 lat temu
rodzic
commit
25c3988698

+ 7 - 9
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2079,20 +2079,18 @@ void CLP(GraphicsStateGuardian)::
 draw_tristrips(const qpGeomTristrips *primitive) {
   setup_antialias_polygon();
 
-  int min_vertex = primitive->get_min_vertex();
-  int max_vertex = primitive->get_max_vertex();
   CPTA_ushort vertices = primitive->get_flat_last_vertices();
   CPTA_int ends = primitive->get_ends();
+  CPTA_ushort mins = primitive->get_mins();
+  CPTA_ushort maxs = primitive->get_maxs();
+  nassertv(mins.size() == ends.size() && maxs.size() == ends.size());
 
-  int num_primitives = primitive->get_num_primitives();
-  int start = 0;
-  for (CPTA_int::const_iterator pi = ends.begin(); pi != ends.end(); ++pi) {
-    int end = (*pi);
-
+  unsigned int start = 0;
+  for (size_t i = 0; i < ends.size(); i++) {
     _glDrawRangeElements(GL_TRIANGLE_STRIP, 
-                         min_vertex, max_vertex, end - start,
+                         mins[i], maxs[i], ends[i] - start,
                          GL_UNSIGNED_SHORT, vertices + start);
-    start = end;
+    start = ends[i];
   }
 
   report_my_gl_errors();

+ 69 - 1
panda/src/gobj/qpgeomPrimitive.I

@@ -145,7 +145,7 @@ get_flat_last_vertices() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::get_vertices
+//     Function: qpGeomPrimitive::get_ends
 //       Access: Published
 //  Description: Returns a const pointer to the primitive ends
 //               array so application code can read it directly.  Do
@@ -162,6 +162,40 @@ get_ends() const {
   return cdata->_ends;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_mins
+//       Access: Published
+//  Description: Returns a const pointer to the primitive mins
+//               array so application code can read it directly.  Do
+//               not attempt to modify the returned array; use
+//               modify_mins() or set_mins() for this.
+//
+//               Note that simple primitive types, like triangles, do
+//               not have a mins array.
+////////////////////////////////////////////////////////////////////
+INLINE CPTA_ushort qpGeomPrimitive::
+get_mins() const {
+  CDReader cdata(_cycler);
+  return cdata->_mins;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_maxs
+//       Access: Published
+//  Description: Returns a const pointer to the primitive maxs
+//               array so application code can read it directly.  Do
+//               not attempt to modify the returned array; use
+//               modify_maxs() or set_maxs() for this.
+//
+//               Note that simple primitive types, like triangles, do
+//               not have a maxs array.
+////////////////////////////////////////////////////////////////////
+INLINE CPTA_ushort qpGeomPrimitive::
+get_maxs() const {
+  CDReader cdata(_cycler);
+  return cdata->_maxs;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_min_vertex
 //       Access: Published
@@ -177,6 +211,22 @@ get_min_vertex() const {
   return cdata->_min_vertex;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_min_vertex
+//       Access: Published
+//  Description: Returns the minimum vertex index number used by the
+//               ith primitive in this object.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_min_vertex(int i) const {
+  CDReader cdata(_cycler);
+  if (!cdata->_got_minmax) {
+    ((qpGeomPrimitive *)this)->recompute_minmax();
+  }
+  nassertr(i >= 0 && i < (int)cdata->_mins.size(), -1);
+  return cdata->_mins[i];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_max_vertex
 //       Access: Published
@@ -192,6 +242,22 @@ get_max_vertex() const {
   return cdata->_max_vertex;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_max_vertex
+//       Access: Published
+//  Description: Returns the maximum vertex index number used by the
+//               ith primitive in this object.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_max_vertex(int i) const {
+  CDReader cdata(_cycler);
+  if (!cdata->_got_minmax) {
+    ((qpGeomPrimitive *)this)->recompute_minmax();
+  }
+  nassertr(i >= 0 && i < (int)cdata->_maxs.size(), -1);
+  return cdata->_maxs[i];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_primitive_end
 //       Access: Published
@@ -228,6 +294,8 @@ CData(const qpGeomPrimitive::CData &copy) :
   _vertices(copy._vertices),
   _rotated_vertices(copy._rotated_vertices),
   _ends(copy._ends),
+  _mins(copy._mins),
+  _maxs(copy._maxs),
   _got_minmax(copy._got_minmax),
   _min_vertex(copy._min_vertex),
   _max_vertex(copy._max_vertex)

+ 92 - 6
panda/src/gobj/qpgeomPrimitive.cxx

@@ -28,7 +28,7 @@
 
 TypeHandle qpGeomPrimitive::_type_handle;
 
-PStatCollector qpGeomPrimitive::_rotate_pcollector("Cull:Rotate");
+PStatCollector qpGeomPrimitive::_rotate_pcollector("Draw:Rotate");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::Constructor
@@ -100,6 +100,20 @@ add_vertex(int vertex) {
   if (cdata->_got_minmax) {
     cdata->_min_vertex = min(cdata->_min_vertex, short_vertex);
     cdata->_max_vertex = max(cdata->_max_vertex, short_vertex);
+
+    if (get_num_vertices_per_primitive() == 0) {
+      // Complex primitives also update their per-primitive minmax.
+      size_t pi = cdata->_ends.size();
+      if (pi < cdata->_mins.size()) {
+        cdata->_mins[pi] = min(cdata->_mins[pi], short_vertex);
+        cdata->_maxs[pi] = max(cdata->_maxs[pi], short_vertex);
+      } else {
+        cdata->_mins.push_back(short_vertex);
+        cdata->_maxs.push_back(short_vertex);
+      }
+      nassertv((cdata->_mins.size() == cdata->_ends.size() + 1) &&
+               (cdata->_maxs.size() == cdata->_ends.size() + 1));
+    }
   }
 }
 
@@ -126,6 +140,20 @@ add_consecutive_vertices(int start, int num_vertices) {
   if (cdata->_got_minmax) {
     cdata->_min_vertex = min(cdata->_min_vertex, short_start);
     cdata->_max_vertex = max(cdata->_max_vertex, short_end);
+
+    if (get_num_vertices_per_primitive() == 0) {
+      // Complex primitives also update their per-primitive minmax.
+      size_t pi = cdata->_ends.size();
+      if (pi < cdata->_mins.size()) {
+        cdata->_mins[pi] = min(cdata->_mins[pi], short_start);
+        cdata->_maxs[pi] = max(cdata->_maxs[pi], short_end);
+      } else {
+        cdata->_mins.push_back(short_start);
+        cdata->_maxs.push_back(short_end);
+      }
+      nassertv((cdata->_mins.size() == cdata->_ends.size() + 1) &&
+               (cdata->_maxs.size() == cdata->_ends.size() + 1));
+    }
   }
 }
 
@@ -156,6 +184,11 @@ close_primitive() {
 #endif
     cdata->_ends.push_back((int)cdata->_vertices.size());
 
+    if (cdata->_got_minmax) {
+      nassertv((cdata->_mins.size() == cdata->_ends.size()) &&
+               (cdata->_maxs.size() == cdata->_ends.size()));
+    }
+
   } else {
     // This is a simple primitive type like a triangle: each primitive
     // uses the same number of vertices.  Assert that we added the
@@ -177,6 +210,9 @@ clear_vertices() {
   cdata->_vertices.clear();
   cdata->_rotated_vertices.clear();
   cdata->_ends.clear();
+  cdata->_mins.clear();
+  cdata->_maxs.clear();
+  cdata->_got_minmax = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -192,6 +228,7 @@ modify_vertices() {
   clear_cache();
   CDWriter cdata(_cycler);
   cdata->_rotated_vertices.clear();
+  cdata->_got_minmax = false;
   return cdata->_vertices;
 }
 
@@ -203,11 +240,12 @@ modify_vertices() {
 //               the ends list with set_ends() at the same time.
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
-set_vertices(PTA_ushort vertices) {
+set_vertices(CPTA_ushort vertices) {
   clear_cache();
   CDWriter cdata(_cycler);
-  cdata->_vertices = vertices;
+  cdata->_vertices = (PTA_ushort &)vertices;
   cdata->_rotated_vertices.clear();
+  cdata->_got_minmax = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -226,6 +264,8 @@ PTA_int qpGeomPrimitive::
 modify_ends() {
   clear_cache();
   CDWriter cdata(_cycler);
+  cdata->_rotated_vertices.clear();
+  cdata->_got_minmax = false;
   return cdata->_ends;
 }
 
@@ -242,10 +282,12 @@ modify_ends() {
 //               have the same number of vertices, it is not needed.
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
-set_ends(PTA_int ends) {
+set_ends(CPTA_int ends) {
   clear_cache();
   CDWriter cdata(_cycler);
-  cdata->_ends = ends;
+  cdata->_ends = (PTA_int &)ends;
+  cdata->_rotated_vertices.clear();
+  cdata->_got_minmax = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -257,7 +299,7 @@ set_ends(PTA_int ends) {
 int qpGeomPrimitive::
 get_num_bytes() const {
   CDReader cdata(_cycler);
-  return cdata->_vertices.size() * sizeof(short) +
+  return (cdata->_vertices.size() + cdata->_mins.size() + cdata->_maxs.size()) * sizeof(short) +
     cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive);
 }
 
@@ -633,10 +675,54 @@ recompute_minmax() {
   if (cdata->_vertices.empty()) {
     cdata->_min_vertex = 0;
     cdata->_max_vertex = 0;
+    cdata->_mins.clear();
+    cdata->_maxs.clear();
+
+  } else if (get_num_vertices_per_primitive() == 0) {
+    // This is a complex primitive type like a triangle strip; compute
+    // the minmax of each primitive (as well as the overall minmax).
+    cdata->_mins = PTA_ushort::empty_array(cdata->_ends.size());
+    cdata->_maxs = PTA_ushort::empty_array(cdata->_ends.size());
+    
+    int pi = 0;
+    int vi = 0;
+    int num_vertices = (int)cdata->_vertices.size();
+    
+    unsigned short vertex = cdata->_vertices[vi];
+    cdata->_min_vertex = vertex;
+    cdata->_mins[pi] = vertex;
+    cdata->_max_vertex = vertex;
+    cdata->_maxs[pi] = vertex;
+    
+    ++vi;
+    while (vi < num_vertices) {
+      unsigned short vertex = cdata->_vertices[vi];
+      cdata->_min_vertex = min(cdata->_min_vertex, vertex);
+      cdata->_max_vertex = max(cdata->_max_vertex, vertex);
+      
+      if (vi == cdata->_ends[pi]) {
+        ++pi;
+        if (pi < (int)cdata->_ends.size()) {
+          cdata->_mins[pi] = vertex;
+          cdata->_maxs[pi] = vertex;
+        }
+      } else {
+        nassertv(pi < (int)cdata->_ends.size());
+        cdata->_mins[pi] = min(cdata->_mins[pi], vertex);
+        cdata->_maxs[pi] = max(cdata->_maxs[pi], vertex);
+      }
+      
+      ++vi;
+    }
+
   } else {
+    // This is a simple primitive type like a triangle; just compute
+    // the overall minmax.
     PTA_ushort::const_iterator ii = cdata->_vertices.begin();
     cdata->_min_vertex = (*ii);
     cdata->_max_vertex = (*ii);
+    cdata->_mins.clear();
+    cdata->_maxs.clear();
     
     ++ii;
     while (ii != cdata->_vertices.end()) {

+ 25 - 4
panda/src/gobj/qpgeomPrimitive.h

@@ -68,8 +68,22 @@ PUBLISHED:
   virtual PT(qpGeomPrimitive) make_copy() const=0;
 
   enum ShadeModel {
-    SM_smooth,
-    SM_uniform,
+    // SM_smooth: vertices within a single face have different
+    // colors/normals that should be smoothed across the face.  This
+    // primitive should be rendered with SmoothModelAttrib::M_smooth.
+    SM_smooth,  
+
+    // SM_uniform: all vertices across all faces have the same colors
+    // and normals.  It doesn't matter which ShadeModelAttrib mode is
+    // used to render this primitive.
+    SM_uniform, 
+
+    // SM_flat_(first,last)_vertex: each face within the primitive
+    // might have a different color/normal than the other faces, but
+    // across a particular face there is only one color/normal.  Each
+    // face's color/normal is taken from the (first, last) vertex of
+    // the face.  This primitive should be rendered with
+    // SmoothModelAttrib::M_flat.
     SM_flat_first_vertex,
     SM_flat_last_vertex,
   };
@@ -88,16 +102,21 @@ PUBLISHED:
   INLINE CPTA_ushort get_flat_first_vertices() const;
   INLINE CPTA_ushort get_flat_last_vertices() const;
   PTA_ushort modify_vertices();
-  void set_vertices(PTA_ushort vertices);
+  void set_vertices(CPTA_ushort vertices);
 
   INLINE CPTA_int get_ends() const;
   PTA_int modify_ends();
-  void set_ends(PTA_int ends);
+  void set_ends(CPTA_int ends);
+
+  INLINE CPTA_ushort get_mins() const;
+  INLINE CPTA_ushort get_maxs() const;
 
   int get_num_bytes() const;
 
   INLINE int get_min_vertex() const;
+  INLINE int get_min_vertex(int i) const;
   INLINE int get_max_vertex() const;
+  INLINE int get_max_vertex(int i) const;
 
   virtual int get_num_vertices_per_primitive() const;
   virtual int get_min_num_vertices_per_primitive() const;
@@ -146,6 +165,8 @@ private:
     PTA_ushort _vertices;
     CPTA_ushort _rotated_vertices;
     PTA_int _ends;
+    PTA_ushort _mins;
+    PTA_ushort _maxs;
 
     bool _got_minmax;
     unsigned short _min_vertex;

+ 13 - 0
panda/src/gobj/qpgeomVertexData.I

@@ -28,6 +28,19 @@ get_format() const {
   return _format;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::set_num_vertices
+//       Access: Published
+//  Description: Sets the length of the array to n vertices in all of
+//               the various arrays (presumably by adding vertices).
+//               The new vertex data is uninitialized.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexData::
+set_num_vertices(int n) {
+  CDWriter cdata(_cycler);
+  do_set_num_vertices(n, cdata);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::get_num_arrays
 //       Access: Published

+ 51 - 53
panda/src/gobj/qpgeomVertexData.cxx

@@ -18,14 +18,14 @@
 
 #include "qpgeomVertexData.h"
 #include "qpgeomVertexCacheManager.h"
+#include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "pset.h"
 
 TypeHandle qpGeomVertexData::_type_handle;
 
-// Temporarily not a member of the class.
-static PStatCollector _munge_pcollector("Cull:Munge:Data");
+PStatCollector qpGeomVertexData::_munge_data_pcollector("Cull:Munge:Data");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::Default Constructor
@@ -128,55 +128,6 @@ get_num_vertices() const {
   return cdata->_arrays[0].size() / stride;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexData::set_num_vertices
-//       Access: Published
-//  Description: Sets the length of the array to n vertices in all of
-//               the various arrays (presumably by adding vertices).
-//               The new vertex data is uninitialized.
-////////////////////////////////////////////////////////////////////
-void qpGeomVertexData::
-set_num_vertices(int n) {
-  CDWriter cdata(_cycler);
-  nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
-
-  bool any_changed = false;
-
-  for (size_t i = 0; i < cdata->_arrays.size(); i++) {
-    int stride = _format->get_array(i)->get_stride();
-    int delta = n - (cdata->_arrays[i].size() / stride);
-
-    if (delta != 0) {
-      any_changed = true;
-      if (cdata->_arrays[i].get_ref_count() > 1) {
-        // Copy-on-write: the array is already reffed somewhere else,
-        // so we're just going to make a copy.
-        PTA_uchar new_array;
-        new_array.reserve(n * stride);
-        new_array.insert(new_array.end(), n * stride, uchar());
-        memcpy(new_array, cdata->_arrays[i], 
-               min((size_t)(n * stride), cdata->_arrays[i].size()));
-        cdata->_arrays[i] = new_array;
-
-      } else {
-        // We've got the only reference to the array, so we can change
-        // it directly.
-        if (delta > 0) {
-          cdata->_arrays[i].insert(cdata->_arrays[i].end(), delta * stride, uchar());
-          
-        } else {
-          cdata->_arrays[i].erase(cdata->_arrays[i].begin() + n * stride, 
-                                  cdata->_arrays[i].end());
-        }
-      }
-    }
-  }
-
-  if (any_changed) {
-    clear_cache();
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::clear_vertices
 //       Access: Published
@@ -304,7 +255,7 @@ convert_to(const qpGeomVertexFormat *new_format) const {
     gobj_cat.debug()
       << "Converting " << num_vertices << " vertices.\n";
   }
-  PStatTimer timer(_munge_pcollector);
+  PStatTimer timer(_munge_data_pcollector);
 
   PT(qpGeomVertexData) new_data = new qpGeomVertexData(new_format);
 
@@ -449,7 +400,8 @@ set_data(int array, const qpGeomVertexDataType *data_type,
     int array_size = (int)cdata->_arrays[array].size();
     if (element + data_type->get_total_bytes() > array_size) {
       // Whoops, we need more vertices!
-      set_num_vertices(vertex + 1);
+      CDWriter cdataw(_cycler, cdata);
+      do_set_num_vertices(vertex + 1, cdataw);
     }
   }
 
@@ -755,6 +707,52 @@ remove_cache_entry(const qpGeomVertexFormat *modifier) const {
   ((qpGeomVertexData *)this)->_cycler.release_write_stage(0, cdata);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::do_set_num_vertices
+//       Access: Private
+//  Description: The private implementation of set_num_vertices().
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+do_set_num_vertices(int n, CDWriter &cdata) {
+  nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
+
+  bool any_changed = false;
+
+  for (size_t i = 0; i < cdata->_arrays.size(); i++) {
+    int stride = _format->get_array(i)->get_stride();
+    int delta = n - (cdata->_arrays[i].size() / stride);
+
+    if (delta != 0) {
+      any_changed = true;
+      if (cdata->_arrays[i].get_ref_count() > 1) {
+        // Copy-on-write: the array is already reffed somewhere else,
+        // so we're just going to make a copy.
+        PTA_uchar new_array;
+        new_array.reserve(n * stride);
+        new_array.insert(new_array.end(), n * stride, uchar());
+        memcpy(new_array, cdata->_arrays[i], 
+               min((size_t)(n * stride), cdata->_arrays[i].size()));
+        cdata->_arrays[i] = new_array;
+
+      } else {
+        // We've got the only reference to the array, so we can change
+        // it directly.
+        if (delta > 0) {
+          cdata->_arrays[i].insert(cdata->_arrays[i].end(), delta * stride, uchar());
+          
+        } else {
+          cdata->_arrays[i].erase(cdata->_arrays[i].begin() + n * stride, 
+                                  cdata->_arrays[i].end());
+        }
+      }
+    }
+  }
+
+  if (any_changed) {
+    clear_cache();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::register_with_read_factory
 //       Access: Public, Static

+ 7 - 1
panda/src/gobj/qpgeomVertexData.h

@@ -28,6 +28,7 @@
 #include "cycleDataReader.h"
 #include "cycleDataWriter.h"
 #include "pipelineCycler.h"
+#include "pStatCollector.h"
 #include "pointerTo.h"
 #include "pmap.h"
 #include "pvector.h"
@@ -69,7 +70,7 @@ PUBLISHED:
   INLINE const qpGeomVertexFormat *get_format() const;
 
   int get_num_vertices() const;
-  void set_num_vertices(int n);
+  INLINE void set_num_vertices(int n);
   void clear_vertices();
 
   INLINE int get_num_arrays() const;
@@ -137,6 +138,11 @@ private:
   typedef CycleDataReader<CData> CDReader;
   typedef CycleDataWriter<CData> CDWriter;
 
+private:
+  void do_set_num_vertices(int n, CDWriter &cdata);
+
+  static PStatCollector _munge_data_pcollector;
+
 public:
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);

+ 2 - 1
panda/src/pstatclient/pStatProperties.cxx

@@ -126,7 +126,7 @@ static TimeCollectorProperties time_properties[] = {
   { 1, "Cull:Show fps",                    { 0.5, 0.8, 1.0 } },
   { 1, "Cull:Bins",                        { 0.3, 0.6, 0.3 } },
   { 1, "Cull:Munge",                       { 0.3, 0.3, 0.9 } },
-  { 1, "Cull:Rotate",                      { 0.9, 0.8, 0.5 } },
+  { 1, "Cull:Munge:Data"                   { 0.7, 0.5, 0.2 } },
   { 1, "Draw",                             { 1.0, 0.0, 0.0 },  1.0 / 30.0 },
   { 1, "Draw:Make current",                { 0.4, 0.2, 0.6 } },
   { 1, "Draw:Copy texture",                { 0.2, 0.6, 0.4 } },
@@ -138,6 +138,7 @@ static TimeCollectorProperties time_properties[] = {
   { 1, "Draw:Flip:End",                    { 0.9, 0.3, 0.6 } },
   { 1, "Draw:Bins",                        { 0.3, 0.6, 0.0 } },
   { 0, "Draw:Primitive",                   { 0.0, 0.0, 0.5 } },
+  { 1, "Draw:Rotate",                      { 0.9, 0.8, 0.5 } },
   { 0, NULL }
 };