📄 s_stencil.c
字号:
}
}
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( GLcontext *ctx, struct sw_span *span, GLuint face )
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
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];
GLubyte origMask[MAX_WIDTH];
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
_swrast_get_values(ctx, rb, n, x, y, stencil, sizeof(GLubyte));
_mesa_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 {
_swrast_depth_test_span(ctx, span);
if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
GLubyte failmask[MAX_WIDTH];
GLuint i;
for (i = 0; i < n; i++) {
ASSERT(mask[i] == 0 || mask[i] == 1);
failmask[i] = origMask[i] & (mask[i] ^ 1);
}
apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face,
n, stencil, failmask);
}
if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
GLubyte passmask[MAX_WIDTH];
GLuint i;
for (i = 0; i < n; i++) {
ASSERT(mask[i] == 0 || mask[i] == 1);
passmask[i] = origMask[i] & mask[i];
}
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 {
GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
GLuint i;
_mesa_memcpy(oldmask, mask, n * sizeof(GLubyte));
_swrast_depth_test_span(ctx, span);
for (i=0;i<n;i++) {
ASSERT(mask[i] == 0 || mask[i] == 1);
passmask[i] = oldmask[i] & mask[i];
failmask[i] = oldmask[i] & (mask[i] ^ 1);
}
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(GLcontext *ctx, struct sw_span *span)
{
/* span->facing can only be non-zero if using two-sided stencil */
ASSERT(ctx->Stencil.TestTwoSide || span->facing == 0);
if (span->arrayMask & SPAN_XY)
return stencil_and_ztest_pixels(ctx, span, span->facing);
else
return stencil_and_ztest_span(ctx, span, span->facing);
}
#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
/**
* Return a span of stencil values from the stencil buffer.
* Used for glRead/CopyPixels
* Input: n - how many pixels
* x,y - location of first pixel
* Output: stencil - the array of stencil values
*/
void
_swrast_read_stencil_span(GLcontext *ctx, struct gl_renderbuffer *rb,
GLint n, GLint x, GLint y, GLstencil stencil[])
{
if (y < 0 || y >= rb->Height || x + n <= 0 || x >= rb->Width) {
/* span is completely outside framebuffer */
return; /* undefined values OK */
}
if (x < 0) {
GLint dx = -x;
x = 0;
n -= dx;
stencil += dx;
}
if (x + n > rb->Width) {
GLint dx = x + n - rb->Width;
n -= dx;
}
if (n <= 0) {
return;
}
rb->GetRow(ctx, rb, n, x, y, stencil);
}
/**
* Write a span of stencil values to the stencil buffer.
* Used for glDraw/CopyPixels
* Input: n - how many pixels
* x, y - location of first pixel
* stencil - the array of stencil values
*/
void
_swrast_write_stencil_span(GLcontext *ctx, GLint n, GLint x, GLint y,
const GLstencil stencil[] )
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1;
const GLuint stencilMask = ctx->Stencil.WriteMask[0];
if (y < 0 || y >= rb->Height || x + n <= 0 || x >= rb->Width) {
/* span is completely outside framebuffer */
return; /* undefined values OK */
}
if (x < 0) {
GLint dx = -x;
x = 0;
n -= dx;
stencil += dx;
}
if (x + n > rb->Width) {
GLint dx = x + n - rb->Width;
n -= dx;
}
if (n <= 0) {
return;
}
if ((stencilMask & stencilMax) != stencilMax) {
/* need to apply writemask */
GLstencil destVals[MAX_WIDTH], newVals[MAX_WIDTH];
GLint i;
rb->GetRow(ctx, rb, n, x, y, destVals);
for (i = 0; i < n; i++) {
newVals[i]
= (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask);
}
rb->PutRow(ctx, rb, n, x, y, newVals, NULL);
}
else {
rb->PutRow(ctx, rb, n, x, y, stencil, NULL);
}
}
/**
* Clear the stencil buffer.
*/
void
_swrast_clear_stencil_buffer( GLcontext *ctx, struct gl_renderbuffer *rb )
{
const GLstencil mask = ctx->Stencil.WriteMask[0];
const GLstencil invMask = ~mask;
const GLstencil clearVal = (ctx->Stencil.Clear & mask);
GLint x, y, width, height;
if (!rb || mask == 0)
return;
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
ASSERT(rb->_BaseFormat == GL_STENCIL_INDEX);
/* compute region to clear */
x = ctx->DrawBuffer->_Xmin;
y = ctx->DrawBuffer->_Ymin;
width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
if (rb->GetPointer(ctx, rb, 0, 0)) {
/* Direct buffer access */
if (ctx->Stencil.WriteMask[0] != STENCIL_MAX) {
/* need to mask the clear */
GLint i, j;
for (i = 0; i < height; i++) {
GLubyte *stencil = rb->GetPointer(ctx, rb, x, y + i);
for (j = 0; j < width; j++) {
stencil[j] = (stencil[j] & invMask) | clearVal;
}
}
}
else {
/* no bit masking */
if (width == rb->Width &&
rb->InternalFormat == GL_STENCIL_INDEX8_EXT) {
/* optimized case */
GLubyte *stencil = rb->GetPointer(ctx, rb, x, y);
GLuint len = width * height * sizeof(GLubyte);
_mesa_memset(stencil, clearVal, len);
}
else {
/* general case */
GLint i, j;
for (i = 0; i < height; i++) {
GLubyte *stencil = rb->GetPointer(ctx, rb, x, y + i);
for (j = 0; j < width; j++) {
stencil[j] = clearVal;
}
}
}
}
}
else {
/* no direct access */
if (ctx->Stencil.WriteMask[0] != STENCIL_MAX) {
/* need to mask the clear */
GLint i, j;
for (i = 0; i < height; i++) {
GLubyte stencil[MAX_WIDTH];
rb->GetRow(ctx, rb, width, x, y + i, stencil);
for (j = 0; j < width; j++) {
stencil[j] = (stencil[j] & invMask) | clearVal;
}
rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL);
}
}
else {
/* no bit masking */
const GLubyte clear8 = clearVal;
GLint i;
for (i = 0; i < height; i++) {
rb->PutMonoRow(ctx, rb, width, x, y + i, &clear8, NULL);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -