Przeglądaj źródła

Simplify oddly redundant StencilAttrib implementation.
Also add RenderState::compare_mask().

rdb 11 lat temu
rodzic
commit
0473fa7ead

+ 0 - 3
panda/src/display/Sources.pp

@@ -43,7 +43,6 @@
     windowHandle.I windowHandle.h \
     windowProperties.I windowProperties.h \
     renderBuffer.h \
-    stencilRenderStates.h \
     stereoDisplayRegion.I stereoDisplayRegion.h \
     displaySearchParameters.h \
     displayInformation.h \
@@ -80,7 +79,6 @@
     parasiteBuffer.cxx \
     windowHandle.cxx \
     windowProperties.cxx \
-    stencilRenderStates.cxx \
     stereoDisplayRegion.cxx \
     subprocessWindow.cxx \
     touchInfo.cxx
@@ -118,7 +116,6 @@
     windowHandle.I windowHandle.h \
     windowProperties.I windowProperties.h \
     renderBuffer.h \
-    stencilRenderStates.h \
     stereoDisplayRegion.I stereoDisplayRegion.h \
     subprocessWindow.h subprocessWindow.I \
     subprocessWindowBuffer.h subprocessWindowBuffer.I \

+ 0 - 13
panda/src/display/graphicsStateGuardian.cxx

@@ -258,8 +258,6 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   // it is rendered.
   _runtime_color_scale = false;
 
-  _stencil_render_states = 0;
-
   // The default is no shader support.
   _auto_detect_shader_model = SM_00;
   _shader_model = SM_00;
@@ -279,11 +277,6 @@ GraphicsStateGuardian::
 ~GraphicsStateGuardian() {
   remove_gsg(this);
 
-  if (_stencil_render_states) {
-    delete _stencil_render_states;
-    _stencil_render_states = 0;
-  }
-
   if (_shader_generator) {
     delete _shader_generator;
     _shader_generator = 0;
@@ -1988,12 +1981,6 @@ reset() {
   _last_max_stage_index = 0;
 
   _is_valid = true;
-
-  if (_stencil_render_states) {
-    delete _stencil_render_states;
-    _stencil_render_states = 0;
-  }
-  _stencil_render_states = new StencilRenderStates(this);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 3
panda/src/display/graphicsStateGuardian.h

@@ -45,7 +45,6 @@
 #include "texture.h"
 #include "occlusionQueryContext.h"
 #include "timerQueryContext.h"
-#include "stencilRenderStates.h"
 #include "loader.h"
 #include "shaderAttrib.h"
 #include "texGenAttrib.h"
@@ -532,8 +531,6 @@ protected:
 
   int  _stereo_buffer_mask;
 
-  StencilRenderStates *_stencil_render_states;
-
   int _auto_detect_shader_model;
   int _shader_model;
 

+ 0 - 1
panda/src/display/p3display_composite2.cxx

@@ -12,7 +12,6 @@
 #include "nativeWindowHandle.cxx"
 #include "parasiteBuffer.cxx"
 #include "standardMunger.cxx"
-#include "stencilRenderStates.cxx"
 #include "touchInfo.cxx"
 #include "stereoDisplayRegion.cxx"
 #include "subprocessWindow.cxx"

+ 0 - 111
panda/src/display/stencilRenderStates.cxx

@@ -1,111 +0,0 @@
-// Filename: stencilRenderStates.cxx
-// Created by:  aignacio (17May06)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-#include "graphicsStateGuardian.h"
-#include "stencilRenderStates.h"
-
-////////////////////////////////////////////////////////////////////
-//     Function: StencilRenderStates::Constructor
-//  Description: Constructor.  All data is set to the default.
-////////////////////////////////////////////////////////////////////
-StencilRenderStates::
-StencilRenderStates (GraphicsStateGuardian *gsg) {
-
-  int index;
-
-  // clear all
-  for (index = 0; index < SRS_total; index++) {
-    _stencil_render_state_array [index] = 0;
-    _stencil_function_array [index] = 0;
-  }
-
-  // set default render states
-  set_stencil_render_state (false, SRS_reference, 0);
-
-  set_stencil_render_state (false, SRS_read_mask, ~0);
-  set_stencil_render_state (false, SRS_write_mask, ~0);
-
-  set_stencil_render_state (false, SRS_front_enable, 0);
-  set_stencil_render_state (false, SRS_front_comparison_function, SCF_always);
-  set_stencil_render_state (false, SRS_front_stencil_fail_operation, SO_keep);
-  set_stencil_render_state (false, SRS_front_stencil_pass_z_fail_operation, SO_keep);
-  set_stencil_render_state (false, SRS_front_stencil_pass_z_pass_operation, SO_keep);
-
-  set_stencil_render_state (false, SRS_back_enable, 0);
-  set_stencil_render_state (false, SRS_back_comparison_function, SCF_always);
-  set_stencil_render_state (false, SRS_back_stencil_fail_operation, SO_keep);
-  set_stencil_render_state (false, SRS_back_stencil_pass_z_fail_operation, SO_keep);
-  set_stencil_render_state (false, SRS_back_stencil_pass_z_pass_operation, SO_keep);
-
-  _gsg = gsg;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: StencilRenderStates::Destructor
-//  Description:
-////////////////////////////////////////////////////////////////////
-StencilRenderStates::
-~StencilRenderStates (void) {
-
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: StencilRenderStates::set_stencil_render_state
-//  Description: Sets the current render state for the specified
-//               stencil render state. The execute_function
-//               parameter can be used to defer the actual setting
-//               of the render state at the API level.  This is
-//               useful for the OpenGL API where certain render
-//               states are not independent/atomic (i.e.
-//               glStencilFunc and glStencilOp).
-////////////////////////////////////////////////////////////////////
-void StencilRenderStates::
-set_stencil_render_state (bool execute_function, StencilRenderStates::StencilRenderState stencil_render_state, StencilType value) {
-
-  // DEBUG
-  if (false) {
-    printf ("SRS %d %d %d \n", execute_function, stencil_render_state, value);
-  }
-
-  _stencil_render_state_array [stencil_render_state] = value;
-
-  if (execute_function) {
-    StencilFunction stencil_function;
-
-    stencil_function = _stencil_function_array [stencil_render_state];
-    if (stencil_function) {
-      stencil_function (stencil_render_state, this);
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: StencilRenderStates::get_stencil_render_state
-//  Description: Gets the current render state for the specified
-//               stencil render state.
-////////////////////////////////////////////////////////////////////
-StencilType StencilRenderStates::
-get_stencil_render_state (StencilRenderStates::StencilRenderState stencil_render_state) {
-  return _stencil_render_state_array [stencil_render_state];
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: StencilRenderStates::set_stencil_function
-//  Description: Registers an API specific callback for setting a
-//               specified stencil render state.
-////////////////////////////////////////////////////////////////////
-void StencilRenderStates::
-set_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilFunction stencil_function) {
-  _stencil_function_array [stencil_render_state] = stencil_function;
-}

+ 0 - 101
panda/src/display/stencilRenderStates.h

@@ -1,101 +0,0 @@
-// Filename: stencilRenderStates.h
-// Created by:  aignacio (17May06)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef STENCILRENDERSTATES_H
-#define STENCILRENDERSTATES_H
-
-class GraphicsStateGuardian;
-typedef unsigned int StencilType;
-
-////////////////////////////////////////////////////////////////////
-//       Class : StencilRenderStates
-// Description : An abstract cross-platform class for setting stencil
-//               buffer render states.  Each gsg needs to create its
-//               own low-level API specific functions on how to set
-//               each render state. The "set_stencil_render_state"
-//               function can be used in an immediate-mode fashion.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_DISPLAY StencilRenderStates {
-
-PUBLISHED:
-  enum StencilRenderState
-  {
-    SRS_front_enable,
-    SRS_back_enable,
-
-    SRS_front_comparison_function,
-    SRS_front_stencil_fail_operation,
-    SRS_front_stencil_pass_z_fail_operation,
-    SRS_front_stencil_pass_z_pass_operation,
-
-    SRS_reference,
-    SRS_read_mask,
-    SRS_write_mask,
-
-    SRS_back_comparison_function,
-    SRS_back_stencil_fail_operation,
-    SRS_back_stencil_pass_z_fail_operation,
-    SRS_back_stencil_pass_z_pass_operation,
-
-    SRS_clear,
-    SRS_clear_value,
-
-    SRS_total,
-
-    SRS_first = 0,
-  };
-
-  enum StencilComparisonFunction
-  {
-    SCF_never,
-    SCF_less_than,
-    SCF_equal,
-    SCF_less_than_or_equal,
-    SCF_greater_than,
-    SCF_not_equal,
-    SCF_greater_than_or_equal,
-    SCF_always,
-  };
-
-  enum StencilOperation
-  {
-    SO_keep,
-    SO_zero,
-    SO_replace,
-    SO_increment,
-    SO_decrement,
-    SO_invert,
-    SO_increment_saturate,
-    SO_decrement_saturate,
-  };
-
-public:
-  typedef void (*StencilFunction) (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states);
-
-  StencilRenderStates (GraphicsStateGuardian *gsg);
-  ~StencilRenderStates (void);
-
-  void set_stencil_render_state (bool execute_function, StencilRenderStates::StencilRenderState stencil_render_state, StencilType value);
-  StencilType get_stencil_render_state (StencilRenderStates::StencilRenderState stencil_render_state);
-
-  void set_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilFunction stencil_function);
-
-  GraphicsStateGuardian *_gsg;
-
-private:
-  StencilType _stencil_render_state_array [SRS_total];
-  StencilFunction _stencil_function_array [SRS_total];
-};
-
-#endif

+ 38 - 114
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -2074,9 +2074,6 @@ reset() {
 
   PRINT_REFCNT(dxgsg8, _d3d_device);
 
-  void dx_set_stencil_functions (StencilRenderStates *stencil_render_states);
-  dx_set_stencil_functions (_stencil_render_states);
-
   // Now that the GSG has been initialized, make it available for
   // optimizations.
   add_gsg(this);
@@ -4310,9 +4307,7 @@ draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type,
 ////////////////////////////////////////////////////////////////////
 //  DX stencil code section
 ////////////////////////////////////////////////////////////////////
-
-static int dx_stencil_comparison_function_array [ ] =
-{
+static int dx_stencil_comparison_function_array[] = {
   D3DCMP_NEVER,
   D3DCMP_LESS,
   D3DCMP_EQUAL,
@@ -4323,8 +4318,7 @@ static int dx_stencil_comparison_function_array [ ] =
   D3DCMP_ALWAYS,
 };
 
-static int dx_stencil_operation_array [ ] =
-{
+static int dx_stencil_operation_array[] = {
   D3DSTENCILOP_KEEP,
   D3DSTENCILOP_ZERO,
   D3DSTENCILOP_REPLACE,
@@ -4336,84 +4330,6 @@ static int dx_stencil_operation_array [ ] =
   D3DSTENCILOP_DECRSAT,
 };
 
-void dx_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-  StencilType render_state_value;
-
-  DXGraphicsStateGuardian8 *gsg;
-  LPDIRECT3DDEVICE8 device;
-
-  gsg = (DXGraphicsStateGuardian8 *) stencil_render_states -> _gsg;
-  device = gsg->get_d3d_device();
-
-  render_state_value = stencil_render_states -> get_stencil_render_state (stencil_render_state);
-
-  if (dxgsg8_cat.is_debug()) {
-    dxgsg8_cat.debug()
-      << "SRS: " <<  StencilAttrib::stencil_render_state_name_array [stencil_render_state] << ", " << render_state_value << "\n";
-  }
-
-  switch (stencil_render_state)
-  {
-    case StencilRenderStates::SRS_front_enable:
-      device->SetRenderState (D3DRS_STENCILENABLE, render_state_value);
-      break;
-
-    case StencilRenderStates::SRS_back_enable:
-      // not supported in DX8
-      break;
-
-    case StencilRenderStates::SRS_front_comparison_function:
-      device->SetRenderState (D3DRS_STENCILFUNC, dx_stencil_comparison_function_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_front_stencil_fail_operation:
-      device->SetRenderState (D3DRS_STENCILFAIL, dx_stencil_operation_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_front_stencil_pass_z_fail_operation:
-      device->SetRenderState (D3DRS_STENCILZFAIL, dx_stencil_operation_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_front_stencil_pass_z_pass_operation:
-      device->SetRenderState (D3DRS_STENCILPASS, dx_stencil_operation_array [render_state_value]);
-      break;
-
-    case StencilRenderStates::SRS_reference:
-      device->SetRenderState (D3DRS_STENCILREF, render_state_value);
-      break;
-
-    case StencilRenderStates::SRS_read_mask:
-      device->SetRenderState (D3DRS_STENCILMASK, render_state_value);
-      break;
-    case StencilRenderStates::SRS_write_mask:
-      device->SetRenderState (D3DRS_STENCILWRITEMASK, render_state_value);
-      break;
-
-    case StencilRenderStates::SRS_back_comparison_function:
-      // not supported in DX8
-      break;
-    case StencilRenderStates::SRS_back_stencil_fail_operation:
-      // not supported in DX8
-      break;
-    case StencilRenderStates::SRS_back_stencil_pass_z_fail_operation:
-      // not supported in DX8
-      break;
-    case StencilRenderStates::SRS_back_stencil_pass_z_pass_operation:
-      // not supported in DX8
-      break;
-
-    default:
-      break;
-  }
-}
-
-void dx_set_stencil_functions (StencilRenderStates *stencil_render_states) {
-  if (stencil_render_states) {
-    StencilRenderStates::StencilRenderState stencil_render_state;
-
-    for (stencil_render_state = StencilRenderStates::SRS_first; stencil_render_state < StencilRenderStates::SRS_total; stencil_render_state = (StencilRenderStates::StencilRenderState) ((int) stencil_render_state + 1)) {
-      stencil_render_states -> set_stencil_function (stencil_render_state, dx_stencil_function);
-    }
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::do_issue_stencil
 //       Access: Protected
@@ -4421,48 +4337,56 @@ void dx_set_stencil_functions (StencilRenderStates *stencil_render_states) {
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian8::
 do_issue_stencil() {
-
   if (!_supports_stencil) {
     return;
   }
 
-  StencilRenderStates *stencil_render_states;
-  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib_def(StencilAttrib::get_class_slot()));
-  stencil_render_states = this -> _stencil_render_states;
-  if (stencil && stencil_render_states) {
+  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib(StencilAttrib::get_class_slot()));
 
-    if (dxgsg8_cat.is_debug()) {
+  if (stencil != (const StencilAttrib *)NULL) {
+    // DEBUG
+    if (false) {
       dxgsg8_cat.debug() << "STENCIL STATE CHANGE\n";
       dxgsg8_cat.debug() << "\n"
-        << "SRS_front_enable " << stencil -> get_render_state (StencilAttrib::SRS_front_enable) << "\n"
-        << "SRS_front_comparison_function " << stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function) << "\n"
-        << "SRS_front_stencil_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
-        << "SRS_front_stencil_pass_z_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
-        << "SRS_front_stencil_pass_z_pass_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
-        << "SRS_reference " << stencil -> get_render_state (StencilAttrib::SRS_reference) << "\n"
-        << "SRS_read_mask " << stencil -> get_render_state (StencilAttrib::SRS_read_mask) << "\n"
-        << "SRS_write_mask " << stencil -> get_render_state (StencilAttrib::SRS_write_mask) << "\n";
+        << "SRS_front_comparison_function " << stencil->get_render_state(StencilAttrib::SRS_front_comparison_function) << "\n"
+        << "SRS_front_stencil_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
+        << "SRS_front_stencil_pass_z_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
+        << "SRS_front_stencil_pass_z_pass_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
+        << "SRS_reference " << stencil->get_render_state(StencilAttrib::SRS_reference) << "\n"
+        << "SRS_read_mask " << stencil->get_render_state(StencilAttrib::SRS_read_mask) << "\n"
+        << "SRS_write_mask " << stencil->get_render_state(StencilAttrib::SRS_write_mask) << "\n";
     }
 
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, stencil -> get_render_state (StencilAttrib::SRS_front_enable));
-    if (stencil -> get_render_state (StencilAttrib::SRS_front_enable)) {
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_comparison_function, stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_pass_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation));
+    unsigned int front_compare;
+    front_compare = stencil->get_render_state(StencilAttrib::SRS_front_comparison_function);
+    if (front_compare != RenderAttrib::M_none) {
+      set_render_state(D3DRS_STENCILENABLE, TRUE);
+      set_render_state(D3DRS_STENCILFUNC, dx_stencil_comparison_function_array[front_compare]);
+      set_render_state(D3DRS_STENCILFAIL, dx_stencil_operation_array[
+        stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation)]);
+      set_render_state(D3DRS_STENCILZFAIL, dx_stencil_operation_array[
+        stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation)]);
+      set_render_state(D3DRS_STENCILPASS, dx_stencil_operation_array[
+        stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation)]);
+
+      set_render_state(D3DRS_STENCILREF, stencil->get_render_state(StencilAttrib::SRS_reference));
+      set_render_state(D3DRS_STENCILMASK, stencil->get_render_state(StencilAttrib::SRS_read_mask));
+      set_render_state(D3DRS_STENCILWRITEMASK, stencil->get_render_state(StencilAttrib::SRS_write_mask));
+    } else {
+      set_render_state(D3DRS_STENCILENABLE, FALSE);
+    }
 
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_reference, stencil -> get_render_state (StencilAttrib::SRS_reference));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_read_mask, stencil -> get_render_state (StencilAttrib::SRS_read_mask));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_write_mask, stencil -> get_render_state (StencilAttrib::SRS_write_mask));
+    if (stencil->get_render_state(StencilAttrib::SRS_clear)) {
+      _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0.0f, stencil->get_render_state(StencilAttrib::SRS_clear_value));
     }
-  }
-  else {
 
-    if (dxgsg8_cat.is_debug()) {
-      dxgsg8_cat.debug() << "STENCIL STATE CHANGE TO OFF \n";
+  } else {
+    // DEBUG
+    if (false) {
+      dxgsg8_cat.debug() << "STENCIL STATE CHANGE TO OFF\n";
     }
 
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, 0);
+    set_render_state(D3DRS_STENCILENABLE, FALSE);
   }
 }
 

+ 58 - 137
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -2769,9 +2769,6 @@ reset() {
 
   PRINT_REFCNT(dxgsg9, _d3d_device);
 
-  void dx_set_stencil_functions (StencilRenderStates *stencil_render_states);
-  dx_set_stencil_functions (_stencil_render_states);
-
   // Now that the GSG has been initialized, make it available for
   // optimizations.
   add_gsg(this);
@@ -5261,9 +5258,7 @@ check_dx_allocation (HRESULT result, int allocation_size, int attempts)
 ////////////////////////////////////////////////////////////////////
 //  DX stencil code section
 ////////////////////////////////////////////////////////////////////
-
-static int dx_stencil_comparison_function_array [ ] =
-{
+static int dx_stencil_comparison_function_array[] = {
   D3DCMP_NEVER,
   D3DCMP_LESS,
   D3DCMP_EQUAL,
@@ -5274,8 +5269,7 @@ static int dx_stencil_comparison_function_array [ ] =
   D3DCMP_ALWAYS,
 };
 
-static int dx_stencil_operation_array [ ] =
-{
+static int dx_stencil_operation_array[] = {
   D3DSTENCILOP_KEEP,
   D3DSTENCILOP_ZERO,
   D3DSTENCILOP_REPLACE,
@@ -5287,93 +5281,6 @@ static int dx_stencil_operation_array [ ] =
   D3DSTENCILOP_DECRSAT,
 };
 
-void dx_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-  StencilType render_state_value;
-
-  DXGraphicsStateGuardian9 *gsg;
-
-  gsg = (DXGraphicsStateGuardian9 *) stencil_render_states -> _gsg;
-
-  render_state_value = stencil_render_states -> get_stencil_render_state (stencil_render_state);
-
-  // DEBUG
-  if (false) {
-    dxgsg9_cat.debug()
-      << "SRS: " <<  StencilAttrib::stencil_render_state_name_array [stencil_render_state] << ", " << render_state_value << "\n";
-  }
-
-  switch (stencil_render_state)
-  {
-    case StencilRenderStates::SRS_front_enable:
-      gsg -> set_render_state (D3DRS_STENCILENABLE, render_state_value);
-      break;
-
-    case StencilRenderStates::SRS_back_enable:
-      if (gsg -> get_supports_two_sided_stencil()) {
-        gsg -> set_render_state (D3DRS_TWOSIDEDSTENCILMODE, render_state_value);
-      }
-      break;
-
-    case StencilRenderStates::SRS_front_comparison_function:
-      gsg -> set_render_state (D3DRS_STENCILFUNC, dx_stencil_comparison_function_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_front_stencil_fail_operation:
-      gsg -> set_render_state (D3DRS_STENCILFAIL, dx_stencil_operation_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_front_stencil_pass_z_fail_operation:
-      gsg -> set_render_state (D3DRS_STENCILZFAIL, dx_stencil_operation_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_front_stencil_pass_z_pass_operation:
-      gsg -> set_render_state (D3DRS_STENCILPASS, dx_stencil_operation_array [render_state_value]);
-      break;
-
-    case StencilRenderStates::SRS_reference:
-      gsg -> set_render_state (D3DRS_STENCILREF, render_state_value);
-      break;
-
-    case StencilRenderStates::SRS_read_mask:
-      gsg -> set_render_state (D3DRS_STENCILMASK, render_state_value);
-      break;
-    case StencilRenderStates::SRS_write_mask:
-      gsg -> set_render_state (D3DRS_STENCILWRITEMASK, render_state_value);
-      break;
-
-    case StencilRenderStates::SRS_back_comparison_function:
-      if (gsg -> get_supports_two_sided_stencil()) {
-        gsg -> set_render_state (D3DRS_CCW_STENCILFUNC, dx_stencil_comparison_function_array [render_state_value]);
-      }
-      break;
-    case StencilRenderStates::SRS_back_stencil_fail_operation:
-      if (gsg -> get_supports_two_sided_stencil()) {
-        gsg -> set_render_state (D3DRS_CCW_STENCILFAIL, dx_stencil_operation_array [render_state_value]);
-      }
-      break;
-    case StencilRenderStates::SRS_back_stencil_pass_z_fail_operation:
-      if (gsg -> get_supports_two_sided_stencil()) {
-        gsg -> set_render_state (D3DRS_CCW_STENCILZFAIL, dx_stencil_operation_array [render_state_value]);
-      }
-      break;
-    case StencilRenderStates::SRS_back_stencil_pass_z_pass_operation:
-      if (gsg -> get_supports_two_sided_stencil()) {
-        gsg -> set_render_state (D3DRS_CCW_STENCILPASS, dx_stencil_operation_array [render_state_value]);
-      }
-      break;
-
-    default:
-      break;
-  }
-}
-
-void dx_set_stencil_functions (StencilRenderStates *stencil_render_states) {
-  if (stencil_render_states) {
-    StencilRenderStates::StencilRenderState stencil_render_state;
-
-    for (stencil_render_state = StencilRenderStates::SRS_first; stencil_render_state < StencilRenderStates::SRS_total; stencil_render_state = (StencilRenderStates::StencilRenderState) ((int) stencil_render_state + 1)) {
-      stencil_render_states -> set_stencil_function (stencil_render_state, dx_stencil_function);
-    }
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian9::do_issue_stencil
 //       Access: Protected
@@ -5385,70 +5292,84 @@ do_issue_stencil() {
     return;
   }
 
-  StencilRenderStates *stencil_render_states;
-  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib_def(StencilAttrib::get_class_slot()));
-  stencil_render_states = this -> _stencil_render_states;
-  if (stencil && stencil_render_states) {
+  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib(StencilAttrib::get_class_slot()));
 
+  if (stencil != (const StencilAttrib *)NULL) {
     // DEBUG
     if (false) {
       dxgsg9_cat.debug() << "STENCIL STATE CHANGE\n";
       dxgsg9_cat.debug() << "\n"
-        << "SRS_front_enable " << stencil -> get_render_state (StencilAttrib::SRS_front_enable) << "\n"
-        << "SRS_back_enable " << stencil -> get_render_state (StencilAttrib::SRS_back_enable) << "\n"
-        << "SRS_front_comparison_function " << stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function) << "\n"
-        << "SRS_front_stencil_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
-        << "SRS_front_stencil_pass_z_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
-        << "SRS_front_stencil_pass_z_pass_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
-        << "SRS_reference " << stencil -> get_render_state (StencilAttrib::SRS_reference) << "\n"
-        << "SRS_read_mask " << stencil -> get_render_state (StencilAttrib::SRS_read_mask) << "\n"
-        << "SRS_write_mask " << stencil -> get_render_state (StencilAttrib::SRS_write_mask) << "\n"
-        << "SRS_back_comparison_function " << stencil -> get_render_state (StencilAttrib::SRS_back_comparison_function) << "\n"
-        << "SRS_back_stencil_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
-        << "SRS_back_stencil_pass_z_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
-        << "SRS_back_stencil_pass_z_pass_operation " << stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
+        << "SRS_front_comparison_function " << stencil->get_render_state(StencilAttrib::SRS_front_comparison_function) << "\n"
+        << "SRS_front_stencil_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
+        << "SRS_front_stencil_pass_z_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
+        << "SRS_front_stencil_pass_z_pass_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
+        << "SRS_reference " << stencil->get_render_state(StencilAttrib::SRS_reference) << "\n"
+        << "SRS_read_mask " << stencil->get_render_state(StencilAttrib::SRS_read_mask) << "\n"
+        << "SRS_write_mask " << stencil->get_render_state(StencilAttrib::SRS_write_mask) << "\n"
+        << "SRS_back_comparison_function " << stencil->get_render_state(StencilAttrib::SRS_back_comparison_function) << "\n"
+        << "SRS_back_stencil_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
+        << "SRS_back_stencil_pass_z_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
+        << "SRS_back_stencil_pass_z_pass_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
     }
 
-    bool on;
+    bool on = false;
 
-    on = false;
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, stencil -> get_render_state (StencilAttrib::SRS_front_enable));
-    if (stencil -> get_render_state (StencilAttrib::SRS_front_enable)) {
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_comparison_function, stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_pass_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation));
+    unsigned int front_compare;
+    front_compare = stencil->get_render_state(StencilAttrib::SRS_front_comparison_function);
+
+    if (front_compare != RenderAttrib::M_none) {
+      set_render_state(D3DRS_STENCILENABLE, TRUE);
+      set_render_state(D3DRS_STENCILFUNC, dx_stencil_comparison_function_array[front_compare]);
+      set_render_state(D3DRS_STENCILFAIL, dx_stencil_operation_array[
+        stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation)]);
+      set_render_state(D3DRS_STENCILZFAIL, dx_stencil_operation_array[
+        stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation)]);
+      set_render_state(D3DRS_STENCILPASS, dx_stencil_operation_array[
+        stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation)]);
       on = true;
+    } else {
+      set_render_state(D3DRS_STENCILENABLE, FALSE);
     }
 
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_enable, stencil -> get_render_state (StencilAttrib::SRS_back_enable));
-    if (stencil -> get_render_state (StencilAttrib::SRS_back_enable)) {
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_comparison_function, stencil -> get_render_state (StencilAttrib::SRS_back_comparison_function));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_fail_operation));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_pass_z_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_fail_operation));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_pass_z_pass_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_pass_operation));
-      on = true;
+    if (_supports_two_sided_stencil) {
+      unsigned int back_compare;
+      back_compare = stencil->get_render_state(StencilAttrib::SRS_back_comparison_function);
+
+      if (back_compare != RenderAttrib::M_none) {
+        set_render_state(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+        set_render_state(D3DRS_CCW_STENCILFUNC, dx_stencil_comparison_function_array[back_compare]);
+        set_render_state(D3DRS_CCW_STENCILFAIL, dx_stencil_operation_array[
+          stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation)]);
+        set_render_state(D3DRS_CCW_STENCILZFAIL, dx_stencil_operation_array[
+          stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation)]);
+        set_render_state(D3DRS_CCW_STENCILPASS, dx_stencil_operation_array[
+          stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation)]);
+        on = true;
+      } else {
+        set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+      }
     }
 
     if (on) {
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_reference, stencil -> get_render_state (StencilAttrib::SRS_reference));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_read_mask, stencil -> get_render_state (StencilAttrib::SRS_read_mask));
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_write_mask, stencil -> get_render_state (StencilAttrib::SRS_write_mask));
+      set_render_state(D3DRS_STENCILREF, stencil->get_render_state(StencilAttrib::SRS_reference));
+      set_render_state(D3DRS_STENCILMASK, stencil->get_render_state(StencilAttrib::SRS_read_mask));
+      set_render_state(D3DRS_STENCILWRITEMASK, stencil->get_render_state(StencilAttrib::SRS_write_mask));
     }
 
-    if (stencil -> get_render_state (StencilAttrib::SRS_clear)) {
-      _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0.0f, stencil -> get_render_state (StencilAttrib::SRS_clear_value));
+    if (stencil->get_render_state(StencilAttrib::SRS_clear)) {
+      _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0.0f, stencil->get_render_state(StencilAttrib::SRS_clear_value));
     }
-  }
-  else {
 
+  } else {
     // DEBUG
     if (false) {
-      dxgsg9_cat.debug() << "STENCIL STATE CHANGE TO OFF \n";
+      dxgsg9_cat.debug() << "STENCIL STATE CHANGE TO OFF\n";
     }
 
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, 0);
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_enable, 0);
+    set_render_state(D3DRS_STENCILENABLE, FALSE);
+    if (_supports_two_sided_stencil) {
+      set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+    }
   }
 }
 

+ 65 - 210
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -337,11 +337,6 @@ CLP(GraphicsStateGuardian)::
   }
 
   close_gsg();
-
-  if (_stencil_render_states) {
-    delete _stencil_render_states;
-    _stencil_render_states = 0;
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2103,9 +2098,6 @@ reset() {
 
   report_my_gl_errors();
 
-  void gl_set_stencil_functions (StencilRenderStates *stencil_render_states);
-  gl_set_stencil_functions(_stencil_render_states);
-
 #if defined(HAVE_CG) && !defined(OPENGLES)
 
   typedef struct {
@@ -11511,18 +11503,7 @@ bind_fbo(GLuint fbo) {
 //  GL stencil code section
 ////////////////////////////////////////////////////////////////////
 
-static int gl_stencil_comparison_function_array [ ] = {
-  GL_NEVER,
-  GL_LESS,
-  GL_EQUAL,
-  GL_LEQUAL,
-  GL_GREATER,
-  GL_NOTEQUAL,
-  GL_GEQUAL,
-  GL_ALWAYS,
-};
-
-static int gl_stencil_operations_array [ ] = {
+static int gl_stencil_operations_array[] = {
   GL_KEEP,
   GL_ZERO,
   GL_REPLACE,
@@ -11539,144 +11520,6 @@ static int gl_stencil_operations_array [ ] = {
   GL_DECR,
 };
 
-void __glActiveStencilFace (GraphicsStateGuardian *gsg, GLenum face) {
-  CLP(GraphicsStateGuardian) *glgsg;
-
-  glgsg = (CLP(GraphicsStateGuardian) *) gsg;
-  if (gsg -> get_supports_two_sided_stencil ( ) &&
-      glgsg -> _glActiveStencilFaceEXT) {
-    if (face == GL_FRONT) {
-      // glActiveStencilFaceEXT (GL_FRONT);
-      glgsg -> _glActiveStencilFaceEXT (GL_FRONT);
-    }
-    else {
-      // glActiveStencilFaceEXT (GL_BACK);
-      glgsg -> _glActiveStencilFaceEXT (GL_BACK);
-    }
-  }
-}
-
-void gl_front_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-
-  __glActiveStencilFace (stencil_render_states -> _gsg, GL_FRONT);
-  glStencilFunc
-    (
-     gl_stencil_comparison_function_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_front_comparison_function)],
-     stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_reference),
-     stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_read_mask)
-     );
-}
-void gl_front_stencil_operation (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-  __glActiveStencilFace (stencil_render_states -> _gsg, GL_FRONT);
-  glStencilOp
-    (
-     gl_stencil_operations_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_front_stencil_fail_operation)],
-     gl_stencil_operations_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_front_stencil_pass_z_fail_operation)],
-     gl_stencil_operations_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_front_stencil_pass_z_pass_operation)]
-     );
-}
-
-void gl_back_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-
-  bool supports_two_sided_stencil;
-
-  supports_two_sided_stencil = stencil_render_states -> _gsg -> get_supports_two_sided_stencil ( );
-  if (supports_two_sided_stencil) {
-    __glActiveStencilFace (stencil_render_states -> _gsg, GL_BACK);
-    glStencilFunc
-      (
-       gl_stencil_comparison_function_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_back_comparison_function)],
-       stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_reference),
-       stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_read_mask)
-       );
-  }
-}
-
-void gl_back_stencil_operation (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-
-  bool supports_two_sided_stencil;
-
-  supports_two_sided_stencil = stencil_render_states -> _gsg -> get_supports_two_sided_stencil ( );
-  if (supports_two_sided_stencil) {
-    __glActiveStencilFace (stencil_render_states -> _gsg, GL_BACK);
-    glStencilOp
-      (
-       gl_stencil_operations_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_back_stencil_fail_operation)],
-       gl_stencil_operations_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_back_stencil_pass_z_fail_operation)],
-       gl_stencil_operations_array [stencil_render_states -> get_stencil_render_state (StencilRenderStates::SRS_back_stencil_pass_z_pass_operation)]
-       );
-  }
-}
-
-void gl_front_back_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-  gl_front_stencil_function (stencil_render_state, stencil_render_states);
-  gl_back_stencil_function (stencil_render_state, stencil_render_states);
-}
-
-void gl_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
-
-  StencilType render_state_value;
-  bool supports_two_sided_stencil;
-
-  supports_two_sided_stencil = stencil_render_states -> _gsg -> get_supports_two_sided_stencil ( );
-
-  render_state_value = stencil_render_states -> get_stencil_render_state (stencil_render_state);
-  switch (stencil_render_state) {
-  case StencilRenderStates::SRS_front_enable:
-    if (render_state_value) {
-      glEnable (GL_STENCIL_TEST);
-    }
-    else {
-      glDisable (GL_STENCIL_TEST);
-    }
-    break;
-#ifndef OPENGLES
-  case StencilRenderStates::SRS_back_enable:
-    if (supports_two_sided_stencil) {
-      if (render_state_value) {
-        glEnable (GL_STENCIL_TEST_TWO_SIDE_EXT);
-      }
-      else {
-        glDisable (GL_STENCIL_TEST_TWO_SIDE_EXT);
-      }
-    }
-    break;
-#endif
-
-  case StencilRenderStates::SRS_write_mask:
-    glStencilMask (render_state_value);
-    break;
-
-  default:
-    break;
-  }
-}
-
-void gl_set_stencil_functions (StencilRenderStates *stencil_render_states) {
-
-  if (stencil_render_states) {
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_front_enable, gl_stencil_function);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_back_enable, gl_stencil_function);
-
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_front_comparison_function, gl_front_stencil_function);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_front_stencil_fail_operation,  gl_front_stencil_operation);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_front_stencil_pass_z_fail_operation, gl_front_stencil_operation);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_front_stencil_pass_z_pass_operation, gl_front_stencil_operation);
-
-    // GL seems to support different read masks and/or reference values for front and back, but DX does not.
-    // This needs to be cross-platform so do it the DX way by setting the same read mask and reference for both front and back.
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_reference, gl_front_back_stencil_function);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_read_mask, gl_front_back_stencil_function);
-
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_write_mask, gl_stencil_function);
-
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_back_comparison_function, gl_back_stencil_function);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_back_stencil_fail_operation, gl_back_stencil_operation);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_back_stencil_pass_z_fail_operation, gl_back_stencil_operation);
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_back_stencil_pass_z_pass_operation, gl_back_stencil_operation);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::do_issue_stencil
 //       Access: Protected
@@ -11688,72 +11531,84 @@ do_issue_stencil() {
     return;
   }
 
-  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib_def(StencilAttrib::get_class_slot()));
-
-  StencilRenderStates *stencil_render_states;
-  stencil_render_states = this -> _stencil_render_states;
-  if (stencil && stencil_render_states) {
+  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib(StencilAttrib::get_class_slot()));
 
+  if (stencil != (const StencilAttrib *)NULL) {
     // DEBUG
     if (false) {
       GLCAT.debug() << "STENCIL STATE CHANGE\n";
       GLCAT.debug() << "\n"
-                    << "SRS_front_enable " << (int)stencil -> get_render_state (StencilAttrib::SRS_front_enable) << "\n"
-                    << "SRS_back_enable " << (int)stencil -> get_render_state (StencilAttrib::SRS_back_enable) << "\n"
-                    << "SRS_front_comparison_function " << (int)stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function) << "\n"
-                    << "SRS_front_stencil_fail_operation " << (int)stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
-                    << "SRS_front_stencil_pass_z_fail_operation " << (int)stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
-                    << "SRS_front_stencil_pass_z_pass_operation " << (int)stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
-                    << "SRS_reference " << (int)stencil -> get_render_state (StencilAttrib::SRS_reference) << "\n"
-                    << "SRS_read_mask " << (int)stencil -> get_render_state (StencilAttrib::SRS_read_mask) << "\n"
-                    << "SRS_write_mask " << (int)stencil -> get_render_state (StencilAttrib::SRS_write_mask) << "\n"
-                    << "SRS_back_comparison_function " << (int)stencil -> get_render_state (StencilAttrib::SRS_back_comparison_function) << "\n"
-                    << "SRS_back_stencil_fail_operation " << (int)stencil -> get_render_state (StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
-                    << "SRS_back_stencil_pass_z_fail_operation " << (int)stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
-                    << "SRS_back_stencil_pass_z_pass_operation " << (int)stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
+                    << "SRS_front_comparison_function " << (int)stencil->get_render_state(StencilAttrib::SRS_front_comparison_function) << "\n"
+                    << "SRS_front_stencil_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
+                    << "SRS_front_stencil_pass_z_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
+                    << "SRS_front_stencil_pass_z_pass_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
+                    << "SRS_reference " << (int)stencil->get_render_state(StencilAttrib::SRS_reference) << "\n"
+                    << "SRS_read_mask " << (int)stencil->get_render_state(StencilAttrib::SRS_read_mask) << "\n"
+                    << "SRS_write_mask " << (int)stencil->get_render_state(StencilAttrib::SRS_write_mask) << "\n"
+                    << "SRS_back_comparison_function " << (int)stencil->get_render_state(StencilAttrib::SRS_back_comparison_function) << "\n"
+                    << "SRS_back_stencil_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
+                    << "SRS_back_stencil_pass_z_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
+                    << "SRS_back_stencil_pass_z_pass_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
+    }
+
+    if (_supports_two_sided_stencil) {
+      //TODO: add support for OpenGL 2.0-style glStencilFuncSeparate.
+      unsigned int back_compare;
+      back_compare = stencil->get_render_state(StencilAttrib::SRS_back_comparison_function);
+
+      if (back_compare != RenderAttrib::M_none) {
+        glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+        _glActiveStencilFaceEXT(GL_BACK);
+
+        glStencilFunc(
+          PANDA_TO_GL_COMPAREFUNC(back_compare),
+          stencil->get_render_state(StencilAttrib::SRS_reference),
+          stencil->get_render_state(StencilAttrib::SRS_read_mask));
+
+        glStencilOp(
+           gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation)],
+           gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation)],
+           gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation)]
+        );
+        glStencilMask(stencil->get_render_state(StencilAttrib::SRS_write_mask));
+      } else {
+        glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+      }
+
+      _glActiveStencilFaceEXT(GL_FRONT);
     }
 
-    {
-      bool on;
+    unsigned int front_compare;
+    front_compare = stencil->get_render_state(StencilAttrib::SRS_front_comparison_function);
 
-      on = false;
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, stencil -> get_render_state (StencilAttrib::SRS_front_enable));
-      if (stencil -> get_render_state (StencilAttrib::SRS_front_enable)) {
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_comparison_function, stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_pass_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation));
-        on = true;
-      }
+    if (front_compare != RenderAttrib::M_none) {
+      glEnable(GL_STENCIL_TEST);
 
-      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_enable, stencil -> get_render_state (StencilAttrib::SRS_back_enable));
-      if (stencil -> get_render_state (StencilAttrib::SRS_back_enable)) {
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_comparison_function, stencil -> get_render_state (StencilAttrib::SRS_back_comparison_function));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_fail_operation));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_pass_z_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_fail_operation));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_pass_z_pass_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_pass_operation));
-        on = true;
-      }
+      glStencilFunc(
+        PANDA_TO_GL_COMPAREFUNC(front_compare),
+        stencil->get_render_state(StencilAttrib::SRS_reference),
+        stencil->get_render_state(StencilAttrib::SRS_read_mask));
 
-      if (on) {
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_reference, stencil -> get_render_state (StencilAttrib::SRS_reference));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_read_mask, stencil -> get_render_state (StencilAttrib::SRS_read_mask));
-        stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_write_mask, stencil -> get_render_state (StencilAttrib::SRS_write_mask));
-      }
+      glStencilOp(
+         gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation)],
+         gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation)],
+         gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation)]
+      );
+      glStencilMask(stencil->get_render_state(StencilAttrib::SRS_write_mask));
+    } else {
+      glDisable(GL_STENCIL_TEST);
     }
 
-    if (stencil -> get_render_state (StencilAttrib::SRS_clear)) {
-      GLbitfield mask = 0;
-
+    if (stencil->get_render_state(StencilAttrib::SRS_clear)) {
       // clear stencil buffer
-      glClearStencil(stencil -> get_render_state (StencilAttrib::SRS_clear_value));
-      mask |= GL_STENCIL_BUFFER_BIT;
-      glClear(mask);
+      glClearStencil(stencil->get_render_state(StencilAttrib::SRS_clear_value));
+      glClear(GL_STENCIL_BUFFER_BIT);
+    }
+  } else {
+    glDisable(GL_STENCIL_TEST);
+    if (_supports_two_sided_stencil) {
+      glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
     }
-  }
-  else {
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, 0);
-    stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_enable, 0);
   }
 }
 

+ 61 - 36
panda/src/pgraph/renderState.cxx

@@ -37,7 +37,7 @@
 #include "thread.h"
 #include "renderAttribRegistry.h"
 #include "py_panda.h"
-  
+
 LightReMutex *RenderState::_states_lock = NULL;
 RenderState::States *RenderState::_states = NULL;
 CPT(RenderState) RenderState::_empty_state;
@@ -67,7 +67,7 @@ TypeHandle RenderState::_type_handle;
 //               spurious warning if all constructors are private.
 ////////////////////////////////////////////////////////////////////
 RenderState::
-RenderState() : 
+RenderState() :
   _flags(0),
   _auto_shader_state(NULL),
   _lock("RenderState")
@@ -230,6 +230,31 @@ compare_sort(const RenderState &other) const {
   return 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::compare_mask
+//       Access: Published
+//  Description: This version of compare_to takes a slot mask that
+//               indicates which attributes to include in the
+//               comparison.  Unlike compare_to, this method
+//               compares the attributes by pointer.
+////////////////////////////////////////////////////////////////////
+int RenderState::
+compare_mask(const RenderState &other, SlotMask compare_mask) const {
+  SlotMask mask = (_filled_slots | other._filled_slots) & compare_mask;
+  int slot = mask.get_lowest_on_bit();
+  while (slot >= 0) {
+    const RenderAttrib *a = _attributes[slot]._attrib;
+    const RenderAttrib *b = other._attributes[slot]._attrib;
+    if (a != b) {
+      return a < b ? -1 : 1;
+    }
+    mask.clear_bit(slot);
+    slot = mask.get_lowest_on_bit();
+  }
+
+  return 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::cull_callback
 //       Access: Published
@@ -464,7 +489,7 @@ compose(const RenderState *other) const {
     // to decrement it again later, when the composition entry is
     // removed from the cache.
     result->cache_ref();
-    
+
     // (If the result was just this again, we still store the
     // result, but we don't increment the reference count, since
     // that would be a self-referential leak.)
@@ -558,7 +583,7 @@ invert_compose(const RenderState *other) const {
     // to decrement it again later, when the composition entry is
     // removed from the cache.
     result->cache_ref();
-    
+
     // (If the result was just this again, we still store the
     // result, but we don't increment the reference count, since
     // that would be a self-referential leak.)
@@ -759,7 +784,7 @@ get_auto_shader_state() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::output
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 output(ostream &out) const {
@@ -789,12 +814,12 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::write
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 write(ostream &out, int indent_level) const {
   if (is_empty()) {
-    indent(out, indent_level) 
+    indent(out, indent_level)
       << "(empty)\n";
   }
 
@@ -804,7 +829,7 @@ write(ostream &out, int indent_level) const {
     const Attribute &attrib = _attributes[slot];
     nassertv(attrib._attrib != (RenderAttrib *)NULL);
     attrib._attrib->write(out, indent_level);
-    
+
     mask.clear_bit(slot);
     slot = mask.get_lowest_on_bit();
   }
@@ -927,7 +952,7 @@ get_num_unused_states() {
 
       if (pgraph_cat.is_debug()) {
         pgraph_cat.debug()
-          << "Unused state: " << (void *)state << ":" 
+          << "Unused state: " << (void *)state << ":"
           << state->get_ref_count() << " =\n";
         state->write(pgraph_cat.debug(false), 2);
       }
@@ -1062,7 +1087,7 @@ garbage_collect() {
   }
   num_this_pass = min(num_this_pass, size);
   int stop_at_element = (_garbage_index + num_this_pass) % size;
-  
+
   int num_elements = 0;
   int si = _garbage_index;
   do {
@@ -1092,7 +1117,7 @@ garbage_collect() {
         state->cache_unref();
         delete state;
       }
-    }      
+    }
 
     si = (si + 1) % size;
   } while (si != stop_at_element);
@@ -1193,7 +1218,7 @@ list_cycles(ostream &out) {
         if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
           // This state begins a cycle.
           CompositionCycleDesc::iterator csi;
-          
+
           out << "\nReverse cycle detected of length " << cycle_desc.size() + 1 << ":\n"
               << "state ";
           for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
@@ -1209,7 +1234,7 @@ list_cycles(ostream &out) {
           out << (void *)state << ":"
               << state->get_ref_count() << " =\n";
           state->write(out, 2);
-          
+
           cycle_desc.clear();
         }
       }
@@ -1272,7 +1297,7 @@ validate_states() {
     pgraph_cat.error()
       << "RenderState::_states cache is invalid!\n";
     return false;
-  }    
+  }
 
   int size = _states->get_size();
   int si = 0;
@@ -1447,7 +1472,7 @@ do_calc_auto_shader_state() {
       state->_attributes[slot].set(new_attrib, 0);
       state->_filled_slots.set_bit(slot);
     }
-    
+
     mask.clear_bit(slot);
     slot = mask.get_lowest_on_bit();
   }
@@ -1455,7 +1480,7 @@ do_calc_auto_shader_state() {
   return return_new(state);
 }
 
-  
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::return_new
 //       Access: Private, Static
@@ -1553,7 +1578,7 @@ return_unique(RenderState *state) {
       attrib._attrib = attrib._attrib->get_unique();
       mask.clear_bit(slot);
       slot = mask.get_lowest_on_bit();
-    }    
+    }
   }
 
   int si = _states->find(state);
@@ -1561,7 +1586,7 @@ return_unique(RenderState *state) {
     // There's an equivalent state already in the set.  Return it.
     return _states->get_key(si);
   }
-  
+
   // Not already in the set; add it.
   if (garbage_collect_states) {
     // If we'll be garbage collecting states explicitly, we'll
@@ -1627,11 +1652,11 @@ do_compose(const RenderState *other) const {
       // with B's override value.
       result.set(a._attrib->compose(b._attrib), b._override);
     }
-    
+
     mask.clear_bit(slot);
     slot = mask.get_lowest_on_bit();
   }
-  
+
   // If we have any ShaderAttrib with auto-shader enabled,
   // remove any shader inputs on it. This is a workaround for an
   // issue that makes the shader-generator regenerate the shader
@@ -1640,7 +1665,7 @@ do_compose(const RenderState *other) const {
   if (sattrib->auto_shader()) {
     sattrib = DCAST(ShaderAttrib, sattrib->clear_all_shader_inputs());
   }
-  
+
   return return_new(new_state);
 }
 
@@ -1680,7 +1705,7 @@ do_invert_compose(const RenderState *other) const {
       // Compose.
       result.set(a._attrib->invert_compose(b._attrib), 0);
     }
-    
+
     mask.clear_bit(slot);
     slot = mask.get_lowest_on_bit();
   }
