-/*
- * Return the address of a stencil buffer value given the window coords:
- */
-#define STENCIL_ADDRESS(X, Y) (stencilStart + (Y) * stride + (X))
-
-
-
-/**
- * Apply the given stencil operator for each pixel in the array whose
- * mask flag is set.
- * \note This is for software stencil buffers only.
- * Input: n - number of pixels in the span
- * x, y - array of [n] pixels
- * operator - the stencil buffer operator
- * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
- */
-static void
-apply_stencil_op_to_pixels( struct gl_context *ctx,
- GLuint n, const GLint x[], const GLint y[],
- GLenum oper, GLuint face, const GLubyte mask[] )
-{
- struct gl_framebuffer *fb = ctx->DrawBuffer;
- struct gl_renderbuffer *rb = fb->_StencilBuffer;
- const GLstencil stencilMax = (1 << fb->Visual.stencilBits) - 1;
- const GLstencil ref = ctx->Stencil.Ref[face];
- const GLstencil wrtmask = ctx->Stencil.WriteMask[face];
- const GLstencil invmask = (GLstencil) (~wrtmask);
- GLuint i;
- GLstencil *stencilStart = (GLubyte *) rb->Data;
- const GLuint stride = rb->Width;
-
- ASSERT(rb->GetPointer(ctx, rb, 0, 0));
- ASSERT(sizeof(GLstencil) == 1);
-
- switch (oper) {
- case GL_KEEP:
- /* do nothing */
- break;
- case GL_ZERO:
- if (invmask==0) {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = 0;
- }
- }
- }
- else {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) (invmask & *sptr);
- }
- }
- }
- break;
- case GL_REPLACE:
- if (invmask==0) {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = ref;
- }
- }
- }
- else {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
- }
- }
- }
- break;
- case GL_INCR:
- if (invmask==0) {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- if (*sptr < stencilMax) {
- *sptr = (GLstencil) (*sptr + 1);
- }
- }
- }
- }
- else {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- if (*sptr < stencilMax) {
- *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
- }
- }
- }
- }
- break;
- case GL_DECR:
- if (invmask==0) {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- if (*sptr>0) {
- *sptr = (GLstencil) (*sptr - 1);
- }
- }
- }
- }
- else {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- if (*sptr>0) {
- *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
- }
- }
- }
- }
- break;
- case GL_INCR_WRAP_EXT:
- if (invmask==0) {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) (*sptr + 1);
- }
- }
- }
- else {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
- }
- }
- }
- break;
- case GL_DECR_WRAP_EXT:
- if (invmask==0) {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) (*sptr - 1);
- }
- }
- }
- else {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
- }
- }
- }
- break;
- case GL_INVERT:
- if (invmask==0) {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) (~*sptr);
- }
- }
- }
- else {
- for (i=0;i<n;i++) {
- if (mask[i]) {
- GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
- *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
- }
- }
- }
- break;
- default:
- _mesa_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
- }
-}
-
-
-
-/**
- * Apply stencil test to an array of pixels before depth buffering.
- *
- * \note Used for software stencil buffer only.
- * Input: n - number of pixels in the span
- * x, y - array of [n] pixels to stencil
- * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
- * Output: mask - pixels which fail the stencil test will have their
- * mask flag set to 0.
- * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
- */
-static GLboolean
-stencil_test_pixels( struct gl_context *ctx, GLuint face, GLuint n,
- const GLint x[], const GLint y[], GLubyte mask[] )
-{
- const struct gl_framebuffer *fb = ctx->DrawBuffer;
- struct gl_renderbuffer *rb = fb->_StencilBuffer;
- GLubyte fail[MAX_WIDTH];
- GLstencil r, s;
- GLuint i;
- GLboolean allfail = GL_FALSE;
- const GLuint valueMask = ctx->Stencil.ValueMask[face];
- const GLstencil *stencilStart = (GLstencil *) rb->Data;
- const GLuint stride = rb->Width;
-
- ASSERT(rb->GetPointer(ctx, rb, 0, 0));
- ASSERT(sizeof(GLstencil) == 1);
-
- /*
- * Perform stencil test. The results of this operation are stored
- * in the fail[] array:
- * IF fail[i] is non-zero THEN
- * the stencil fail operator is to be applied
- * ELSE
- * the stencil fail operator is not to be applied
- * ENDIF
- */
-
- switch (ctx->Stencil.Function[face]) {
- case GL_NEVER:
- /* always fail */
- for (i=0;i<n;i++) {
- if (mask[i]) {
- mask[i] = 0;
- fail[i] = 1;
- }
- else {
- fail[i] = 0;
- }
- }
- allfail = GL_TRUE;
- break;
- case GL_LESS:
- r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
- for (i=0;i<n;i++) {
- if (mask[i]) {
- const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
- s = (GLstencil) (*sptr & valueMask);
- if (r < s) {
- /* passed */
- fail[i] = 0;
- }
- else {
- fail[i] = 1;
- mask[i] = 0;
- }
- }
- else {
- fail[i] = 0;
- }
- }
- break;
- case GL_LEQUAL:
- r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
- for (i=0;i<n;i++) {
- if (mask[i]) {
- const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
- s = (GLstencil) (*sptr & valueMask);
- if (r <= s) {
- /* pass */
- fail[i] = 0;
- }
- else {
- fail[i] = 1;
- mask[i] = 0;
- }
- }
- else {
- fail[i] = 0;
- }
- }
- break;
- case GL_GREATER:
- r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
- for (i=0;i<n;i++) {
- if (mask[i]) {
- const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
- s = (GLstencil) (*sptr & valueMask);
- if (r > s) {
- /* passed */
- fail[i] = 0;
- }
- else {
- fail[i] = 1;
- mask[i] = 0;
- }
- }
- else {
- fail[i] = 0;
- }
- }
- break;
- case GL_GEQUAL:
- r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
- for (i=0;i<n;i++) {
- if (mask[i]) {
- const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
- s = (GLstencil) (*sptr & valueMask);
- if (r >= s) {
- /* passed */
- fail[i] = 0;
- }
- else {
- fail[i] = 1;
- mask[i] = 0;
- }
- }
- else {
- fail[i] = 0;
- }
- }
- break;
- case GL_EQUAL:
- r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
- for (i=0;i<n;i++) {
- if (mask[i]) {
- const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
- s = (GLstencil) (*sptr & valueMask);
- if (r == s) {
- /* passed */
- fail[i] = 0;
- }
- else {
- fail[i] = 1;
- mask[i] = 0;
- }
- }
- else {
- fail[i] = 0;
- }
- }
- break;
- case GL_NOTEQUAL:
- r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
- for (i=0;i<n;i++) {
- if (mask[i]) {
- const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
- s = (GLstencil) (*sptr & valueMask);
- if (r != s) {
- /* passed */
- fail[i] = 0;
- }
- else {
- fail[i] = 1;
- mask[i] = 0;
- }
- }
- else {
- fail[i] = 0;
- }
- }
- break;
- case GL_ALWAYS:
- /* always pass */
- for (i=0;i<n;i++) {
- fail[i] = 0;
- }
- break;
- default:
- _mesa_problem(ctx, "Bad stencil func in gl_stencil_pixels");
- return 0;
- }
-
- if (ctx->Stencil.FailFunc[face] != GL_KEEP) {
- apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc[face],
- face, fail );
- }
-
- return !allfail;
-}
-
-
-
-
-/**
- * Apply stencil and depth testing to an array of pixels.
- * This is used both for software and hardware stencil buffers.
- *
- * The comments in this function are a bit sparse but the code is
- * almost identical to stencil_and_ztest_span(), which is well
- * commented.
- *
- * Input: n - number of pixels in the array
- * x, y - array of [n] pixel positions
- * z - array [n] of z values
- * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
- * Output: mask - array [n] of flags (1=stencil and depth test passed)
- * Return: GL_FALSE - all fragments failed the testing
- * GL_TRUE - one or more fragments passed the testing
- */
-static GLboolean
-stencil_and_ztest_pixels( struct gl_context *ctx, SWspan *span, GLuint face )
-{
- GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH];
- struct gl_framebuffer *fb = ctx->DrawBuffer;
- struct gl_renderbuffer *rb = fb->_StencilBuffer;
- const GLuint n = span->end;
- const GLint *x = span->array->x;
- const GLint *y = span->array->y;
- GLubyte *mask = span->array->mask;
-
- ASSERT(span->arrayMask & SPAN_XY);
- ASSERT(ctx->Stencil.Enabled);
- ASSERT(n <= MAX_WIDTH);
-
- if (!rb->GetPointer(ctx, rb, 0, 0)) {
- /* No direct access */
- GLstencil stencil[MAX_WIDTH];
-
- ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
- _swrast_get_values(ctx, rb, n, x, y, stencil, sizeof(GLubyte));
-
- memcpy(origMask, mask, n * sizeof(GLubyte));
-
- (void) do_stencil_test(ctx, face, n, stencil, mask);
-
- if (ctx->Depth.Test == GL_FALSE) {
- apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face,
- n, stencil, mask);
- }
- else {
- GLubyte tmpMask[MAX_WIDTH];
- memcpy(tmpMask, mask, n * sizeof(GLubyte));
-
- _swrast_depth_test_span(ctx, span);
-
- compute_pass_fail_masks(n, tmpMask, mask, passMask, failMask);
-
- if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
- apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face,
- n, stencil, failMask);
- }
- if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
- apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face,
- n, stencil, passMask);
- }
- }
-
- /* Write updated stencil values into hardware stencil buffer */
- rb->PutValues(ctx, rb, n, x, y, stencil, origMask);
-
- return GL_TRUE;
- }
- else {
- /* Direct access to stencil buffer */
-
- if (stencil_test_pixels(ctx, face, n, x, y, mask) == GL_FALSE) {
- /* all fragments failed the stencil test, we're done. */
- return GL_FALSE;
- }
-
- if (ctx->Depth.Test==GL_FALSE) {
- apply_stencil_op_to_pixels(ctx, n, x, y,
- ctx->Stencil.ZPassFunc[face], face, mask);
- }
- else {
- memcpy(origMask, mask, n * sizeof(GLubyte));
-
- _swrast_depth_test_span(ctx, span);
-
- compute_pass_fail_masks(n, origMask, mask, passMask, failMask);
-
- if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
- apply_stencil_op_to_pixels(ctx, n, x, y,
- ctx->Stencil.ZFailFunc[face],
- face, failMask);
- }
- if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
- apply_stencil_op_to_pixels(ctx, n, x, y,
- ctx->Stencil.ZPassFunc[face],
- face, passMask);
- }
- }
-
- return GL_TRUE; /* one or more fragments passed both tests */
- }
-}
-
-
-/**
- * /return GL_TRUE = one or more fragments passed,
- * GL_FALSE = all fragments failed.
- */
-GLboolean
-_swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span)
-{
- const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace;
-
- if (span->arrayMask & SPAN_XY)
- return stencil_and_ztest_pixels(ctx, span, face);
- else
- return stencil_and_ztest_span(ctx, span, face);
-}
-
-
-#if 0
-GLuint
-clip_span(GLuint bufferWidth, GLuint bufferHeight,
- GLint x, GLint y, GLuint *count)
-{
- GLuint n = *count;
- GLuint skipPixels = 0;
-
- if (y < 0 || y >= bufferHeight || x + n <= 0 || x >= bufferWidth) {
- /* totally out of bounds */
- n = 0;
- }
- else {
- /* left clip */
- if (x < 0) {
- skipPixels = -x;
- x = 0;
- n -= skipPixels;
- }
- /* right clip */
- if (x + n > bufferWidth) {
- GLint dx = x + n - bufferWidth;
- n -= dx;
- }
- }
-
- *count = n;
-
- return skipPixels;
-}
-#endif
-