Browse Source

gl vertex animation

David Rose 21 years ago
parent
commit
b31d8eadd7

+ 2 - 2
panda/src/dxgsg8/dxIndexBufferContext8.cxx

@@ -90,8 +90,8 @@ upload_data() {
 
   int data_size = get_data()->get_data_size_bytes();
   
-  if (dxgsg8_cat.is_debug()) {
-    dxgsg8_cat.debug()
+  if (dxgsg8_cat.is_spam()) {
+    dxgsg8_cat.spam()
       << "copying " << data_size
       << " bytes into index buffer " << _ibuffer << "\n";
   }

+ 2 - 2
panda/src/dxgsg8/dxVertexBufferContext8.cxx

@@ -185,8 +185,8 @@ upload_data() {
 
   int data_size = get_data()->get_data_size_bytes();
   
-  if (dxgsg8_cat.is_debug()) {
-    dxgsg8_cat.debug()
+  if (dxgsg8_cat.is_spam()) {
+    dxgsg8_cat.spam()
       << "copying " << data_size
       << " bytes into vertex buffer " << _vbuffer << "\n";
   }

+ 33 - 0
panda/src/glstuff/glGeomMunger_src.cxx

@@ -65,6 +65,39 @@ munge_format_impl(const qpGeomVertexFormat *orig,
        qpGeomVertexColumn::C_color, color_type->get_start());
   }
 
+  if (animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_hardware &&
+      animation.get_num_transforms() > 0) {
+    // If we want hardware animation, we need to reserve space for the
+    // blend weights.
+
+    PT(qpGeomVertexArrayFormat) new_array_format = new qpGeomVertexArrayFormat;
+    new_array_format->add_column
+      (InternalName::get_transform_weight(), animation.get_num_transforms() - 1,
+       qpGeomVertexColumn::NT_float32, qpGeomVertexColumn::C_other);
+
+    if (animation.get_indexed_transforms()) {
+      // Also, if we'll be indexing into the transform palette, reserve
+      // space for the index.
+
+      // TODO: We should examine the maximum palette index so we can
+      // decide whether we need 16-bit indices.  That implies saving
+      // the maximum palette index, presumably in the AnimationSpec.
+      new_array_format->add_column
+        (InternalName::get_transform_index(), animation.get_num_transforms(),
+         qpGeomVertexColumn::NT_uint8, qpGeomVertexColumn::C_index);
+    }                                    
+
+    // Make sure the old weights and indices are removed, just in
+    // case.
+    new_format->remove_column(InternalName::get_transform_weight());
+    new_format->remove_column(InternalName::get_transform_index());
+
+    // And we don't need the transform_blend table any more.
+    new_format->remove_column(InternalName::get_transform_blend());
+
+    new_format->add_array(new_array_format);
+  }
+
   /*
   if (true) {
     // Split out the interleaved array into n parallel arrays.

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

@@ -364,12 +364,78 @@ reset() {
   get_extra_extensions();
   report_extensions();
 
+  _supports_vertex_blend = has_extension("GL_ARB_vertex_blend");
+
+  if (_supports_vertex_blend) {
+    _glWeightPointerARB = (PFNGLWEIGHTPOINTERARBPROC)
+      get_extension_func(GLPREFIX_QUOTED, "WeightPointerARB");
+    _glVertexBlendARB = (PFNGLVERTEXBLENDARBPROC)
+      get_extension_func(GLPREFIX_QUOTED, "VertexBlendARB");
+
+    if (_glWeightPointerARB == NULL || _glVertexBlendARB == NULL) {
+      GLCAT.warning()
+        << "Vertex blending advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
+      _supports_vertex_blend = false;
+    }
+  }
+
+  if (_supports_vertex_blend) {
+    GLP(Enable)(GL_WEIGHT_SUM_UNITY_ARB);
+
+    GLint max_vertex_units;
+    GLP(GetIntegerv)(GL_MAX_VERTEX_UNITS_ARB, &max_vertex_units);
+    _max_vertex_transforms = max_vertex_units;
+    GLCAT.debug()
+      << "max vertex transforms = " << _max_vertex_transforms << "\n";
+  }
+
+  _supports_matrix_palette = has_extension("GL_ARB_matrix_palette");
+
+  if (_supports_matrix_palette) {
+    _glCurrentPaletteMatrixARB = (PFNGLCURRENTPALETTEMATRIXARBPROC)
+      get_extension_func(GLPREFIX_QUOTED, "CurrentPaletteMatrixARB");
+    _glMatrixIndexPointerARB = (PFNGLMATRIXINDEXPOINTERARBPROC)
+      get_extension_func(GLPREFIX_QUOTED, "MatrixIndexPointerARB");
+
+    if (_glCurrentPaletteMatrixARB == NULL || _glMatrixIndexPointerARB == NULL) {
+      GLCAT.warning()
+        << "Matrix palette advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
+      _supports_matrix_palette = false;
+    }
+  }
+
+  /*
+    The matrix_palette support in this module is completely untested
+    (because I don't happen to have a card handy whose driver supports
+    this extension), so I have this ConfigVariable set to
+    unconditionally set this flag off for now, to protect the unwary.
+    When we have shown that the code works, we should remove this bit.
+    In the meantime, you must put both "matrix-palette 1" and
+    "gl-matrix-palette 1" in your Config.prc to exercise the new
+    code. */
+  if (!ConfigVariableBool("gl-matrix-palette", false, PRC_DESC("Temporary hack variable protecting untested code.  See glGraphicsStateGuardian_src.cxx."))) {
+    if (_supports_matrix_palette) {
+      GLCAT.debug() << "Forcing off matrix palette support.\n";
+    }
+    _supports_matrix_palette = false;
+  }
+
+  if (_supports_matrix_palette) {
+    GLint max_palette_matrices;
+    GLP(GetIntegerv)(GL_MAX_PALETTE_MATRICES_ARB, &max_palette_matrices);
+    _max_vertex_transform_indices = max_palette_matrices;
+    GLCAT.debug()
+      << "max vertex transform indices = " << _max_vertex_transform_indices << "\n";
+  }
+
+  _supports_draw_range_elements = false;
+
   if (is_at_least_version(1, 2)) {
     _supports_draw_range_elements = true;
     _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)
       get_extension_func(GLPREFIX_QUOTED, "DrawRangeElements");
 
-  } else if (has_extension("EXT_draw_range_elements")) {
+  } else if (has_extension("GL_EXT_draw_range_elements")) {
     _supports_draw_range_elements = true;
     _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)
       get_extension_func(GLPREFIX_QUOTED, "DrawRangeElementsEXT");
@@ -721,6 +787,9 @@ reset() {
   _auto_antialias_mode = false;
   _render_mode = RenderModeAttrib::M_filled;
 
+  _transform_stale = false;
+  _vertex_blending_enabled = false;
+
   report_my_gl_errors();
 
   // Make sure the GL state matches all of our initial attribute
@@ -2084,9 +2153,93 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
     }
   }
 
+  const qpGeomVertexAnimationSpec &animation = 
+    vertex_data->get_format()->get_animation();
+  bool hardware_animation = (animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_hardware);
+  if (hardware_animation) {
+    // Set up the transform matrices for vertex blending.
+    GLP(Enable)(GL_VERTEX_BLEND_ARB);
+    _glVertexBlendARB(animation.get_num_transforms() - 1);
+    
+    const TransformPalette *palette = vertex_data->get_transform_palette();
+    if (palette != (TransformPalette *)NULL) {
+      if (animation.get_indexed_transforms()) {
+        // We are loading the indexed matrix palette.  The ARB decided
+        // to change this interface from that for the list of
+        // nonindexed matrices, to make it easier to load an arbitrary
+        // number of matrices.
+        GLP(Enable)(GL_MATRIX_PALETTE_ARB);
+
+        GLP(MatrixMode)(GL_MATRIX_PALETTE_ARB);
+
+        for (int i = 0; i < palette->get_num_transforms(); ++i) {
+          LMatrix4f mat;
+          palette->get_transform(i)->mult_matrix(mat, _transform->get_mat());
+          _glCurrentPaletteMatrixARB(i);
+          GLP(LoadMatrixf)(mat.get_data());
+        }
+
+        // Presumably loading the matrix palette does not step on the
+        // GL_MODELVIEW matrix?
+
+      } else {
+        // We are loading the list of nonindexed matrices.  This is a
+        // little clumsier.
+
+        if (_supports_matrix_palette) {
+          GLP(Disable)(GL_MATRIX_PALETTE_ARB);
+        }
+
+        // GL_MODELVIEW0 and 1 are different than the rest.
+        int i = 0;
+        if (i < palette->get_num_transforms()) {
+          LMatrix4f mat;
+          palette->get_transform(i)->mult_matrix(mat, _transform->get_mat());
+          GLP(MatrixMode)(GL_MODELVIEW0_ARB);
+          GLP(LoadMatrixf)(mat.get_data());
+          ++i;
+        }
+        if (i < palette->get_num_transforms()) {
+          LMatrix4f mat;
+          palette->get_transform(i)->mult_matrix(mat, _transform->get_mat());
+          GLP(MatrixMode)(GL_MODELVIEW1_ARB);
+          GLP(LoadMatrixf)(mat.get_data());
+          ++i;
+        }
+        while (i < palette->get_num_transforms()) {
+          LMatrix4f mat;
+          palette->get_transform(i)->mult_matrix(mat, _transform->get_mat());
+          GLP(MatrixMode)(GL_MODELVIEW2_ARB + i - 2);
+          GLP(LoadMatrixf)(mat.get_data());
+          ++i;
+        }
+        
+        // Setting the GL_MODELVIEW0 matrix steps on the world matrix,
+        // so we have to set a flag to reload the world matrix later.
+        _transform_stale = true;
+      }
+    }
+    _vertex_blending_enabled = true;
+    
+  } else {
+    // We're not using vertex blending.
+    if (_vertex_blending_enabled) {
+      GLP(Disable)(GL_VERTEX_BLEND_ARB);
+      if (_supports_matrix_palette) {
+        GLP(Disable)(GL_MATRIX_PALETTE_ARB);
+      }
+      _vertex_blending_enabled = false;
+    }
+
+    if (_transform_stale) {
+      GLP(MatrixMode)(GL_MODELVIEW);
+      GLP(LoadMatrixf)(_transform->get_mat().get_data());
+    }
+  }
+
   if (geom->get_usage_hint() == qpGeomUsageHint::UH_static && 
       _vertex_data->get_usage_hint() == qpGeomUsageHint::UH_static &&
-      display_lists) {
+      display_lists && (!hardware_animation || display_list_animation)) {
     // If the geom claims to be totally static, try to build it into
     // a display list.
     GeomContext *gc = ((qpGeom *)geom)->prepare_now(get_prepared_objects(), this);
@@ -2105,8 +2258,10 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
 #ifdef DO_PSTATS
       _vertices_display_list_pcollector.add_level(ggc->_num_verts);
 #endif
-      
+
       // And now we don't need to do anything else for this geom.
+      _geom_display_list = 0;
+      end_draw_primitives();
       return false;
     }
     
@@ -2218,6 +2373,42 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
   }
   _last_max_stage_index = max_stage_index;
 
+  if (_supports_vertex_blend) {
+    if (hardware_animation) {
+      // Issue the weights and/or transform indices for vertex blending.
+      if (_vertex_data->get_array_info(InternalName::get_transform_weight(),
+                                       array_data, num_values, numeric_type, 
+                                       start, stride)) {
+        const unsigned char *client_pointer = setup_array_data(array_data);
+        _glWeightPointerARB(num_values, get_numeric_type(numeric_type), 
+                            stride, client_pointer + start);
+        GLP(EnableClientState)(GL_WEIGHT_ARRAY_ARB);
+      } else {
+        GLP(DisableClientState)(GL_WEIGHT_ARRAY_ARB);
+      }
+
+      if (animation.get_indexed_transforms()) {
+        // Issue the matrix palette indices.
+        if (_vertex_data->get_array_info(InternalName::get_transform_index(),
+                                         array_data, num_values, numeric_type, 
+                                         start, stride)) {
+          const unsigned char *client_pointer = setup_array_data(array_data);
+          _glMatrixIndexPointerARB(num_values, get_numeric_type(numeric_type), 
+                              stride, client_pointer + start);
+          GLP(EnableClientState)(GL_MATRIX_INDEX_ARRAY_ARB);
+        } else {
+          GLP(DisableClientState)(GL_MATRIX_INDEX_ARRAY_ARB);
+        }
+      }
+
+    } else {
+      GLP(DisableClientState)(GL_WEIGHT_ARRAY_ARB);
+      if (_supports_matrix_palette) {
+        GLP(DisableClientState)(GL_MATRIX_INDEX_ARRAY_ARB);
+      }
+    }
+  }
+
   return true;
 }
 
