Prechádzať zdrojové kódy

Initial working version of stencil buffer.

aignacio_sf 19 rokov pred
rodič
commit
8b4638b38c

+ 13 - 12
panda/src/display/stencilRenderStates.h

@@ -4,7 +4,8 @@
 ////////////////////////////////////////////////////////////////////
 //
 // PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2006, Disney Enterprises, Inc.  All rights reserved
+// Copyright (c) 2001 - 2006, Disney Enterprises, Inc.  All rights
+// reserved.
 //
 // All use of this software is subject to the terms of the Panda 3d
 // Software license.  You should have received a copy of this license
@@ -24,29 +25,29 @@ typedef unsigned int StencilType;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : StencilRenderStates
-// Description : An abstract cross-platform class for stencil buffer
-//               render states.  Each gsg needs to create its own
-//               low-level functions on how to set each render state.
+// 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 StencilRenderStates {
 
 PUBLISHED:
   enum StencilRenderState
   {
-    SRS_clear_value,
-
-    SRS_reference,
-
-    SRS_read_mask,
-    SRS_write_mask,
-
     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_back_enable,
+    SRS_reference,
+    SRS_read_mask,
+    SRS_write_mask,
+
     SRS_back_comparison_function,
     SRS_back_stencil_fail_operation,
     SRS_back_stencil_pass_z_fail_operation,

+ 186 - 3
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -506,8 +506,11 @@ do_clear(const RenderBuffer &buffer) {
   }
 
   if (buffer_type & RenderBuffer::T_stencil) {
-    aux_flags |=  D3DCLEAR_STENCIL;
-    nassertv(_screen->_presentation_params.EnableAutoDepthStencil && IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat));
+    // clear only if there is a stencil buffer
+    if (_screen->_presentation_params.EnableAutoDepthStencil &&
+      IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat)) {
+      aux_flags |=  D3DCLEAR_STENCIL;
+    }
   }
 
   if ((main_flags | aux_flags) != 0) {
@@ -1438,7 +1441,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian9::framebuffer_copy_to_ram
+//     Function: DXGraphicsStateGuardian8::framebuffer_copy_to_ram
 //       Access: Public, Virtual
 //  Description: Copy the pixels within the indicated display region
 //               from the framebuffer into system memory, not texture
@@ -1826,6 +1829,9 @@ reset() {
   _d3d_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
 
   PRINT_REFCNT(dxgsg8, _d3d_device);
+
+  void dx_set_stencil_functions (StencilRenderStates *stencil_render_states);
+  dx_set_stencil_functions (_stencil_render_states);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2261,6 +2267,11 @@ set_state_and_transform(const RenderState *target,
     _state._light = _target._light;
   }
 
+  if (_target._stencil != _state._stencil) {
+    do_issue_stencil();
+    _state._stencil = _target._stencil;
+  }
+
   _state_rs = _target_rs;
 }
 
@@ -3877,3 +3888,175 @@ draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type,
        index_data, index_type, safe_buffer_start, stride);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//  DX stencil code section
+////////////////////////////////////////////////////////////////////
+
+static int dx_stencil_comparison_function_array [ ] =
+{
+  D3DCMP_NEVER,
+  D3DCMP_LESS,
+  D3DCMP_EQUAL,
+  D3DCMP_LESSEQUAL,
+  D3DCMP_GREATER,
+  D3DCMP_NOTEQUAL,
+  D3DCMP_GREATEREQUAL,
+  D3DCMP_ALWAYS,
+};
+
+static int dx_stencil_operation_array [ ] =
+{
+  D3DSTENCILOP_KEEP,
+  D3DSTENCILOP_ZERO,
+  D3DSTENCILOP_REPLACE,
+  D3DSTENCILOP_INCR,
+  D3DSTENCILOP_DECR,
+  D3DSTENCILOP_INVERT,
+
+  D3DSTENCILOP_INCRSAT,
+  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);
+
+  // DEBUG
+  if (false) {
+    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
+//  Description: Set stencil render states.
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::
+do_issue_stencil() {
+
+  const StencilAttrib *stencil;
+  StencilRenderStates *stencil_render_states;
+
+  stencil = _target._stencil;
+  stencil_render_states = this -> _stencil_render_states;
+  if (stencil && stencil_render_states) {
+
+#ifndef NDEBUG
+    // DEBUG ONLY
+    if (stencil -> _pre) {
+      dxgsg8_cat.error() << "Invalid StencilAttrib\n";
+    }
+#endif
+
+    // 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";
+    }
+
+    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));
+
+      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));
+    }
+  }
+  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);
+  }
+}
+
+LPDIRECT3DDEVICE8 DXGraphicsStateGuardian8::
+get_d3d_device() {
+  return _d3d_device;
+}

+ 4 - 2
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -69,7 +69,7 @@ public:
 
   virtual void do_clear(const RenderBuffer &buffer);
 
-  virtual void prepare_display_region(DisplayRegionPipelineReader *dr, 
+  virtual void prepare_display_region(DisplayRegionPipelineReader *dr,
                                       Lens::StereoChannel stereo_channel);
   virtual CPT(TransformState) calc_projection_mat(const Lens *lens);
   virtual bool prepare_lens();
@@ -79,7 +79,7 @@ public:
   virtual void end_scene();
   virtual void end_frame(Thread *current_thread);
 
-  virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, 
+  virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader,
                                      const GeomMunger *munger,
                                      const GeomVertexDataPipelineReader *data_reader);
   virtual void draw_triangles(const GeomPrimitivePipelineReader *reader);
@@ -111,6 +111,7 @@ public:
 
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform);
+  LPDIRECT3DDEVICE8 get_d3d_device();
 
 protected:
   void do_issue_transform();
@@ -128,6 +129,7 @@ protected:
   void do_issue_material();
   void do_issue_texture();
   void do_issue_blending();
+  void do_issue_stencil();
 
   virtual void enable_lighting(bool enable);
   virtual void set_ambient_light(const Colorf &color);

+ 222 - 119
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -719,9 +719,16 @@ do_clear(const RenderBuffer &buffer) {
   }
 
   if (buffer_type & RenderBuffer::T_stencil) {
-    aux_flags |=  D3DCLEAR_STENCIL;
-    nassertv(_screen->_presentation_params.EnableAutoDepthStencil &&
-      IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat));
+    // clear only if there is a stencil buffer
+    if (_screen->_presentation_params.EnableAutoDepthStencil &&
+      IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat)) {
+      aux_flags |=  D3DCLEAR_STENCIL;
+
+      // DEBUG
+      if (false) {
+        dxgsg9_cat.debug ( ) << "STENCIL CLEAR " << _stencil_clear_value << "\n";
+      }
+    }
   }
 
   if ((main_flags | aux_flags) != 0) {
@@ -1046,8 +1053,7 @@ DBG_S dxgsg9_cat.debug ( ) << "@@@@@@@@@@ end_frame \n"; DBG_E
     return;
   }
 
-  if (_lru)
-  {
+  if (_lru) {
     int frames;
     int maximum_updates;
 
@@ -1056,17 +1062,14 @@ DBG_S dxgsg9_cat.debug ( ) << "@@@@@@@@@@ end_frame \n"; DBG_E
     _lru -> partial_lru_update (maximum_updates);
 
     // LRU debug
-    if (false && dxgsg9_cat.is_debug())
-    {
+    if (false && dxgsg9_cat.is_debug()) {
       dxgsg9_cat.debug() << "*  start_priority_index " << _lru -> _m.start_priority_index << "\n";
       dxgsg9_cat.debug() << "*  start_update_lru_page " << _lru -> _m.start_update_lru_page << "\n";
     }
 
     frames = dx_lru_debug_frames_til_output;
-    if (dx_lru_debug && frames > 0 && (_lru -> _m.current_frame_identifier % frames) == 0)
-    {
-      if (dxgsg9_cat.is_debug())
-      {
+    if (dx_lru_debug && frames > 0 && (_lru -> _m.current_frame_identifier % frames) == 0) {
+      if (dxgsg9_cat.is_debug()) {
         UINT available_texture_memory;
 
         available_texture_memory = _d3d_device->GetAvailableTextureMem ( );
@@ -1092,18 +1095,15 @@ DBG_S dxgsg9_cat.debug ( ) << "@@@@@@@@@@ end_frame \n"; DBG_E
 
         int index;
 
-        for (index = 0; index < LPP_TotalPriorities; index++)
-        {
-          if (_lru -> _m.lru_page_count_array [index])
-          {
+        for (index = 0; index < LPP_TotalPriorities; index++) {
+          if (_lru -> _m.lru_page_count_array [index]) {
             dxgsg9_cat.debug() << "*  priority " << index << " pages " << _lru -> _m.lru_page_count_array [index] << "\n";
           }
         }
 
         _lru -> calculate_lru_statistics ( );
 
-        for (index = 0; index < _lru -> _m.maximum_page_types; index++)
-        {
+        for (index = 0; index < _lru -> _m.maximum_page_types; index++) {
           PageTypeStatistics *page_type_statistics;
 
           page_type_statistics = &_lru -> _m.page_type_statistics_array [index];
@@ -2356,108 +2356,6 @@ void DXGraphicsStateGuardian9::reset_render_states (void)
   _last_fvf = 0;
 }
 
-////////////////////////////////////////////////////////////////////
-//  DX stencil code section
-////////////////////////////////////////////////////////////////////
-
-static int dx_stencil_comparison_function_array [ ] =
-{
-  D3DCMP_NEVER,
-  D3DCMP_LESS,
-  D3DCMP_EQUAL,
-  D3DCMP_LESSEQUAL,
-  D3DCMP_GREATER,
-  D3DCMP_NOTEQUAL,
-  D3DCMP_GREATEREQUAL,
-  D3DCMP_ALWAYS,
-};
-
-static int dx_stencil_operation_array [ ] =
-{
-  D3DSTENCILOP_KEEP,
-  D3DSTENCILOP_ZERO,
-  D3DSTENCILOP_REPLACE,
-  D3DSTENCILOP_INCR,
-  D3DSTENCILOP_DECR,
-  D3DSTENCILOP_INVERT,
-
-  D3DSTENCILOP_INCRSAT,
-  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);
-  switch (stencil_render_state)
-  {
-    case StencilRenderStates::SRS_clear_value:
-      gsg -> set_stencil_clear_value (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_front_enable:
-      gsg -> set_render_state (D3DRS_STENCILENABLE, 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_back_enable:
-      gsg -> set_render_state (D3DRS_TWOSIDEDSTENCILMODE, render_state_value);
-      break;
-    case StencilRenderStates::SRS_back_comparison_function:
-      gsg -> set_render_state (D3DRS_CCW_STENCILFUNC, dx_stencil_comparison_function_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_back_stencil_fail_operation:
-      gsg -> set_render_state (D3DRS_CCW_STENCILFAIL, dx_stencil_operation_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_back_stencil_pass_z_fail_operation:
-      gsg -> set_render_state (D3DRS_CCW_STENCILZFAIL, dx_stencil_operation_array [render_state_value]);
-      break;
-    case StencilRenderStates::SRS_back_stencil_pass_z_pass_operation:
-      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::reset
 //       Access: Public, Virtual
@@ -2807,6 +2705,9 @@ reset() {
 
   // Stencil test is off by default
   set_render_state(D3DRS_STENCILENABLE, FALSE);
+  if (_supports_two_sided_stencil) {
+    set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+  }
 
   // Antialiasing.
 /* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */
@@ -2840,6 +2741,7 @@ reset() {
 
   PRINT_REFCNT(dxgsg9, _d3d_device);
 
+  void dx_set_stencil_functions (StencilRenderStates *stencil_render_states);
   dx_set_stencil_functions (_stencil_render_states);
 }
 
@@ -3357,6 +3259,11 @@ set_state_and_transform(const RenderState *target,
     _state._light = _target._light;
   }
 
+  if (_target._stencil != _state._stencil) {
+    do_issue_stencil();
+    _state._stencil = _target._stencil;
+  }
+
   _state_rs = _target_rs;
 }
 
@@ -5105,3 +5012,199 @@ check_dx_allocation (HRESULT result, int allocation_size, int attempts)
 
   return retry;
 }
+
+////////////////////////////////////////////////////////////////////
+//  DX stencil code section
+////////////////////////////////////////////////////////////////////
+
+static int dx_stencil_comparison_function_array [ ] =
+{
+  D3DCMP_NEVER,
+  D3DCMP_LESS,
+  D3DCMP_EQUAL,
+  D3DCMP_LESSEQUAL,
+  D3DCMP_GREATER,
+  D3DCMP_NOTEQUAL,
+  D3DCMP_GREATEREQUAL,
+  D3DCMP_ALWAYS,
+};
+
+static int dx_stencil_operation_array [ ] =
+{
+  D3DSTENCILOP_KEEP,
+  D3DSTENCILOP_ZERO,
+  D3DSTENCILOP_REPLACE,
+  D3DSTENCILOP_INCR,
+  D3DSTENCILOP_DECR,
+  D3DSTENCILOP_INVERT,
+
+  D3DSTENCILOP_INCRSAT,
+  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
+//  Description: Set stencil render states.
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian9::
+do_issue_stencil() {
+
+  const StencilAttrib *stencil;
+  StencilRenderStates *stencil_render_states;
+
+  stencil = _target._stencil;
+  stencil_render_states = this -> _stencil_render_states;
+  if (stencil && stencil_render_states) {
+
+#ifndef NDEBUG
+    // DEBUG ONLY
+    if (stencil -> _pre) {
+      dxgsg9_cat.error() << "Invalid StencilAttrib\n";
+    }
+#endif
+
+    // 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";
+    }
+
+    bool on;
+
+    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;
+    }
+
+    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 (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));
+    }
+  }
+  else {
+
+    // DEBUG
+    if (false) {
+      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);
+  }
+}

+ 3 - 2
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -105,7 +105,7 @@ public:
 
   virtual void do_clear(const RenderBuffer &buffer);
 
-  virtual void prepare_display_region(DisplayRegionPipelineReader *dr, 
+  virtual void prepare_display_region(DisplayRegionPipelineReader *dr,
                                       Lens::StereoChannel stereo_channel);
   virtual CPT(TransformState) calc_projection_mat(const Lens *lens);
   virtual bool prepare_lens();
@@ -115,7 +115,7 @@ public:
   virtual void end_scene();
   virtual void end_frame(Thread *current_thread);
 
-  virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, 
+  virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader,
                                      const GeomMunger *munger,
                                      const GeomVertexDataPipelineReader *data_reader);
   virtual void draw_triangles(const GeomPrimitivePipelineReader *reader);
@@ -172,6 +172,7 @@ protected:
   void do_issue_material();
   void do_issue_texture();
   void do_issue_blending();
+  void do_issue_stencil();
 
   void disable_texturing();
 

+ 59 - 49
panda/src/framework/windowFramework.cxx

@@ -78,7 +78,7 @@ TypeHandle WindowFramework::_type_handle;
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowFramework::Constructor
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 WindowFramework::
 WindowFramework(PandaFramework *panda_framework) :
@@ -102,7 +102,7 @@ WindowFramework(PandaFramework *panda_framework) :
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowFramework::Copy Constructor
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 WindowFramework::
 WindowFramework(const WindowFramework &copy, DisplayRegion *display_region) :
@@ -133,7 +133,7 @@ WindowFramework(const WindowFramework &copy, DisplayRegion *display_region) :
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowFramework::Destructor
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 WindowFramework::
 ~WindowFramework() {
@@ -173,7 +173,7 @@ open_window(const WindowProperties &props, GraphicsEngine *engine,
   _window = engine->make_window(ptgsg, name, 0);
   if (_window != (GraphicsWindow *)NULL) {
     _window->request_properties(props);
-    
+
     // Create a display region that covers the entire window.
     _display_region_3d = _window->make_display_region();
 
@@ -181,6 +181,7 @@ open_window(const WindowProperties &props, GraphicsEngine *engine,
     // so we can have multiple DisplayRegions of different colors.
     _window->set_clear_color_active(false);
     _window->set_clear_depth_active(false);
+    _window->set_clear_stencil_active(false);
 
     // Set up a 3-d camera for the window by default.
     NodePath camera_np = make_camera();
@@ -192,7 +193,7 @@ open_window(const WindowProperties &props, GraphicsEngine *engine,
     }
 
     set_background_type(_background_type);
-    
+
     if (show_frame_rate_meter) {
       _frame_rate_meter = new FrameRateMeter("frame_rate_meter");
       _frame_rate_meter->setup_window(_window);
@@ -286,18 +287,18 @@ get_render_2d() {
     _render_2d.set_two_sided(1);
 
     // Now set up a 2-d camera to view render_2d.
-    
+
     // Create a display region that matches the size of the 3-d
     // display region.
     float l, r, b, t;
     _display_region_3d->get_dimensions(l, r, b, t);
     _display_region_2d = _window->make_display_region(l, r, b, t);
     _display_region_2d->set_sort(10);
-    
+
     // Finally, we need a camera to associate with the display region.
     PT(Camera) camera = new Camera("camera2d");
     NodePath camera_np = _render_2d.attach_new_node(camera);
-    
+
     PT(Lens) lens = new OrthographicLens;
 
     static const float left = -1.0f;
@@ -344,7 +345,7 @@ get_aspect_2d() {
         properties = _window->get_requested_properties();
       }
       if (properties.has_size() && properties.get_y_size() != 0.0f) {
-        this_aspect_ratio = 
+        this_aspect_ratio =
           (float)properties.get_x_size() / (float)properties.get_y_size();
       }
     }
@@ -429,7 +430,7 @@ setup_trackball() {
     _trackball = new Trackball("trackball");
     _trackball->set_pos(LVector3f::forward() * 50.0);
     mouse.attach_new_node(_trackball);
-    
+
     PT(Transform2SG) tball2cam = new Transform2SG("tball2cam");
     tball2cam->set_node(camera.node());
     _trackball->add_child(tball2cam);
@@ -455,7 +456,7 @@ center_trackball(const NodePath &object) {
   nassertv(volume != (BoundingVolume *)NULL);
   nassertv(volume->is_of_type(GeometricBoundingVolume::get_class_type()));
   GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, volume);
-  
+
   // Determine the bounding sphere around the world.  The topmost
   // BoundingVolume might itself be a sphere (it's likely), but since
   // it might not, we'll take no chances and make our own sphere.
@@ -502,11 +503,11 @@ center_trackball(const NodePath &object) {
 
     // Ensure the far plane is far enough back to see the entire object.
     float ideal_far_plane = distance + radius;
-    lens->set_far(max(lens->get_default_far(), ideal_far_plane)); 
+    lens->set_far(max(lens->get_default_far(), ideal_far_plane));
 
     // And that the near plane is far enough forward.
     float ideal_near_plane = distance - radius;
-    lens->set_near(min(lens->get_default_near(), ideal_near_plane)); 
+    lens->set_near(min(lens->get_default_near(), ideal_near_plane));
   }
 
   _trackball->set_origin(center);
@@ -596,20 +597,20 @@ load_model(const NodePath &parent, Filename filename) {
       // The extension isn't a known model file type; is it a known
       // image file extension?
       if (extension == "txo") {
-	// A texture object.  Not exactly an image, but certainly a
-	// texture.
-	is_image = true;
-	
+  // A texture object.  Not exactly an image, but certainly a
+  // texture.
+  is_image = true;
+
       } else {
-	TexturePool *texture_pool = TexturePool::get_global_ptr();
-	if (texture_pool->get_texture_type(extension) != NULL) {
-	  // It is a known image file extension.
-	  is_image = true;
-	}
+  TexturePool *texture_pool = TexturePool::get_global_ptr();
+  if (texture_pool->get_texture_type(extension) != NULL) {
+    // It is a known image file extension.
+    is_image = true;
+  }
       }
     }
   }
-  
+
   LoaderOptions options = PandaFramework::_loader_options;
   if (search) {
     options.set_flags(options.get_flags() | LoaderOptions::LF_search);
@@ -628,7 +629,7 @@ load_model(const NodePath &parent, Filename filename) {
   if (node == (PandaNode *)NULL) {
     nout << "Unable to load " << filename << "\n";
     return NodePath::not_found();
-  }    
+  }
 
   return parent.attach_new_node(node);
 }
@@ -658,7 +659,7 @@ load_default_model(const NodePath &parent) {
     tex->set_magfilter(Texture::FT_linear);
     state = state->add_attrib(TextureAttrib::make(tex));
   }
-  
+
   GeomNode *geomnode = new GeomNode("tri");
 
   PT(GeomVertexData) vdata = new GeomVertexData
@@ -668,30 +669,30 @@ load_default_model(const NodePath &parent) {
   GeomVertexWriter normal(vdata, InternalName::get_normal());
   GeomVertexWriter color(vdata, InternalName::get_color());
   GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
-  
+
   vertex.add_data3f(Vertexf::rfu(0.0, 0.0, 0.0));
   vertex.add_data3f(Vertexf::rfu(1.0, 0.0, 0.0));
   vertex.add_data3f(Vertexf::rfu(0.0, 0.0, 1.0));
-  
+
   normal.add_data3f(Normalf::back());
   normal.add_data3f(Normalf::back());
   normal.add_data3f(Normalf::back());
-  
+
   color.add_data4f(0.5, 0.5, 1.0, 1.0);
   color.add_data4f(0.5, 0.5, 1.0, 1.0);
   color.add_data4f(0.5, 0.5, 1.0, 1.0);
-  
+
   texcoord.add_data2f(0.0, 0.0);
   texcoord.add_data2f(1.0, 0.0);
   texcoord.add_data2f(0.0, 1.0);
-  
+
   PT(GeomTriangles) tri = new GeomTriangles(Geom::UH_static);
   tri->add_consecutive_vertices(0, 3);
   tri->close_primitive();
-  
+
   PT(Geom) geom = new Geom(vdata);
   geom->add_primitive(tri);
-  
+
   geomnode->add_geom(geom, state);
 
   return parent.attach_new_node(geomnode);
@@ -774,15 +775,15 @@ split_window(SplitType split_type) {
   if (split_type == ST_default) {
     // Choose either horizontal or vertical according to the largest
     // dimension.
-    
-    if (_display_region_3d->get_pixel_width() > 
+
+    if (_display_region_3d->get_pixel_width() >
         _display_region_3d->get_pixel_height()) {
       split_type = ST_horizontal;
     } else {
       split_type = ST_vertical;
     }
   }
-  
+
   float left, right, bottom, top;
   _display_region_3d->get_dimensions(left, right, bottom, top);
   new_region = _display_region_3d->get_window()->make_display_region();
@@ -792,9 +793,9 @@ split_window(SplitType split_type) {
     if (_display_region_2d != (DisplayRegion *)NULL) {
       _display_region_2d->set_dimensions(left, right, bottom, (top + bottom) / 2.0f);
     }
-      
+
     new_region->set_dimensions(left, right, (top + bottom) / 2.0f, top);
-    
+
   } else {
     _display_region_3d->set_dimensions(left, (left + right) / 2.0f, bottom, top);
     if (_display_region_2d != (DisplayRegion *)NULL) {
@@ -967,34 +968,43 @@ set_background_type(WindowFramework::BackgroundType type) {
   case BT_default:
     _display_region_3d->set_clear_color_active(true);
     _display_region_3d->set_clear_depth_active(true);
+    _display_region_3d->set_clear_stencil_active(true);
     _display_region_3d->set_clear_color(_window->get_clear_color());
     _display_region_3d->set_clear_depth(_window->get_clear_depth());
+    _display_region_3d->set_clear_stencil(_window->get_clear_stencil());
     break;
-    
+
   case BT_black:
     _display_region_3d->set_clear_color_active(true);
     _display_region_3d->set_clear_depth_active(true);
+    _display_region_3d->set_clear_stencil_active(true);
     _display_region_3d->set_clear_color(Colorf(0.0f, 0.0f, 0.0f, 0.0f));
     _display_region_3d->set_clear_depth(1.0f);
+    _display_region_3d->set_clear_stencil(0);
     break;
-    
+
   case BT_gray:
     _display_region_3d->set_clear_color_active(true);
     _display_region_3d->set_clear_depth_active(true);
+    _display_region_3d->set_clear_stencil_active(true);
     _display_region_3d->set_clear_color(Colorf(0.3f, 0.3f, 0.3f, 0.0f));
     _display_region_3d->set_clear_depth(1.0f);
+    _display_region_3d->set_clear_stencil(0);
     break;
-    
+
   case BT_white:
     _display_region_3d->set_clear_color_active(true);
     _display_region_3d->set_clear_depth_active(true);
+    _display_region_3d->set_clear_stencil_active(true);
     _display_region_3d->set_clear_color(Colorf(1.0f, 1.0f, 1.0f, 0.0f));
     _display_region_3d->set_clear_depth(1.0f);
+    _display_region_3d->set_clear_stencil(0);
     break;
 
   case BT_none:
     _display_region_3d->set_clear_color_active(false);
     _display_region_3d->set_clear_depth_active(false);
+    _display_region_3d->set_clear_stencil_active(false);
     break;
   }
 }
@@ -1009,7 +1019,7 @@ TextFont *WindowFramework::
 get_shuttle_controls_font() {
   if (_shuttle_controls_font == (TextFont *)NULL) {
     PT(TextFont) font;
-  
+
     string shuttle_controls_string((const char *)shuttle_controls, shuttle_controls_len);
     istringstream in(shuttle_controls_string);
     BamFile bam_file;
@@ -1080,7 +1090,7 @@ setup_lights() {
 
   _alight = light_group.attach_new_node(alight);
   _dlight = light_group.attach_new_node(dlight);
-  
+
   _got_lights = true;
 }
 
@@ -1144,24 +1154,24 @@ load_image_as_model(const Filename &filename) {
      Geom::UH_static);
   GeomVertexWriter vertex(vdata, InternalName::get_vertex());
   GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
-  
+
   vertex.add_data3f(Vertexf::rfu(left, 0.02f, top));
   vertex.add_data3f(Vertexf::rfu(left, 0.02f, bottom));
   vertex.add_data3f(Vertexf::rfu(right, 0.02f, top));
   vertex.add_data3f(Vertexf::rfu(right, 0.02f, bottom));
-  
+
   texcoord.add_data2f(0.0f, tex_scale[1]);
   texcoord.add_data2f(0.0f, 0.0f);
   texcoord.add_data2f(tex_scale[0], tex_scale[1]);
   texcoord.add_data2f(tex_scale[0], 0.0f);
-  
+
   PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
   strip->add_consecutive_vertices(0, 4);
   strip->close_primitive();
-  
+
   PT(Geom) geom = new Geom(vdata);
   geom->add_primitive(strip);
-  
+
   card_node->add_geom(geom);
 
   return card_node.p();
@@ -1196,7 +1206,7 @@ create_anim_controls() {
     NodePath tnp = _anim_controls_group.attach_new_node(label);
     tnp.set_pos(0.0f, 0.0f, 0.07f);
     tnp.set_scale(0.1f);
-    
+
     return;
   }
 
@@ -1290,7 +1300,7 @@ update_anim_controls() {
 //               event (play, pause, etc.).
 ////////////////////////////////////////////////////////////////////
 void WindowFramework::
-setup_shuttle_button(const string &label, int index, 
+setup_shuttle_button(const string &label, int index,
                      EventHandler::EventCallbackFunction *func) {
   PT(PGButton) button = new PGButton(label);
   button->set_frame(-0.05f, 0.05f, 0.0f, 0.07f);

+ 255 - 171
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -280,176 +280,6 @@ CLP(GraphicsStateGuardian)::
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//  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 [ ] =
-{
-  GL_KEEP,
-  GL_ZERO,
-  GL_REPLACE,
-  GL_INCR_WRAP,
-  GL_DECR_WRAP,
-  GL_INVERT,
-
-  GL_INCR,
-  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_clear_value:
-      stencil_render_states -> _gsg -> set_stencil_clear_value (render_state_value);
-      break;
-
-    case StencilRenderStates::SRS_write_mask:
-      glStencilMask (render_state_value);
-      break;
-    case StencilRenderStates::SRS_front_enable:
-      if (render_state_value) {
-        glEnable (GL_STENCIL_TEST);
-      }
-      else {
-        glDisable (GL_STENCIL_TEST);
-      }
-      break;
-    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;
-
-    default:
-      break;
-  }
-}
-
-void gl_set_stencil_functions (StencilRenderStates *stencil_render_states) {
-
-  if (stencil_render_states) {
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_clear_value, gl_stencil_function);
-
-    // 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_front_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);
-
-    stencil_render_states -> set_stencil_function (StencilRenderStates::SRS_back_enable, 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::reset
 //       Access: Public, Virtual
@@ -1262,6 +1092,7 @@ reset() {
 
   report_my_gl_errors();
 
+  void gl_set_stencil_functions (StencilRenderStates *stencil_render_states);
   gl_set_stencil_functions (_stencil_render_states);
 }
 
@@ -1295,7 +1126,7 @@ do_clear(const RenderBuffer &buffer) {
   }
 
   if (buffer_type & RenderBuffer::T_stencil) {
-    GLP(ClearStencil)(_stencil_clear_value != false);
+    GLP(ClearStencil)(_stencil_clear_value);
     mask |= GL_STENCIL_BUFFER_BIT;
   }
 
@@ -5848,6 +5679,11 @@ set_state_and_transform(const RenderState *target,
     _state._tex_gen = _target._tex_gen;
   }
 
+  if (_target._stencil != _state._stencil) {
+    do_issue_stencil();
+    _state._stencil = _target._stencil;
+  }
+
   _state_rs = _target_rs;
 }
 
@@ -7352,3 +7188,251 @@ bind_fbo(GLuint fbo) {
   _current_fbo = 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 [ ] =
+{
+  GL_KEEP,
+  GL_ZERO,
+  GL_REPLACE,
+  GL_INCR_WRAP,
+  GL_DECR_WRAP,
+  GL_INVERT,
+
+  GL_INCR,
+  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;
+    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;
+
+    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
+//  Description: Set stencil render states.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+do_issue_stencil() {
+  const StencilAttrib *stencil;
+  StencilRenderStates *stencil_render_states;
+
+  stencil = _target._stencil;
+  stencil_render_states = this -> _stencil_render_states;
+  if (stencil && stencil_render_states) {
+
+#ifndef NDEBUG
+    // DEBUG ONLY
+    if (stencil -> _pre) {
+      GLCAT.error() << "Invalid StencilAttrib\n";
+    }
+#endif
+
+    // DEBUG
+    if (false) {
+      GLCAT.debug() << "STENCIL STATE CHANGE\n";
+      GLCAT.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";
+    }
+
+    bool on;
+
+    on = false;
+
+    // SRS_reference and SRS_read_mask are set when SRS_front_comparison_function is set
+    stencil_render_states -> set_stencil_render_state (false, StencilRenderStates::SRS_reference, stencil -> get_render_state (StencilAttrib::SRS_reference));
+    stencil_render_states -> set_stencil_render_state (false, StencilRenderStates::SRS_read_mask, stencil -> get_render_state (StencilAttrib::SRS_read_mask));
+
+    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));
+
+      // setting 2 operation states can be defered since all three must be set at once
+      stencil_render_states -> set_stencil_render_state (false, StencilRenderStates::SRS_front_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation));
+      stencil_render_states -> set_stencil_render_state (false, 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;
+    }
+
+    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));
+
+      // setting 2 operation states can be defered since all three must be set at once
+      stencil_render_states -> set_stencil_render_state (false, StencilRenderStates::SRS_back_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_fail_operation));
+      stencil_render_states -> set_stencil_render_state (false, 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 (on) {
+      stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_write_mask, stencil -> get_render_state (StencilAttrib::SRS_write_mask));
+    }
+  }
+  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);
+  }
+}

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

@@ -207,6 +207,7 @@ protected:
   void do_issue_blending();
   void do_issue_tex_gen();
   void do_issue_tex_matrix();
+  void do_issue_stencil();
 
   virtual void gl_flush() const;
   virtual GLenum gl_get_error() const;