@@ -43,6 +43,15 @@ public static unsafe class Graphics
4343
4444 private static RasterizerState . WindingOrder winding = RasterizerState . WindingOrder . CW ;
4545
46+ private static bool stencilEnabled = false ;
47+ private static RasterizerState . StencilFunction stencilFunc = RasterizerState . StencilFunction . Always ;
48+ private static int stencilRef = 0 ;
49+ private static int stencilReadMask = 255 ;
50+ private static int stencilWriteMask = 255 ;
51+ private static RasterizerState . StencilOp stencilPassOp = RasterizerState . StencilOp . Keep ;
52+ private static RasterizerState . StencilOp stencilFailOp = RasterizerState . StencilOp . Keep ;
53+ private static RasterizerState . StencilOp stencilZFailOp = RasterizerState . StencilOp . Keep ;
54+
4655 private static GraphicsFrameBuffer ? currentFramebuffer = null ;
4756 private static GraphicsFrameBuffer ? currentReadFramebuffer = null ;
4857 private static GraphicsFrameBuffer ? currentDrawFramebuffer = null ;
@@ -163,6 +172,39 @@ public static void SetState(RasterizerState state, bool force = false)
163172 GL . FrontFace ( WindingToGL ( state . Winding ) ) ;
164173 winding = state . Winding ;
165174 }
175+
176+ if ( stencilEnabled != state . StencilEnabled || force )
177+ {
178+ if ( state . StencilEnabled )
179+ GL . Enable ( EnableCap . StencilTest ) ;
180+ else
181+ GL . Disable ( EnableCap . StencilTest ) ;
182+ stencilEnabled = state . StencilEnabled ;
183+ }
184+
185+ if ( state . StencilEnabled &&
186+ ( stencilFunc != state . StencilFunc || stencilRef != state . StencilRef || stencilReadMask != state . StencilReadMask || force ) )
187+ {
188+ GL . StencilFunc ( StencilFuncToGL ( state . StencilFunc ) , state . StencilRef , ( uint ) state . StencilReadMask ) ;
189+ stencilFunc = state . StencilFunc ;
190+ stencilRef = state . StencilRef ;
191+ stencilReadMask = state . StencilReadMask ;
192+ }
193+
194+ if ( state . StencilEnabled &&
195+ ( stencilFailOp != state . StencilFailOp || stencilZFailOp != state . StencilZFailOp || stencilPassOp != state . StencilPassOp || force ) )
196+ {
197+ GL . StencilOp ( StencilOpToGL ( state . StencilFailOp ) , StencilOpToGL ( state . StencilZFailOp ) , StencilOpToGL ( state . StencilPassOp ) ) ;
198+ stencilFailOp = state . StencilFailOp ;
199+ stencilZFailOp = state . StencilZFailOp ;
200+ stencilPassOp = state . StencilPassOp ;
201+ }
202+
203+ if ( state . StencilEnabled && ( stencilWriteMask != state . StencilWriteMask || force ) )
204+ {
205+ GL . StencilMask ( ( uint ) state . StencilWriteMask ) ;
206+ stencilWriteMask = state . StencilWriteMask ;
207+ }
166208 }
167209
168210 public static RasterizerState GetState ( )
@@ -176,7 +218,15 @@ public static RasterizerState GetState()
176218 BlendSrc = blendSrc ,
177219 BlendDst = blendDst ,
178220 Blend = blendEquation ,
179- CullFace = cullFace
221+ CullFace = cullFace ,
222+ StencilEnabled = stencilEnabled ,
223+ StencilFunc = stencilFunc ,
224+ StencilRef = stencilRef ,
225+ StencilReadMask = stencilReadMask ,
226+ StencilWriteMask = stencilWriteMask ,
227+ StencilPassOp = stencilPassOp ,
228+ StencilFailOp = stencilFailOp ,
229+ StencilZFailOp = stencilZFailOp ,
180230 } ;
181231 }
182232
@@ -209,6 +259,16 @@ public static void ResetState()
209259
210260 GL . FrontFace ( FrontFaceDirection . CW ) ;
211261 winding = RasterizerState . WindingOrder . CW ;
262+
263+ GL . Disable ( EnableCap . StencilTest ) ;
264+ stencilEnabled = false ;
265+ stencilFunc = RasterizerState . StencilFunction . Always ;
266+ stencilRef = 0 ;
267+ stencilReadMask = 255 ;
268+ stencilWriteMask = 255 ;
269+ stencilPassOp = RasterizerState . StencilOp . Keep ;
270+ stencilFailOp = RasterizerState . StencilOp . Keep ;
271+ stencilZFailOp = RasterizerState . StencilOp . Keep ;
212272 }
213273
214274 // Helper method to combine program ID and string hash into a unique ulong key
@@ -662,6 +722,38 @@ private static FrontFaceDirection WindingToGL(RasterizerState.WindingOrder windi
662722 } ;
663723 }
664724
725+ private static StencilFunction StencilFuncToGL ( RasterizerState . StencilFunction func )
726+ {
727+ return func switch
728+ {
729+ RasterizerState . StencilFunction . Never => StencilFunction . Never ,
730+ RasterizerState . StencilFunction . Less => StencilFunction . Less ,
731+ RasterizerState . StencilFunction . Equal => StencilFunction . Equal ,
732+ RasterizerState . StencilFunction . Lequal => StencilFunction . Lequal ,
733+ RasterizerState . StencilFunction . Greater => StencilFunction . Greater ,
734+ RasterizerState . StencilFunction . Notequal => StencilFunction . Notequal ,
735+ RasterizerState . StencilFunction . Gequal => StencilFunction . Gequal ,
736+ RasterizerState . StencilFunction . Always => StencilFunction . Always ,
737+ _ => throw new ArgumentOutOfRangeException ( nameof ( func ) , func , null ) ,
738+ } ;
739+ }
740+
741+ private static StencilOp StencilOpToGL ( RasterizerState . StencilOp op )
742+ {
743+ return op switch
744+ {
745+ RasterizerState . StencilOp . Keep => StencilOp . Keep ,
746+ RasterizerState . StencilOp . Zero => StencilOp . Zero ,
747+ RasterizerState . StencilOp . Replace => StencilOp . Replace ,
748+ RasterizerState . StencilOp . Incr => StencilOp . Incr ,
749+ RasterizerState . StencilOp . IncrWrap => StencilOp . IncrWrap ,
750+ RasterizerState . StencilOp . Decr => StencilOp . Decr ,
751+ RasterizerState . StencilOp . DecrWrap => StencilOp . DecrWrap ,
752+ RasterizerState . StencilOp . Invert => StencilOp . Invert ,
753+ _ => throw new ArgumentOutOfRangeException ( nameof ( op ) , op , null ) ,
754+ } ;
755+ }
756+
665757 #endregion
666758
667759 #endregion
0 commit comments