@@ -1697,7 +1722,7 @@ do_invert_compose(const RenderState *other) const {
 void RenderState::
 detect_and_break_cycles() {
   PStatTimer timer(_state_break_cycles_pcollector);
-      
+
   ++_last_cycle_detect;
   if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) {
     // Ok, we have a cycle.  This will be a leak unless we break the
@@ -1706,7 +1731,7 @@ detect_and_break_cycles() {
       pgraph_cat.debug()
         << "Breaking cycle involving " << (*this) << "\n";
     }
-    
+
     ((RenderState *)this)->remove_cache_pointers();
   } else {
     ++_last_cycle_detect;
@@ -1715,12 +1740,12 @@ detect_and_break_cycles() {
         pgraph_cat.debug()
           << "Breaking cycle involving " << (*this) << "\n";
       }
-      
+
       ((RenderState *)this)->remove_cache_pointers();
     }
   }
 }
-  
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::r_detect_cycles
 //       Access: Private, Static
@@ -1747,14 +1772,14 @@ r_detect_cycles(const RenderState *start_state,
     return (current_state == start_state && length > 2);
   }
   ((RenderState *)current_state)->_cycle_detect = this_seq;
-    
+
   int i;
   int cache_size = current_state->_composition_cache.get_size();
   for (i = 0; i < cache_size; ++i) {
     if (current_state->_composition_cache.has_element(i)) {
       const RenderState *result = current_state->_composition_cache.get_data(i)._result;
       if (result != (const RenderState *)NULL) {
-        if (r_detect_cycles(start_state, result, length + 1, 
+        if (r_detect_cycles(start_state, result, length + 1,
                             this_seq, cycle_desc)) {
           // Cycle detected.
           if (cycle_desc != (CompositionCycleDesc *)NULL) {
@@ -1826,7 +1851,7 @@ r_detect_reverse_cycles(const RenderState *start_state,
 
         const RenderState *result = other->_composition_cache.get_data(oi)._result;
         if (result != (const RenderState *)NULL) {
-          if (r_detect_reverse_cycles(start_state, result, length + 1, 
+          if (r_detect_reverse_cycles(start_state, result, length + 1,
                                       this_seq, cycle_desc)) {
             // Cycle detected.
             if (cycle_desc != (CompositionCycleDesc *)NULL) {
@@ -1851,7 +1876,7 @@ r_detect_reverse_cycles(const RenderState *start_state,
 
         const RenderState *result = other->_invert_composition_cache.get_data(oi)._result;
         if (result != (const RenderState *)NULL) {
-          if (r_detect_reverse_cycles(start_state, result, length + 1, 
+          if (r_detect_reverse_cycles(start_state, result, length + 1,
                                       this_seq, cycle_desc)) {
             // Cycle detected.
             if (cycle_desc != (CompositionCycleDesc *)NULL) {
@@ -1975,11 +2000,11 @@ remove_cache_pointers() {
       if (oi != -1) {
         // Hold a copy of the other composition result, too.
         Composition ocomp = other->_composition_cache.get_data(oi);
-        
+
         other->_composition_cache.remove_element(oi);
         _cache_stats.add_total_size(-1);
         _cache_stats.inc_dels();
-        
+
         // It's finally safe to let our held pointers go away.  This may
         // have cascading effects as other RenderState objects are
         // destructed, but there will be no harm done if they destruct
@@ -2071,7 +2096,7 @@ determine_bin_index() {
       }
     }
   }
-  
+
   CullBinManager *bin_manager = CullBinManager::get_global_ptr();
   _bin_index = bin_manager->find_bin(bin_name);
   if (_bin_index == -1) {
@@ -2104,7 +2129,7 @@ determine_cull_callback() {
       _flags |= F_has_cull_callback;
       break;
     }
-    
+
     mask.clear_bit(slot);
     slot = mask.get_lowest_on_bit();
   }
@@ -2210,7 +2235,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
     nassertv(attrib._attrib != (RenderAttrib *)NULL);
     manager->write_pointer(dg, attrib._attrib);
     dg.add_int32(attrib._override);
-    
+
     mask.clear_bit(slot);
     slot = mask.get_lowest_on_bit();
   }
@@ -2276,7 +2301,7 @@ change_this(TypedWritable *old_ptr, BamReader *manager) {
     pointer->ref();
     manager->register_finalize(state);
   }
-  
+
   // We have to cast the pointer back to non-const, because the bam
   // reader expects that.
   return (RenderState *)pointer.p();

+ 5 - 4
panda/src/pgraph/renderState.h

@@ -67,6 +67,7 @@ public:
 PUBLISHED:
   int compare_to(const RenderState &other) const;
   int compare_sort(const RenderState &other) const;
+  int compare_mask(const RenderState &other, SlotMask compare_mask) const;
   INLINE size_t get_hash() const;
 
   INLINE bool is_empty() const;
@@ -88,7 +89,7 @@ PUBLISHED:
                                const RenderAttrib *attrib4, int override = 0);
   static CPT(RenderState) make(const RenderAttrib * const *attrib,
                                int num_attribs, int override = 0);
-  
+
   CPT(RenderState) compose(const RenderState *other) const;
   CPT(RenderState) invert_compose(const RenderState *other) const;
 
@@ -152,10 +153,10 @@ PUBLISHED:
   INLINE int get_draw_order() const;
   INLINE int get_bin_index() const;
   int get_geom_rendering(int geom_rendering) const;
-  
+
 public:
   static void bin_removed(int bin_index);
-  
+
   INLINE static void flush_level();
 
 private:
@@ -339,7 +340,7 @@ public:
 protected:
   static TypedWritable *make_from_bam(const FactoryParams &params);
   void fillin(DatagramIterator &scan, BamReader *manager);
-  
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 2 - 2
panda/src/pgraph/stencilAttrib.I

@@ -18,6 +18,6 @@
 //  Description: Returns render state.
 ////////////////////////////////////////////////////////////////////
 INLINE unsigned int StencilAttrib::
-get_render_state(unsigned int render_state_identifier) const {
-  return _stencil_render_states [render_state_identifier];
+get_render_state(StencilRenderState render_state_identifier) const {
+  return _stencil_render_states[(int)render_state_identifier];
 }

+ 88 - 65
panda/src/pgraph/stencilAttrib.cxx

@@ -24,11 +24,8 @@ TypeHandle StencilAttrib::_type_handle;
 int StencilAttrib::_attrib_slot;
 
 const char *StencilAttrib::
-stencil_render_state_name_array [StencilAttrib::SRS_total] =
+stencil_render_state_name_array[StencilAttrib::SRS_total] =
 {
-  "SRS_front_enable",
-  "SRS_back_enable",
-
   "SRS_front_comparison_function",
   "SRS_front_stencil_fail_operation",
   "SRS_front_stencil_pass_z_fail_operation",
@@ -55,11 +52,7 @@ stencil_render_state_name_array [StencilAttrib::SRS_total] =
 ////////////////////////////////////////////////////////////////////
 StencilAttrib::
 StencilAttrib() {
-
-  _stencil_render_states [SRS_front_enable] = 0;
-  _stencil_render_states [SRS_back_enable] = 0;
-
-  _stencil_render_states [SRS_front_comparison_function] = SCF_always;
+  _stencil_render_states [SRS_front_comparison_function] = M_none;
   _stencil_render_states [SRS_front_stencil_fail_operation] = SO_keep;
   _stencil_render_states [SRS_front_stencil_pass_z_fail_operation] = SO_keep;
   _stencil_render_states [SRS_front_stencil_pass_z_pass_operation] = SO_keep;
@@ -68,7 +61,7 @@ StencilAttrib() {
   _stencil_render_states [SRS_read_mask] = ~0;
   _stencil_render_states [SRS_write_mask] = ~0;
 
-  _stencil_render_states [SRS_back_comparison_function] = SCF_always;
+  _stencil_render_states [SRS_back_comparison_function] = M_none;
   _stencil_render_states [SRS_back_stencil_fail_operation] = SO_keep;
   _stencil_render_states [SRS_back_stencil_pass_z_fail_operation] = SO_keep;
   _stencil_render_states [SRS_back_stencil_pass_z_pass_operation] = SO_keep;
@@ -80,14 +73,12 @@ StencilAttrib() {
 ////////////////////////////////////////////////////////////////////
 //     Function: StencilAttrib::make_off
 //       Access: Published, Static
-//  Description: Constructs a StencilAttrib that has stenciling 
+//  Description: Constructs a StencilAttrib that has stenciling
 //               turned off.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) StencilAttrib::
-make_off()
-{
+make_off() {
   StencilAttrib *attrib = new StencilAttrib;
-
   return return_new(attrib);
 }
 
@@ -110,19 +101,20 @@ make_default() {
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) StencilAttrib::
 make(
-  unsigned int front_enable,
-  unsigned int front_comparison_function,
-  unsigned int stencil_fail_operation,
-  unsigned int stencil_pass_z_fail_operation,
-  unsigned int front_stencil_pass_z_pass_operation,
+  bool front_enable,
+  PandaCompareFunc front_comparison_function,
+  StencilOperation stencil_fail_operation,
+  StencilOperation stencil_pass_z_fail_operation,
+  StencilOperation front_stencil_pass_z_pass_operation,
   unsigned int reference,
   unsigned int read_mask,
   unsigned int write_mask)
 {
   StencilAttrib *attrib = new StencilAttrib;
 
-  attrib->_stencil_render_states [SRS_front_enable] = front_enable;
-  attrib->_stencil_render_states [SRS_back_enable] = 0;
+  if (!front_enable) {
+    front_comparison_function = M_none;
+  }
 
   attrib->_stencil_render_states [SRS_front_comparison_function] = front_comparison_function;
   attrib->_stencil_render_states [SRS_front_stencil_fail_operation] = stencil_fail_operation;
@@ -133,7 +125,7 @@ make(
   attrib->_stencil_render_states [SRS_read_mask] = read_mask;
   attrib->_stencil_render_states [SRS_write_mask] = write_mask;
 
-  attrib->_stencil_render_states [SRS_back_comparison_function] = SCF_always;
+  attrib->_stencil_render_states [SRS_back_comparison_function] = M_none;
   attrib->_stencil_render_states [SRS_back_stencil_fail_operation] = SO_keep;
   attrib->_stencil_render_states [SRS_back_stencil_pass_z_fail_operation] = SO_keep;
   attrib->_stencil_render_states [SRS_back_stencil_pass_z_pass_operation] = SO_keep;
@@ -148,24 +140,29 @@ make(
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) StencilAttrib::
 make_2_sided(
-  unsigned int front_enable,
-  unsigned int back_enable,
-  unsigned int front_comparison_function,
-  unsigned int stencil_fail_operation,
-  unsigned int stencil_pass_z_fail_operation,
-  unsigned int front_stencil_pass_z_pass_operation,
+  bool front_enable,
+  bool back_enable,
+  PandaCompareFunc front_comparison_function,
+  StencilOperation stencil_fail_operation,
+  StencilOperation stencil_pass_z_fail_operation,
+  StencilOperation front_stencil_pass_z_pass_operation,
   unsigned int reference,
   unsigned int read_mask,
   unsigned int write_mask,
-  unsigned int back_comparison_function,
-  unsigned int back_stencil_fail_operation,
-  unsigned int back_stencil_pass_z_fail_operation,
-  unsigned int back_stencil_pass_z_pass_operation)
+  PandaCompareFunc back_comparison_function,
+  StencilOperation back_stencil_fail_operation,
+  StencilOperation back_stencil_pass_z_fail_operation,
+  StencilOperation back_stencil_pass_z_pass_operation)
 {
   StencilAttrib *attrib = new StencilAttrib;
 
-  attrib->_stencil_render_states [SRS_front_enable] = front_enable;
-  attrib->_stencil_render_states [SRS_back_enable] = back_enable;
+  if (!front_enable) {
+    front_comparison_function = M_none;
+  }
+
+  if (!back_enable) {
+    back_comparison_function = M_none;
+  }
 
   attrib->_stencil_render_states [SRS_front_comparison_function] = front_comparison_function;
   attrib->_stencil_render_states [SRS_front_stencil_fail_operation] = stencil_fail_operation;
@@ -191,21 +188,22 @@ make_2_sided(
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) StencilAttrib::
 make_with_clear(
-  unsigned int front_enable,
-  unsigned int front_comparison_function,
-  unsigned int stencil_fail_operation,
-  unsigned int stencil_pass_z_fail_operation,
-  unsigned int front_stencil_pass_z_pass_operation,
+  bool front_enable,
+  PandaCompareFunc front_comparison_function,
+  StencilOperation stencil_fail_operation,
+  StencilOperation stencil_pass_z_fail_operation,
+  StencilOperation front_stencil_pass_z_pass_operation,
   unsigned int reference,
   unsigned int read_mask,
   unsigned int write_mask,
-  unsigned int clear,
+  bool clear,
   unsigned int clear_value)
 {
   StencilAttrib *attrib = new StencilAttrib;
 
-  attrib->_stencil_render_states [SRS_front_enable] = front_enable;
-  attrib->_stencil_render_states [SRS_back_enable] = 0;
+  if (!front_enable) {
+    front_comparison_function = M_none;
+  }
 
   attrib->_stencil_render_states [SRS_front_comparison_function] = front_comparison_function;
   attrib->_stencil_render_states [SRS_front_stencil_fail_operation] = stencil_fail_operation;
@@ -216,7 +214,7 @@ make_with_clear(
   attrib->_stencil_render_states [SRS_read_mask] = read_mask;
   attrib->_stencil_render_states [SRS_write_mask] = write_mask;
 
-  attrib->_stencil_render_states [SRS_back_comparison_function] = SCF_always;
+  attrib->_stencil_render_states [SRS_back_comparison_function] = M_none;
   attrib->_stencil_render_states [SRS_back_stencil_fail_operation] = SO_keep;
   attrib->_stencil_render_states [SRS_back_stencil_pass_z_fail_operation] = SO_keep;
   attrib->_stencil_render_states [SRS_back_stencil_pass_z_pass_operation] = SO_keep;
@@ -234,26 +232,31 @@ make_with_clear(
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) StencilAttrib::
 make_2_sided_with_clear(
-  unsigned int front_enable,
-  unsigned int back_enable,
-  unsigned int front_comparison_function,
-  unsigned int stencil_fail_operation,
-  unsigned int stencil_pass_z_fail_operation,
-  unsigned int front_stencil_pass_z_pass_operation,
+  bool front_enable,
+  bool back_enable,
+  PandaCompareFunc front_comparison_function,
+  StencilOperation stencil_fail_operation,
+  StencilOperation stencil_pass_z_fail_operation,
+  StencilOperation front_stencil_pass_z_pass_operation,
   unsigned int reference,
   unsigned int read_mask,
   unsigned int write_mask,
-  unsigned int back_comparison_function,
-  unsigned int back_stencil_fail_operation,
-  unsigned int back_stencil_pass_z_fail_operation,
-  unsigned int back_stencil_pass_z_pass_operation,
-  unsigned int clear,
+  PandaCompareFunc back_comparison_function,
+  StencilOperation back_stencil_fail_operation,
+  StencilOperation back_stencil_pass_z_fail_operation,
+  StencilOperation back_stencil_pass_z_pass_operation,
+  bool clear,
   unsigned int clear_value)
 {
   StencilAttrib *attrib = new StencilAttrib;
 
-  attrib->_stencil_render_states [SRS_front_enable] = front_enable;
-  attrib->_stencil_render_states [SRS_back_enable] = back_enable;
+  if (!front_enable) {
+    front_comparison_function = M_none;
+  }
+
+  if (!back_enable) {
+    back_comparison_function = M_none;
+  }
 
   attrib->_stencil_render_states [SRS_front_comparison_function] = front_comparison_function;
   attrib->_stencil_render_states [SRS_front_stencil_fail_operation] = stencil_fail_operation;
@@ -316,9 +319,9 @@ compare_to_impl(const RenderAttrib *other) const {
   int index;
   int compare_result = 0;
 
-  for (index = 0; index < SRS_total; index++) {
-    a = (int) sa -> _stencil_render_states [index];
-    b = (int) _stencil_render_states [index];
+  for (index = 0; index < SRS_total; ++index) {
+    a = (int) sa -> _stencil_render_states[index];
+    b = (int) _stencil_render_states[index];
     compare_result = (a - b);
     if (compare_result) {
       break;
@@ -368,9 +371,8 @@ void StencilAttrib::
 write_datagram(BamWriter *manager, Datagram &dg) {
   RenderAttrib::write_datagram(manager, dg);
 
-  int index;
-  for (index = 0; index < SRS_total; index++) {
-    dg.add_int32(_stencil_render_states [index]);
+  for (int index = 0; index < SRS_total; ++index) {
+    dg.add_uint32(_stencil_render_states[index]);
   }
 }
 
@@ -405,8 +407,29 @@ void StencilAttrib::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderAttrib::fillin(scan, manager);
 
-  int index;
-  for (index = 0; index < SRS_total; index++) {
-    _stencil_render_states [index] = scan.get_int32();
+  if (manager->get_file_minor_ver() < 35) {
+    unsigned int front_enable, back_enable;
+    front_enable = scan.get_int32();
+    back_enable = scan.get_int32();
+
+    for (int index = 0; index < SRS_total; ++index) {
+      _stencil_render_states[index] = scan.get_int32();
+    }
+
+    if (front_enable) {
+      _stencil_render_states[SRS_front_comparison_function]++;
+    } else {
+      _stencil_render_states[SRS_front_comparison_function] = M_none;
+    }
+
+    if (back_enable) {
+      _stencil_render_states[SRS_back_comparison_function]++;
+    } else {
+      _stencil_render_states[SRS_back_comparison_function] = M_none;
+    }
+  } else {
+    for (int index = 0; index < SRS_total; ++index) {
+      _stencil_render_states[index] = scan.get_uint32();
+    }
   }
 }

+ 50 - 63
panda/src/pgraph/stencilAttrib.h

@@ -23,9 +23,9 @@ class FactoryParams;
 ////////////////////////////////////////////////////////////////////
 //       Class : StencilAttrib
 // Description : A StencilAttrib is a collection of all stencil render
-//               states.  The render states in a StencilAttrib are 
-//               read-only.  A StencilAttrib is created with make or 
-//               make_2_sided.  To determine if two sided stencil is 
+//               states.  The render states in a StencilAttrib are
+//               read-only.  A StencilAttrib is created with make or
+//               make_2_sided.  To determine if two sided stencil is
 //               supported, call the function GraphicsStateGuardian::
 //               get_supports_two_sided_stencil.
 ////////////////////////////////////////////////////////////////////
@@ -35,13 +35,8 @@ private:
   StencilAttrib();
 
 PUBLISHED:
-
   // enums are duplicated here from class StencilRenderStates for use in Python
-  enum StencilRenderState
-  {
-    SRS_front_enable,
-    SRS_back_enable,
-
+  enum StencilRenderState {
     SRS_front_comparison_function,
     SRS_front_stencil_fail_operation,
     SRS_front_stencil_pass_z_fail_operation,
@@ -58,26 +53,23 @@ PUBLISHED:
 
     SRS_clear,
     SRS_clear_value,
-    
-    SRS_total,
 
-    SRS_first = 0,
+    SRS_total,
   };
 
-  enum StencilComparisonFunction
-  {
-    SCF_never,
-    SCF_less_than,
-    SCF_equal,
-    SCF_less_than_or_equal,
-    SCF_greater_than,
-    SCF_not_equal,
-    SCF_greater_than_or_equal,
-    SCF_always,
+  // Exists purely for backward compatibility.
+  enum StencilComparisonFunction {
+    SCF_never = M_never,
+    SCF_less_than = M_less,
+    SCF_equal = M_equal,
+    SCF_less_than_or_equal = M_less_equal,
+    SCF_greater_than = M_greater,
+    SCF_not_equal = M_not_equal,
+    SCF_greater_than_or_equal = M_greater_equal,
+    SCF_always = M_always,
   };
 
-  enum StencilOperation
-  {
+  enum StencilOperation {
     SO_keep,
     SO_zero,
     SO_replace,
@@ -88,73 +80,68 @@ PUBLISHED:
     SO_decrement_saturate,
   };
 
-  enum StencilMask
-  {
-    SM_default = ~0,
-  };
-
   static CPT(RenderAttrib) make_off();
   static CPT(RenderAttrib) make_default();
 
   static CPT(RenderAttrib) make(
-    unsigned int front_enable,
-    unsigned int front_comparison_function,
-    unsigned int stencil_fail_operation,
-    unsigned int stencil_pass_z_fail_operation,
-    unsigned int front_stencil_pass_z_pass_operation,
+    bool front_enable,
+    PandaCompareFunc front_comparison_function,
+    StencilOperation stencil_fail_operation,
+    StencilOperation stencil_pass_z_fail_operation,
+    StencilOperation front_stencil_pass_z_pass_operation,
     unsigned int reference,
     unsigned int read_mask,
     unsigned int write_mask);
 
   static CPT(RenderAttrib) make_2_sided(
-    unsigned int front_enable,
-    unsigned int back_enable,
-    unsigned int front_comparison_function,
-    unsigned int stencil_fail_operation,
-    unsigned int stencil_pass_z_fail_operation,
-    unsigned int front_stencil_pass_z_pass_operation,
+    bool front_enable,
+    bool back_enable,
+    PandaCompareFunc front_comparison_function,
+    StencilOperation stencil_fail_operation,
+    StencilOperation stencil_pass_z_fail_operation,
+    StencilOperation front_stencil_pass_z_pass_operation,
     unsigned int reference,
     unsigned int read_mask,
     unsigned int write_mask,
-    unsigned int back_comparison_function,
-    unsigned int back_stencil_fail_operation,
-    unsigned int back_stencil_pass_z_fail_operation,
-    unsigned int back_stencil_pass_z_pass_operation);
+    PandaCompareFunc back_comparison_function,
+    StencilOperation back_stencil_fail_operation,
+    StencilOperation back_stencil_pass_z_fail_operation,
+    StencilOperation back_stencil_pass_z_pass_operation);
 
   static CPT(RenderAttrib) make_with_clear(
-    unsigned int front_enable,
-    unsigned int front_comparison_function,
-    unsigned int stencil_fail_operation,
-    unsigned int stencil_pass_z_fail_operation,
-    unsigned int front_stencil_pass_z_pass_operation,
+    bool front_enable,
+    PandaCompareFunc front_comparison_function,
+    StencilOperation stencil_fail_operation,
+    StencilOperation stencil_pass_z_fail_operation,
+    StencilOperation front_stencil_pass_z_pass_operation,
     unsigned int reference,
     unsigned int read_mask,
     unsigned int write_mask,
-    unsigned int clear,
+    bool clear,
     unsigned int clear_value);
 
   static CPT(RenderAttrib) make_2_sided_with_clear(
-    unsigned int front_enable,
-    unsigned int back_enable,
-    unsigned int front_comparison_function,
-    unsigned int stencil_fail_operation,
-    unsigned int stencil_pass_z_fail_operation,
-    unsigned int front_stencil_pass_z_pass_operation,
+    bool front_enable,
+    bool back_enable,
+    PandaCompareFunc front_comparison_function,
+    StencilOperation stencil_fail_operation,
+    StencilOperation stencil_pass_z_fail_operation,
+    StencilOperation front_stencil_pass_z_pass_operation,
     unsigned int reference,
     unsigned int read_mask,
     unsigned int write_mask,
-    unsigned int back_comparison_function,
-    unsigned int back_stencil_fail_operation,
-    unsigned int back_stencil_pass_z_fail_operation,
-    unsigned int back_stencil_pass_z_pass_operation,
-    unsigned int clear,
+    PandaCompareFunc back_comparison_function,
+    StencilOperation back_stencil_fail_operation,
+    StencilOperation back_stencil_pass_z_fail_operation,
+    StencilOperation back_stencil_pass_z_pass_operation,
+    bool clear,
     unsigned int clear_value);
 
-  INLINE unsigned int get_render_state (unsigned int render_state_identifier) const;
+  INLINE unsigned int get_render_state(StencilRenderState render_state_identifier) const;
 
 public:
   static const char *stencil_render_state_name_array [SRS_total];
-  
+
   virtual void output(ostream &out) const;
 
 protected:

+ 2 - 1
panda/src/putil/bam.h

@@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
 static const unsigned short _bam_first_minor_ver = 14;
-static const unsigned short _bam_minor_ver = 34;
+static const unsigned short _bam_minor_ver = 35;
 // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
 // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
@@ -55,5 +55,6 @@ static const unsigned short _bam_minor_ver = 34;
 // Bumped to minor version 32 on 6/11/12 to add Texture::_has_read_mipmaps.
 // Bumped to minor version 33 on 8/17/13 to add UvScrollNode::_w_speed.
 // Bumped to minor version 34 on 9/16/14 to add ScissorAttrib::_off.
+// Bumped to minor version 35 on 12/3/14 to change StencilAttrib.
 
 #endif