summaryrefslogtreecommitdiff
path: root/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c')
-rw-r--r--src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c1335
1 files changed, 1290 insertions, 45 deletions
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c
index e284b31a..d543e301 100644
--- a/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c
+++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c
@@ -9,24 +9,74 @@
#include "state/cr_statetypes.h"
#include "state_internals.h"
+
+static GLint crStateStencilBufferGetIdxAndCount(CRStencilState *s, GLenum face, GLint *pIdx, GLint *pBitsIdx)
+{
+ switch (face)
+ {
+ case GL_FRONT_AND_BACK:
+ *pIdx = 0;
+ *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK;
+ return 2;
+ case GL_FRONT:
+ *pIdx = CRSTATE_STENCIL_BUFFER_ID_FRONT;
+ *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT;
+ return 1;
+ case GL_BACK:
+ *pIdx = CRSTATE_STENCIL_BUFFER_ID_BACK;
+ *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_BACK;
+ return 1;
+ case 0:
+ if (!s->stencilTwoSideEXT || s->activeStencilFace == GL_FRONT)
+ {
+ /* both front and back */
+ *pIdx = 0;
+ *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK;
+ return 2;
+ }
+ *pIdx = CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK;
+ *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK;
+ return 1;
+ default:
+ crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilBufferGetIdxAndCount");
+ return 0;
+ }
+ crError("should never be here!");
+ return 0;
+}
+
+void crStateStencilBufferInit(CRStencilBufferState *s)
+{
+ s->func = GL_ALWAYS;
+ s->mask = 0xFFFFFFFF;
+ s->ref = 0;
+
+ s->fail = GL_KEEP;
+ s->passDepthFail = GL_KEEP;
+ s->passDepthPass = GL_KEEP;
+}
+
+static void crStateStencilBufferRefBitsInit(CRContext *ctx, CRStencilBufferRefBits *sb)
+{
+ RESET(sb->func, ctx->bitid);
+ RESET(sb->op, ctx->bitid);
+}
+
void crStateStencilInit(CRContext *ctx)
{
CRStencilState *s = &ctx->stencil;
CRStateBits *stateb = GetCurrentBits();
CRStencilBits *sb = &(stateb->stencil);
+ int i;
s->stencilTest = GL_FALSE;
RESET(sb->enable, ctx->bitid);
- s->func = GL_ALWAYS;
- s->mask = 0xFFFFFFFF;
- s->ref = 0;
- RESET(sb->func, ctx->bitid);
+ s->stencilTwoSideEXT = GL_FALSE;
+ RESET(sb->enableTwoSideEXT, ctx->bitid);
- s->fail = GL_KEEP;
- s->passDepthFail = GL_KEEP;
- s->passDepthPass = GL_KEEP;
- RESET(sb->op, ctx->bitid);
+ s->activeStencilFace = GL_FRONT;
+ RESET(sb->activeStencilFace, ctx->bitid);
s->clearValue = 0;
RESET(sb->clearValue, ctx->bitid);
@@ -35,53 +85,101 @@ void crStateStencilInit(CRContext *ctx)
RESET(sb->writeMask, ctx->bitid);
RESET(sb->dirty, ctx->bitid);
+
+ for (i = 0; i < CRSTATE_STENCIL_BUFFER_COUNT; ++i)
+ {
+ crStateStencilBufferInit(&s->buffers[i]);
+ }
+
+ for (i = 0; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i)
+ {
+ crStateStencilBufferRefBitsInit(ctx, &sb->bufferRefs[i]);
+ }
}
-void STATE_APIENTRY crStateStencilFunc(GLenum func, GLint ref, GLuint mask)
+static void crStateStencilBufferFunc(CRContext *g, CRStencilBufferState *s, GLenum func, GLint ref, GLuint mask)
{
- CRContext *g = GetCurrentContext();
- CRStencilState *s = &(g->stencil);
- CRStateBits *stateb = GetCurrentBits();
- CRStencilBits *sb = &(stateb->stencil);
+ s->func = func;
+ s->ref = ref;
+ s->mask = mask;
+}
+static void crStateStencilFuncPerform(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ CRContext *g = GetCurrentContext();
+ CRStencilState *s = &(g->stencil);
+ CRStateBits *stateb = GetCurrentBits();
+ CRStencilBits *sb = &(stateb->stencil);
+ GLint idx, bitsIdx, count, i;
- if (g->current.inBeginEnd)
- {
- crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
- "glStencilFunc called in begin/end");
- return;
- }
- FLUSH();
+ if (g->current.inBeginEnd)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glStencilFunc called in begin/end");
+ return;
+ }
- if (func != GL_NEVER &&
- func != GL_LESS &&
- func != GL_LEQUAL &&
- func != GL_GREATER &&
- func != GL_GEQUAL &&
- func != GL_EQUAL &&
- func != GL_NOTEQUAL &&
- func != GL_ALWAYS)
- {
- crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
- "glStencilFunc called with bogu func: %d", func);
- return;
- }
+ FLUSH();
- s->func = func;
- s->ref = ref;
- s->mask = mask;
+ if (func != GL_NEVER &&
+ func != GL_LESS &&
+ func != GL_LEQUAL &&
+ func != GL_GREATER &&
+ func != GL_GEQUAL &&
+ func != GL_EQUAL &&
+ func != GL_NOTEQUAL &&
+ func != GL_ALWAYS)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
+ "glStencilFunc called with bogu func: %d", func);
+ return;
+ }
- DIRTY(sb->func, g->neg_bitid);
- DIRTY(sb->dirty, g->neg_bitid);
+ count = crStateStencilBufferGetIdxAndCount(s, face, &idx, &bitsIdx);
+ if (count)
+ {
+ for (i = idx; i < idx + count; ++i)
+ {
+ crStateStencilBufferFunc(g, &s->buffers[i], func, ref, mask);
+ }
+ DIRTY(sb->bufferRefs[bitsIdx].func, g->neg_bitid);
+
+ DIRTY(sb->dirty, g->neg_bitid);
+ }
+}
+
+void STATE_APIENTRY crStateStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ if (!face)
+ {
+ /* crStateStencilFuncPerform accepts 0 value, while glStencilFuncSeparate does not,
+ * filter it out here */
+ crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilFuncSeparate");
+ return;
+ }
+ crStateStencilFuncPerform(face, func, ref, mask);
}
-void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass)
+void STATE_APIENTRY crStateStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+ crStateStencilFuncPerform(0, func, ref, mask);
+}
+
+static void STATE_APIENTRY crStateStencilBufferOp (CRContext *g, CRStencilBufferState *s, GLenum fail, GLenum zfail, GLenum zpass)
+{
+ s->fail = fail;
+ s->passDepthFail = zfail;
+ s->passDepthPass = zpass;
+}
+
+static void crStateStencilOpPerform (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
{
CRContext *g = GetCurrentContext();
CRStencilState *s = &(g->stencil);
CRStateBits *stateb = GetCurrentBits();
CRStencilBits *sb = &(stateb->stencil);
+ GLint idx, bitsIdx, count, i;
if (g->current.inBeginEnd)
{
@@ -146,14 +244,36 @@ void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass)
return;
}
- s->fail = fail;
- s->passDepthFail = zfail;
- s->passDepthPass = zpass;
+ count = crStateStencilBufferGetIdxAndCount(s, face, &idx, &bitsIdx);
+ if (count)
+ {
+ for (i = idx; i < idx + count; ++i)
+ {
+ crStateStencilBufferOp(g, &s->buffers[i], fail, zfail, zpass);
+ }
- DIRTY(sb->op, g->neg_bitid);
- DIRTY(sb->dirty, g->neg_bitid);
+ DIRTY(sb->bufferRefs[bitsIdx].op, g->neg_bitid);
+
+ DIRTY(sb->dirty, g->neg_bitid);
+ }
}
+void STATE_APIENTRY crStateStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+ if (!face)
+ {
+ /* crStateStencilOpPerform accepts 0 value, while glStencilOpSeparate does not,
+ * filter it out here */
+ crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilOpSeparate");
+ return;
+ }
+ crStateStencilOpPerform (0, fail, zfail, zpass);
+}
+
+void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass)
+{
+ crStateStencilOpPerform (0, fail, zfail, zpass);
+}
void STATE_APIENTRY crStateClearStencil (GLint c)
{
@@ -171,7 +291,6 @@ void STATE_APIENTRY crStateClearStencil (GLint c)
FLUSH();
-
s->clearValue = c;
DIRTY(sb->clearValue, g->neg_bitid);
@@ -199,3 +318,1129 @@ void STATE_APIENTRY crStateStencilMask (GLuint mask)
DIRTY(sb->writeMask, g->neg_bitid);
DIRTY(sb->dirty, g->neg_bitid);
}
+
+void STATE_APIENTRY crStateActiveStencilFaceEXT (GLenum face)
+{
+ CRContext *g = GetCurrentContext();
+ CRStencilState *s = &(g->stencil);
+ CRStateBits *stateb = GetCurrentBits();
+ CRStencilBits *sb = &(stateb->stencil);
+
+ switch (face)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ s->activeStencilFace = face;
+ break;
+ default:
+ crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateActiveStencilFaceEXT");
+ return;
+ }
+
+ DIRTY(sb->activeStencilFace, g->neg_bitid);
+ DIRTY(sb->dirty, g->neg_bitid);
+}
+
+#ifdef CRSTATE_DEBUG_STENCIL_ERR
+#define CRSTATE_CLEARERR() do { \
+ while (diff_api.GetError() != GL_NO_ERROR) {} \
+ } while (0)
+
+#define CRSTATE_CHECKGLERR(_op) do {\
+ GLenum _glErr; \
+ CRSTATE_CLEARERR(); \
+ _op; \
+ while ((_glErr = diff_api.GetError()) != GL_NO_ERROR) { Assert(0);} \
+ }while (0)
+#else
+#define CRSTATE_CHECKGLERR(_op) do { _op; } while (0)
+#endif
+
+#define CR_STATE_STENCIL_FUNC_MATCH(_s1, _i1, _s2, _i2) (\
+ (_s1)->buffers[(_i1)].func == (_s2)->buffers[(_i2)].func && \
+ (_s1)->buffers[(_i1)].ref == (_s2)->buffers[(_i2)].ref && \
+ (_s1)->buffers[(_i1)].mask == (_s2)->buffers[(_i2)].mask)
+
+#define CR_STATE_STENCIL_FUNC_COPY(_s1, _i1, _s2, _i2) do { \
+ (_s1)->buffers[(_i1)].func = (_s2)->buffers[(_i2)].func; \
+ (_s1)->buffers[(_i1)].ref = (_s2)->buffers[(_i2)].ref; \
+ (_s1)->buffers[(_i1)].mask = (_s2)->buffers[(_i2)].mask; \
+ } while (0)
+
+
+#define CR_STATE_STENCIL_OP_MATCH(_s1, _i1, _s2, _i2) (\
+ (_s1)->buffers[(_i1)].fail == (_s2)->buffers[(_i2)].fail && \
+ (_s1)->buffers[(_i1)].passDepthFail == (_s2)->buffers[(_i2)].passDepthFail && \
+ (_s1)->buffers[(_i1)].passDepthPass == (_s2)->buffers[(_i2)].passDepthPass)
+
+#define CR_STATE_STENCIL_OP_COPY(_s1, _i1, _s2, _i2) do { \
+ (_s1)->buffers[(_i1)].fail = (_s2)->buffers[(_i2)].fail; \
+ (_s1)->buffers[(_i1)].passDepthFail = (_s2)->buffers[(_i2)].passDepthFail; \
+ (_s1)->buffers[(_i1)].passDepthPass = (_s2)->buffers[(_i2)].passDepthPass; \
+ } while (0)
+
+
+void crStateStencilDiff(CRStencilBits *b, CRbitvalue *bitID,
+ CRContext *fromCtx, CRContext *toCtx)
+{
+ CRStencilState *from = &(fromCtx->stencil);
+ CRStencilState *to = &(toCtx->stencil);
+ unsigned int j, i;
+ GLenum activeFace;
+ GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE, frontBackDirty, frontDirty, backDirty;
+ GLchar frontMatch = -1, backMatch = -1, toFrontBackMatch = -1;
+ CRbitvalue nbitID[CR_MAX_BITARRAY];
+ for (j=0;j<CR_MAX_BITARRAY;j++)
+ nbitID[j] = ~bitID[j];
+ i = 0; /* silence compiler */
+
+ if (CHECKDIRTY(b->enable, bitID))
+ {
+ glAble able[2];
+ able[0] = diff_api.Disable;
+ able[1] = diff_api.Enable;
+ if (from->stencilTest != to->stencilTest)
+ {
+ able[to->stencilTest](GL_STENCIL_TEST);
+ from->stencilTest = to->stencilTest;
+ }
+ CLEARDIRTY(b->enable, nbitID);
+ }
+
+ if (CHECKDIRTY(b->enableTwoSideEXT, bitID))
+ {
+ glAble able[2];
+ able[0] = diff_api.Disable;
+ able[1] = diff_api.Enable;
+ if (from->stencilTwoSideEXT != to->stencilTwoSideEXT)
+ {
+ able[to->stencilTwoSideEXT](GL_STENCIL_TEST_TWO_SIDE_EXT);
+ from->stencilTwoSideEXT = to->stencilTwoSideEXT;
+ }
+ CLEARDIRTY(b->enableTwoSideEXT, nbitID);
+ }
+
+ if (CHECKDIRTY(b->clearValue, bitID))
+ {
+ if (from->clearValue != to->clearValue)
+ {
+ diff_api.ClearStencil (to->clearValue);
+ from->clearValue = to->clearValue;
+ }
+ CLEARDIRTY(b->clearValue, nbitID);
+ }
+
+ activeFace = to->activeStencilFace;
+
+
+ /* func */
+ frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, bitID);
+ frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, bitID);
+ backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, bitID);
+#define CR_STATE_STENCIL_FUNC_FRONT_MATCH() ( \
+ frontMatch >= 0 ? \
+ frontMatch \
+ : (frontMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT)))
+
+#define CR_STATE_STENCIL_FUNC_BACK_MATCH() ( \
+ backMatch >= 0 ? \
+ backMatch \
+ : (backMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+#define CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH() ( \
+ toFrontBackMatch >= 0 ? \
+ toFrontBackMatch \
+ : (toFrontBackMatch = CR_STATE_STENCIL_FUNC_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+ if (frontBackDirty)
+ {
+ if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()
+ || !CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask);
+
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask);
+
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ frontIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask);
+
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK);
+
+ backIsSet = GL_TRUE;
+ }
+ }
+
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, nbitID);
+ }
+
+ if (frontDirty)
+ {
+ if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask);
+
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask);
+
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask);
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK);
+ backIsSet = GL_TRUE;
+ }
+ }
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, nbitID);
+ }
+
+
+ if (backDirty)
+ {
+ if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask);
+
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask);
+
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask);
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK);
+ backIsSet = GL_TRUE;
+ }
+ }
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, nbitID);
+ }
+
+ if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, bitID))
+ {
+ if (!CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK))
+ {
+ if (activeFace == GL_FRONT)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_BACK);
+ activeFace = GL_BACK;
+ }
+
+ diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask);
+ CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, nbitID);
+ }
+
+#undef CR_STATE_STENCIL_FUNC_FRONT_MATCH
+#undef CR_STATE_STENCIL_FUNC_BACK_MATCH
+#undef CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH
+
+ /* op */
+ backIsSet = GL_FALSE, frontIsSet = GL_FALSE;
+ frontMatch = -1, backMatch = -1, toFrontBackMatch = -1;
+ frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, bitID);
+ frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, bitID);
+ backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, bitID);
+
+#define CR_STATE_STENCIL_OP_FRONT_MATCH() ( \
+ frontMatch >= 0 ? \
+ frontMatch \
+ : (frontMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT)))
+
+#define CR_STATE_STENCIL_OP_BACK_MATCH() ( \
+ backMatch >= 0 ? \
+ backMatch \
+ : (backMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+#define CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH() ( \
+ toFrontBackMatch >= 0 ? \
+ toFrontBackMatch \
+ : (toFrontBackMatch = CR_STATE_STENCIL_OP_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+ if (frontBackDirty)
+ {
+ if (!CR_STATE_STENCIL_OP_FRONT_MATCH()
+ || !CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass);
+
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ frontIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK);
+ backIsSet = GL_TRUE;
+ }
+ }
+
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, nbitID);
+ }
+
+ if (frontDirty)
+ {
+ if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass);
+
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass);
+
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK);
+ backIsSet = GL_TRUE;
+ }
+ }
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, nbitID);
+ }
+
+
+ if (backDirty)
+ {
+ if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass);
+
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass);
+
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT);
+
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK);
+ backIsSet = GL_TRUE;
+ }
+ }
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, nbitID);
+ }
+
+ if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, bitID))
+ {
+ if (!CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK))
+ {
+ if (activeFace == GL_FRONT)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_BACK);
+ activeFace = GL_BACK;
+ }
+
+ diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass);
+ CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, nbitID);
+ }
+
+#undef CR_STATE_STENCIL_OP_FRONT_MATCH
+#undef CR_STATE_STENCIL_OP_BACK_MATCH
+#undef CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH
+
+
+ if (activeFace != to->activeStencilFace)
+ {
+ diff_api.ActiveStencilFaceEXT(activeFace);
+ }
+
+ if (CHECKDIRTY(b->activeStencilFace, bitID))
+ {
+ if (from->activeStencilFace != to->activeStencilFace)
+ {
+ /* we already did it ( see above )*/
+ /* diff_api.ActiveStencilFaceEXT(to->activeStencilFace); */
+ from->activeStencilFace = to->activeStencilFace;
+ }
+ CLEARDIRTY(b->activeStencilFace, nbitID);
+ }
+
+ if (CHECKDIRTY(b->writeMask, bitID))
+ {
+ if (from->writeMask != to->writeMask)
+ {
+ diff_api.StencilMask (to->writeMask);
+ from->writeMask = to->writeMask;
+ }
+ CLEARDIRTY(b->writeMask, nbitID);
+ }
+ CLEARDIRTY(b->dirty, nbitID);
+}
+
+void crStateStencilSwitch(CRStencilBits *b, CRbitvalue *bitID,
+ CRContext *fromCtx, CRContext *toCtx)
+{
+ CRStencilState *from = &(fromCtx->stencil);
+ CRStencilState *to = &(toCtx->stencil);
+ unsigned int j, i;
+ GLenum activeFace;
+ GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE, frontBackDirty, frontDirty, backDirty;
+ GLchar frontMatch = -1, backMatch = -1, toFrontBackMatch = -1;
+ CRbitvalue nbitID[CR_MAX_BITARRAY];
+ for (j=0;j<CR_MAX_BITARRAY;j++)
+ nbitID[j] = ~bitID[j];
+ i = 0; /* silence compiler */
+
+ if (CHECKDIRTY(b->enable, bitID))
+ {
+ glAble able[2];
+ able[0] = diff_api.Disable;
+ able[1] = diff_api.Enable;
+ if (from->stencilTest != to->stencilTest)
+ {
+ CRSTATE_CHECKGLERR(able[to->stencilTest](GL_STENCIL_TEST));
+ FILLDIRTY(b->enable);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->enable, nbitID);
+ }
+ if (CHECKDIRTY(b->enableTwoSideEXT, bitID))
+ {
+ glAble able[2];
+ able[0] = diff_api.Disable;
+ able[1] = diff_api.Enable;
+ if (from->stencilTwoSideEXT != to->stencilTwoSideEXT)
+ {
+ CRSTATE_CHECKGLERR(able[to->stencilTwoSideEXT](GL_STENCIL_TEST_TWO_SIDE_EXT));
+ FILLDIRTY(b->enableTwoSideEXT);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->enableTwoSideEXT, nbitID);
+ }
+ if (CHECKDIRTY(b->clearValue, bitID))
+ {
+ if (from->clearValue != to->clearValue)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ClearStencil (to->clearValue));
+ FILLDIRTY(b->clearValue);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->clearValue, nbitID);
+ }
+
+ activeFace = from->activeStencilFace;
+
+ /* func */
+ frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, bitID);
+ frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, bitID);
+ backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, bitID);
+#define CR_STATE_STENCIL_FUNC_FRONT_MATCH() ( \
+ frontMatch >= 0 ? \
+ frontMatch \
+ : (frontMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT)))
+
+#define CR_STATE_STENCIL_FUNC_BACK_MATCH() ( \
+ backMatch >= 0 ? \
+ backMatch \
+ : (backMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+#define CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH() ( \
+ toFrontBackMatch >= 0 ? \
+ toFrontBackMatch \
+ : (toFrontBackMatch = CR_STATE_STENCIL_FUNC_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+ if (frontBackDirty)
+ {
+ if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()
+ || !CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask));
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask));
+ frontIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask));
+ backIsSet = GL_TRUE;
+ }
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func);
+ FILLDIRTY(b->dirty);
+ }
+
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, nbitID);
+ }
+
+ if (frontDirty)
+ {
+ if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask));
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask));
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask));
+ backIsSet = GL_TRUE;
+ }
+ }
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, nbitID);
+ }
+
+
+ if (backDirty)
+ {
+ if (!CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask));
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask));
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ diff_api.ActiveStencilFaceEXT(GL_FRONT);
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask));
+ backIsSet = GL_TRUE;
+ }
+ }
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, nbitID);
+ }
+
+ if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, bitID))
+ {
+ if (!CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK))
+ {
+ if (activeFace == GL_FRONT)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_BACK));
+ activeFace = GL_BACK;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask));
+
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, nbitID);
+ }
+
+#undef CR_STATE_STENCIL_FUNC_FRONT_MATCH
+#undef CR_STATE_STENCIL_FUNC_BACK_MATCH
+#undef CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH
+
+ /* op */
+ backIsSet = GL_FALSE, frontIsSet = GL_FALSE;
+ frontMatch = -1, backMatch = -1, toFrontBackMatch = -1;
+ frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, bitID);
+ frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, bitID);
+ backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, bitID);
+
+#define CR_STATE_STENCIL_OP_FRONT_MATCH() ( \
+ frontMatch >= 0 ? \
+ frontMatch \
+ : (frontMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT)))
+
+#define CR_STATE_STENCIL_OP_BACK_MATCH() ( \
+ backMatch >= 0 ? \
+ backMatch \
+ : (backMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+#define CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH() ( \
+ toFrontBackMatch >= 0 ? \
+ toFrontBackMatch \
+ : (toFrontBackMatch = CR_STATE_STENCIL_OP_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK)))
+
+ if (frontBackDirty)
+ {
+ if (!CR_STATE_STENCIL_OP_FRONT_MATCH()
+ || !CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass));
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass));
+ frontIsSet = GL_TRUE;
+ }
+ else if (!CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass));
+ backIsSet = GL_TRUE;
+ }
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op);
+ FILLDIRTY(b->dirty);
+ }
+
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, nbitID);
+ }
+
+ if (frontDirty)
+ {
+ if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass));
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass));
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass));
+ backIsSet = GL_TRUE;
+ }
+ }
+
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, nbitID);
+ }
+
+
+ if (backDirty)
+ {
+ if (!CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH())
+ {
+ if (!frontIsSet || !backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass));
+
+ frontIsSet = GL_TRUE;
+ backIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_FRONT_MATCH())
+ {
+ if (!frontIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass));
+ frontIsSet = GL_TRUE;
+ }
+ }
+ else if (!CR_STATE_STENCIL_OP_BACK_MATCH())
+ {
+ if (!backIsSet)
+ {
+ if (activeFace == GL_BACK)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT));
+ activeFace = GL_FRONT;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass));
+ backIsSet = GL_TRUE;
+ }
+ }
+
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, nbitID);
+ }
+
+ if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, bitID))
+ {
+ if (!CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK))
+ {
+ if (activeFace == GL_FRONT)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_BACK));
+ activeFace = GL_BACK;
+ }
+
+ CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail,
+ to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass));
+
+ FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, nbitID);
+ }
+
+#undef CR_STATE_STENCIL_OP_FRONT_MATCH
+#undef CR_STATE_STENCIL_OP_BACK_MATCH
+#undef CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH
+
+ if (activeFace != to->activeStencilFace)
+ {
+ CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(activeFace));
+ }
+
+ if (CHECKDIRTY(b->activeStencilFace, bitID))
+ {
+ if (from->activeStencilFace != to->activeStencilFace)
+ {
+ /* we already did it ( see above )*/
+ /* diff_api.ActiveStencilFaceEXT(to->activeStencilFace); */
+ FILLDIRTY(b->activeStencilFace);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->activeStencilFace, nbitID);
+ }
+
+ if (CHECKDIRTY(b->writeMask, bitID))
+ {
+ if (from->writeMask != to->writeMask)
+ {
+ CRSTATE_CHECKGLERR(diff_api.StencilMask (to->writeMask));
+ FILLDIRTY(b->writeMask);
+ FILLDIRTY(b->dirty);
+ }
+ CLEARDIRTY(b->writeMask, nbitID);
+ }
+
+ CLEARDIRTY(b->dirty, nbitID);
+}
+