@@ -2336,6 +2527,20 @@ end_draw_primitives() {
   }
   _geom_display_list = 0;
 
+  // Clean up the vertex blending state.
+  if (_vertex_blending_enabled) {
+    GLP(Disable)(GL_VERTEX_BLEND_ARB);
+    if (_supports_matrix_palette) {
+      GLP(Disable)(GL_MATRIX_PALETTE_ARB);
+    }
+    _vertex_blending_enabled = false;
+  }
+  
+  if (_transform_stale) {
+    GLP(MatrixMode)(GL_MODELVIEW);
+    GLP(LoadMatrixf)(_transform->get_mat().get_data());
+  }
+
   GraphicsStateGuardian::end_draw_primitives();
 }
 
@@ -2585,8 +2790,8 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
   
   add_to_vertex_buffer_record(gvbc);
   if (gvbc->was_modified()) {
-    if (GLCAT.is_debug()) {
-      GLCAT.debug()
+    if (GLCAT.is_spam()) {
+      GLCAT.spam()
         << "copying " << gvbc->get_data()->get_data_size_bytes()
         << " bytes into vertex buffer " << gvbc->_index << "\n";
     }
@@ -2716,8 +2921,8 @@ apply_index_buffer(IndexBufferContext *ibc) {
   
   add_to_index_buffer_record(gibc);
   if (gibc->was_modified()) {
-    if (GLCAT.is_debug()) {
-      GLCAT.debug()
+    if (GLCAT.is_spam()) {
+      GLCAT.spam()
         << "copying " << gibc->get_data()->get_data_size_bytes()
         << " bytes into index buffer " << gibc->_index << "\n";
     }
@@ -3081,6 +3286,7 @@ issue_transform(const TransformState *transform) {
   DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1));
   GLP(MatrixMode)(GL_MODELVIEW);
   GLP(LoadMatrixf)(transform->get_mat().get_data());
+  _transform_stale = false;
 
   _transform = transform;
   if (_auto_rescale_normal) {

+ 11 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -314,6 +314,9 @@ protected:
   bool _auto_antialias_mode;
   RenderModeAttrib::Mode _render_mode;
 
+  bool _transform_stale;
+  bool _vertex_blending_enabled;
+
   CPT(DisplayRegion) _actual_display_region;
 #ifdef HAVE_CGGL
   PT(CgShader) _cg_shader; // The current CgShader object
@@ -332,6 +335,14 @@ protected:
   pset<string> _extensions;
 
 public:
+  bool _supports_vertex_blend;
+  PFNGLWEIGHTPOINTERARBPROC _glWeightPointerARB;
+  PFNGLVERTEXBLENDARBPROC _glVertexBlendARB;
+
+  bool _supports_matrix_palette;
+  PFNGLCURRENTPALETTEMATRIXARBPROC _glCurrentPaletteMatrixARB;
+  PFNGLMATRIXINDEXPOINTERARBPROC _glMatrixIndexPointerARB;
+
   bool _supports_draw_range_elements;
   PFNGLDRAWRANGEELEMENTSPROC _glDrawRangeElements;
 

+ 19 - 9
panda/src/gobj/config_gobj.cxx

@@ -99,16 +99,17 @@ ConfigVariableBool retained_mode
           "in the experimental Geom rewrite."));
 
 ConfigVariableBool vertex_buffers
-("vertex-buffers", false,
+("vertex-buffers", true,
  PRC_DESC("Set this true to allow the use of vertex buffers (or buffer "
           "objects, as OpenGL dubs them) for rendering vertex data.  This "
-          "can greatly improve rendering performance, especially on "
+          "can greatly improve rendering performance on "
           "higher-end graphics cards, at the cost of some additional "
           "graphics memory (which might otherwise be used for textures "
-          "or offscreen buffers)."));
+          "or offscreen buffers).  On lower-end graphics cards this will "
+          "make little or no difference."));
 
 ConfigVariableBool display_lists
-("display-lists", false,
+("display-lists", true,
  PRC_DESC("Set this true to allow the use of OpenGL display lists for "
           "rendering static geometry.  On some systems, this can result "
           "in a performance improvement over vertex buffers alone; on "
@@ -118,7 +119,7 @@ ConfigVariableBool display_lists
           "on dynamic geometry (e.g. soft-skinned animation)."));
 
 ConfigVariableBool hardware_animated_vertices
-("hardware-animated-vertices", false,
+("hardware-animated-vertices", true,
  PRC_DESC("Set this true to allow the transforming of soft-skinned "
           "animated vertices via hardware, if supported, or false always "
           "to perform the vertex animation via software within Panda.  "
@@ -132,16 +133,25 @@ ConfigVariableBool hardware_animated_vertices
 ConfigVariableBool matrix_palette
 ("matrix-palette", false,
  PRC_DESC("Set this true to allow the use of the matrix palette when "
-          "animating vertices in hardware (if hardware-animated-vertices "
-          "is also true).  The matrix palette is not supported by all "
-          "devices, but if it is, using it can allow animation of more "
-          "sophisticated meshes in hardware, and it can also improve the "
+          "animating vertices in hardware.  The matrix palette is "
+          "not supported by all devices, but if it is, using "
+          "it can allow animation of more sophisticated meshes "
+          "in hardware, and it can also improve the "
           "performance of animating some simpler meshes.  Without "
           "this option, certain meshes will have to be animated in "
           "software.  However, this option is not enabled by default, "
           "because its support seems to be buggy in certain drivers "
           "(ATI FireGL T2 8.103 in particular.)"));
 
+ConfigVariableBool display_list_animation
+("display-list-animation", false,
+ PRC_DESC("Set this true to allow the use of OpenGL display lists for "
+          "rendering animated geometry (when the geometry is animated "
+          "by the hardware).  This is not on by default because there "
+          "appear to be some driver issues with this on my FireGL T2, "
+          "but it should be perfectly doable in principle, and might get "
+          "you a small performance boost."));
+
 ConfigVariableBool connect_triangle_strips
 ("connect-triangle-strips", true,
  PRC_DESC("Set this true to set a batch of triangle strips to the graphics "

+ 1 - 0
panda/src/gobj/config_gobj.h

@@ -55,6 +55,7 @@ extern EXPCL_PANDA ConfigVariableBool vertex_buffers;
 extern EXPCL_PANDA ConfigVariableBool display_lists;
 extern EXPCL_PANDA ConfigVariableBool hardware_animated_vertices;
 extern EXPCL_PANDA ConfigVariableBool matrix_palette;
+extern EXPCL_PANDA ConfigVariableBool display_list_animation;
 extern EXPCL_PANDA ConfigVariableBool connect_triangle_strips;
 
 extern EXPCL_PANDA ConfigVariableBool use_qpgeom;