📄 s_stencil.c
字号:
* 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 GLbooleanstencil_and_ztest_span(GLcontext *ctx, SWspan *span, GLuint face){ struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->_StencilBuffer; GLstencil stencilRow[MAX_WIDTH]; GLstencil *stencil; const GLuint n = span->end; const GLint x = span->x; const GLint y = span->y; GLubyte *mask = span->array->mask; ASSERT((span->arrayMask & SPAN_XY) == 0); ASSERT(ctx->Stencil.Enabled); ASSERT(n <= MAX_WIDTH);#ifdef DEBUG if (ctx->Depth.Test) { ASSERT(span->arrayMask & SPAN_Z); }#endif stencil = (GLstencil *) rb->GetPointer(ctx, rb, x, y); if (!stencil) { rb->GetRow(ctx, rb, n, x, y, stencilRow); stencil = stencilRow; } /* * Apply the stencil test to the fragments. * failMask[i] is 1 if the stencil test failed. */ if (do_stencil_test( ctx, face, n, stencil, mask ) == GL_FALSE) { /* all fragments failed the stencil test, we're done. */ span->writeAll = GL_FALSE; if (!rb->GetPointer(ctx, rb, 0, 0)) { /* put updated stencil values into buffer */ rb->PutRow(ctx, rb, n, x, y, stencil, NULL); } return GL_FALSE; } /* * Some fragments passed the stencil test, apply depth test to them * and apply Zpass and Zfail stencil ops. */ if (ctx->Depth.Test == GL_FALSE) { /* * No depth buffer, just apply zpass stencil function to active pixels. */ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask ); } else { /* * Perform depth buffering, then apply zpass or zfail stencil function. */ GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH]; /* save the current mask bits */ _mesa_memcpy(origMask, mask, n * sizeof(GLubyte)); /* apply the depth test */ _swrast_depth_test_span(ctx, span); compute_pass_fail_masks(n, origMask, mask, passMask, failMask); /* apply the pass and fail operations */ 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 back into hardware stencil buffer. */ if (!rb->GetPointer(ctx, rb, 0, 0)) { rb->PutRow(ctx, rb, n, x, y, stencil, NULL); } span->writeAll = GL_FALSE; return GL_TRUE; /* one or more fragments passed both tests */}/* * 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 voidapply_stencil_op_to_pixels( GLcontext *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 GLbooleanstencil_test_pixels( GLcontext *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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -